11// This test demonstrates that re-indexing fixes the wrong zeroeth element in v1 trees.
2- //
2+ //
33// The bug: v1 trees were initialized with wrong zeroeth element (next_index = 0 instead of 1)
44// The fix: Re-indexing now correctly sets next_index = 1 for v1 trees
55
66use crate :: utils:: * ;
7+ use function_name:: named;
8+ use light_compressed_account:: TreeType ;
79use photon_indexer:: dao:: generated:: indexed_trees;
8- use photon_indexer:: ingester:: persist:: persisted_indexed_merkle_tree:: persist_indexed_tree_updates;
10+ use photon_indexer:: ingester:: parser:: indexer_events:: RawIndexedElement ;
11+ use photon_indexer:: ingester:: parser:: state_update:: IndexedTreeLeafUpdate ;
912use photon_indexer:: ingester:: persist:: indexed_merkle_tree:: {
10- get_zeroeth_exclusion_range_v1,
11- compute_range_node_hash_v1,
13+ compute_range_node_hash_v1, get_zeroeth_exclusion_range_v1,
1214} ;
13- use photon_indexer:: ingester:: parser :: state_update :: IndexedTreeLeafUpdate ;
14- use photon_indexer :: ingester :: parser :: indexer_events :: RawIndexedElement ;
15- use light_compressed_account :: TreeType ;
15+ use photon_indexer:: ingester:: persist :: persisted_indexed_merkle_tree :: persist_indexed_tree_updates ;
16+ use sea_orm :: { ColumnTrait , EntityTrait , QueryFilter , Set , TransactionTrait } ;
17+ use serial_test :: serial ;
1618use solana_pubkey:: Pubkey ;
17- use sea_orm:: { EntityTrait , Set , QueryFilter , ColumnTrait , TransactionTrait } ;
1819use std:: collections:: HashMap ;
19- use function_name:: named;
20- use serial_test:: serial;
2120
2221#[ named]
2322#[ rstest]
@@ -30,17 +29,17 @@ async fn test_reindex_fixes_wrong_zeroeth_element(
3029 let name = trim_test_name ( function_name ! ( ) ) ;
3130 let setup = setup ( name. clone ( ) , db_backend) . await ;
3231 let conn = setup. db_conn ;
33-
32+
3433 // Create a v1 address tree
3534 let tree_pubkey = Pubkey :: new_unique ( ) ;
3635 let tree_bytes = tree_pubkey. to_bytes ( ) . to_vec ( ) ;
37-
36+
3837 // Step 1: Insert tree with wrong zeroeth element (simulating the bug)
3938 let txn = conn. begin ( ) . await . unwrap ( ) ;
40-
39+
4140 // Get the correct v1 zeroeth element to use its values
4241 let correct_v1_zeroeth = get_zeroeth_exclusion_range_v1 ( tree_bytes. clone ( ) ) ;
43-
42+
4443 // Insert wrong zeroeth element (using v2 style with next_index = 0 instead of 1)
4544 let wrong_zeroeth = indexed_trees:: ActiveModel {
4645 tree : Set ( tree_bytes. clone ( ) ) ,
@@ -54,10 +53,11 @@ async fn test_reindex_fixes_wrong_zeroeth_element(
5453 . exec ( & txn)
5554 . await
5655 . unwrap ( ) ;
57-
56+
5857 // Get top element for v1 trees
59- let top_element_model = photon_indexer:: ingester:: persist:: indexed_merkle_tree:: get_top_element ( tree_bytes. clone ( ) ) ;
60-
58+ let top_element_model =
59+ photon_indexer:: ingester:: persist:: indexed_merkle_tree:: get_top_element ( tree_bytes. clone ( ) ) ;
60+
6161 // Insert top element at index 1 (required for v1 trees)
6262 let top_element = indexed_trees:: ActiveModel {
6363 tree : Set ( tree_bytes. clone ( ) ) ,
@@ -71,9 +71,9 @@ async fn test_reindex_fixes_wrong_zeroeth_element(
7171 . exec ( & txn)
7272 . await
7373 . unwrap ( ) ;
74-
74+
7575 txn. commit ( ) . await . unwrap ( ) ;
76-
76+
7777 // Verify wrong data exists
7878 let wrong_zeroeth_from_db = indexed_trees:: Entity :: find ( )
7979 . filter ( indexed_trees:: Column :: Tree . eq ( tree_bytes. clone ( ) ) )
@@ -82,20 +82,23 @@ async fn test_reindex_fixes_wrong_zeroeth_element(
8282 . await
8383 . unwrap ( )
8484 . expect ( "Should find zeroeth element" ) ;
85-
86- assert_eq ! ( wrong_zeroeth_from_db. next_index, 0 , "Zeroeth element should have wrong next_index" ) ;
87-
85+
86+ assert_eq ! (
87+ wrong_zeroeth_from_db. next_index, 0 ,
88+ "Zeroeth element should have wrong next_index"
89+ ) ;
90+
8891 // Step 2: Simulate re-indexing that will fix the zeroeth element
8992 let txn = conn. begin ( ) . await . unwrap ( ) ;
90-
93+
9194 // Create the correct zeroeth element update
9295 let correct_zeroeth_leaf = RawIndexedElement {
9396 value : [ 0u8 ; 32 ] ,
9497 next_index : 1 , // Correct value for v1
9598 next_value : wrong_zeroeth_from_db. next_value . clone ( ) . try_into ( ) . unwrap ( ) ,
9699 index : 0 ,
97100 } ;
98-
101+
99102 // Compute the correct hash for v1 tree
100103 let correct_zeroeth_model = indexed_trees:: Model {
101104 tree : tree_bytes. clone ( ) ,
@@ -106,23 +109,23 @@ async fn test_reindex_fixes_wrong_zeroeth_element(
106109 seq : Some ( 2 ) ,
107110 } ;
108111 let correct_hash = compute_range_node_hash_v1 ( & correct_zeroeth_model) . unwrap ( ) ;
109-
112+
110113 let update = IndexedTreeLeafUpdate {
111114 tree : tree_pubkey,
112115 tree_type : TreeType :: AddressV1 ,
113116 leaf : correct_zeroeth_leaf,
114117 hash : correct_hash. 0 ,
115118 seq : 2 , // Higher seq number to ensure update
116119 } ;
117-
120+
118121 // Create HashMap with the update
119122 let mut updates = HashMap :: new ( ) ;
120123 updates. insert ( ( tree_pubkey, 0u64 ) , update) ;
121-
124+
122125 // Persist the update which should fix the zeroeth element
123126 persist_indexed_tree_updates ( & txn, updates) . await . unwrap ( ) ;
124127 txn. commit ( ) . await . unwrap ( ) ;
125-
128+
126129 // Step 3: Verify the zeroeth element is now correct
127130 let fixed_zeroeth = indexed_trees:: Entity :: find ( )
128131 . filter ( indexed_trees:: Column :: Tree . eq ( tree_bytes. clone ( ) ) )
@@ -131,15 +134,18 @@ async fn test_reindex_fixes_wrong_zeroeth_element(
131134 . await
132135 . unwrap ( )
133136 . expect ( "Should find zeroeth element" ) ;
134-
135- assert_eq ! ( fixed_zeroeth. next_index, 1 , "Zeroeth element should now have correct next_index" ) ;
137+
138+ assert_eq ! (
139+ fixed_zeroeth. next_index, 1 ,
140+ "Zeroeth element should now have correct next_index"
141+ ) ;
136142 assert_eq ! ( fixed_zeroeth. seq, Some ( 2 ) , "Seq should be updated" ) ;
137-
143+
138144 // Verify it matches what get_zeroeth_exclusion_range_v1 would create
139145 let expected_zeroeth = get_zeroeth_exclusion_range_v1 ( tree_bytes. clone ( ) ) ;
140146 assert_eq ! ( fixed_zeroeth. next_index, expected_zeroeth. next_index) ;
141147 assert_eq ! ( fixed_zeroeth. value, expected_zeroeth. value) ;
142-
148+
143149 println ! ( "✅ Re-indexing successfully fixed zeroeth element from wrong v2-style (next_index=0) to correct v1-style (next_index=1)" ) ;
144150}
145151
@@ -154,16 +160,16 @@ async fn test_reindex_preserves_correct_zeroeth_element(
154160 let name = trim_test_name ( function_name ! ( ) ) ;
155161 let setup = setup ( name. clone ( ) , db_backend) . await ;
156162 let conn = setup. db_conn ;
157-
163+
158164 // Create a v1 address tree
159165 let tree_pubkey = Pubkey :: new_unique ( ) ;
160166 let tree_bytes = tree_pubkey. to_bytes ( ) . to_vec ( ) ;
161-
167+
162168 // Insert correct zeroeth element
163169 let txn = conn. begin ( ) . await . unwrap ( ) ;
164-
170+
165171 let correct_v1_zeroeth = get_zeroeth_exclusion_range_v1 ( tree_bytes. clone ( ) ) ;
166-
172+
167173 let correct_zeroeth = indexed_trees:: ActiveModel {
168174 tree : Set ( tree_bytes. clone ( ) ) ,
169175 leaf_index : Set ( 0 ) ,
@@ -176,19 +182,19 @@ async fn test_reindex_preserves_correct_zeroeth_element(
176182 . exec ( & txn)
177183 . await
178184 . unwrap ( ) ;
179-
185+
180186 txn. commit ( ) . await . unwrap ( ) ;
181-
187+
182188 // Simulate re-indexing with the same correct data
183189 let txn = conn. begin ( ) . await . unwrap ( ) ;
184-
190+
185191 let leaf = RawIndexedElement {
186192 value : correct_v1_zeroeth. value . clone ( ) . try_into ( ) . unwrap ( ) ,
187193 next_index : 1 ,
188194 next_value : correct_v1_zeroeth. next_value . clone ( ) . try_into ( ) . unwrap ( ) ,
189195 index : 0 ,
190196 } ;
191-
197+
192198 let model = indexed_trees:: Model {
193199 tree : tree_bytes. clone ( ) ,
194200 leaf_index : 0 ,
@@ -198,21 +204,21 @@ async fn test_reindex_preserves_correct_zeroeth_element(
198204 seq : Some ( 1 ) ,
199205 } ;
200206 let hash = compute_range_node_hash_v1 ( & model) . unwrap ( ) ;
201-
207+
202208 let update = IndexedTreeLeafUpdate {
203209 tree : tree_pubkey,
204210 tree_type : TreeType :: AddressV1 ,
205211 leaf,
206212 hash : hash. 0 ,
207213 seq : 1 ,
208214 } ;
209-
215+
210216 let mut updates = HashMap :: new ( ) ;
211217 updates. insert ( ( tree_pubkey, 0u64 ) , update) ;
212-
218+
213219 persist_indexed_tree_updates ( & txn, updates) . await . unwrap ( ) ;
214220 txn. commit ( ) . await . unwrap ( ) ;
215-
221+
216222 // Verify it's still correct
217223 let zeroeth = indexed_trees:: Entity :: find ( )
218224 . filter ( indexed_trees:: Column :: Tree . eq ( tree_bytes. clone ( ) ) )
@@ -221,9 +227,12 @@ async fn test_reindex_preserves_correct_zeroeth_element(
221227 . await
222228 . unwrap ( )
223229 . expect ( "Should find zeroeth element" ) ;
224-
225- assert_eq ! ( zeroeth. next_index, 1 , "Zeroeth element should still be correct" ) ;
230+
231+ assert_eq ! (
232+ zeroeth. next_index, 1 ,
233+ "Zeroeth element should still be correct"
234+ ) ;
226235 assert_eq ! ( zeroeth. seq, Some ( 1 ) , "Seq should be updated" ) ;
227-
236+
228237 println ! ( "✅ Re-indexing preserves already correct zeroeth elements" ) ;
229238}
0 commit comments