@@ -32,32 +32,36 @@ struct LeafSetItem<H, N> {
3232 number : Reverse < N > ,
3333}
3434
35- /// A displaced leaf after import.
36- #[ must_use = "Displaced items from the leaf set must be handled." ]
37- pub struct ImportDisplaced < H , N > {
38- new_hash : H ,
39- displaced : LeafSetItem < H , N > ,
35+ /// Inserted and removed leaves after an import action.
36+ pub struct ImportOutcome < H , N > {
37+ inserted : LeafSetItem < H , N > ,
38+ removed : Option < H > ,
4039}
4140
42- /// Displaced leaves after finalization .
43- # [ must_use = "Displaced items from the leaf set must be handled." ]
44- pub struct FinalizationDisplaced < H , N > {
45- leaves : BTreeMap < Reverse < N > , Vec < H > > ,
41+ /// Inserted and removed leaves after a remove action .
42+ pub struct RemoveOutcome < H , N > {
43+ inserted : Option < H > ,
44+ removed : LeafSetItem < H , N > ,
4645}
4746
48- impl < H , N : Ord > FinalizationDisplaced < H , N > {
47+ /// Removed leaves after a finalization action.
48+ pub struct FinalizationOutcome < H , N > {
49+ removed : BTreeMap < Reverse < N > , Vec < H > > ,
50+ }
51+
52+ impl < H , N : Ord > FinalizationOutcome < H , N > {
4953 /// Merge with another. This should only be used for displaced items that
5054 /// are produced within one transaction of each other.
5155 pub fn merge ( & mut self , mut other : Self ) {
5256 // this will ignore keys that are in duplicate, however
5357 // if these are actually produced correctly via the leaf-set within
5458 // one transaction, then there will be no overlap in the keys.
55- self . leaves . append ( & mut other. leaves ) ;
59+ self . removed . append ( & mut other. removed ) ;
5660 }
5761
5862 /// Iterate over all displaced leaves.
5963 pub fn leaves ( & self ) -> impl Iterator < Item = & H > {
60- self . leaves . values ( ) . flatten ( )
64+ self . removed . values ( ) . flatten ( )
6165 }
6266}
6367
@@ -99,27 +103,52 @@ where
99103 }
100104
101105 /// Update the leaf list on import.
102- /// Returns a displaced leaf if there was one.
103- pub fn import ( & mut self , hash : H , number : N , parent_hash : H ) -> Option < ImportDisplaced < H , N > > {
104- // avoid underflow for genesis.
105- let displaced = if number != N :: zero ( ) {
106- let parent_number = Reverse ( number. clone ( ) - N :: one ( ) ) ;
107- let was_displaced = self . remove_leaf ( & parent_number, & parent_hash) ;
108-
109- if was_displaced {
110- Some ( ImportDisplaced {
111- new_hash : hash. clone ( ) ,
112- displaced : LeafSetItem { hash : parent_hash, number : parent_number } ,
113- } )
114- } else {
115- None
116- }
106+ pub fn import ( & mut self , hash : H , number : N , parent_hash : H ) -> ImportOutcome < H , N > {
107+ let number = Reverse ( number) ;
108+
109+ let removed = if number. 0 != N :: zero ( ) {
110+ let parent_number = Reverse ( number. 0 . clone ( ) - N :: one ( ) ) ;
111+ self . remove_leaf ( & parent_number, & parent_hash) . then ( || parent_hash)
117112 } else {
118113 None
119114 } ;
120115
121- self . insert_leaf ( Reverse ( number. clone ( ) ) , hash. clone ( ) ) ;
122- displaced
116+ self . insert_leaf ( number. clone ( ) , hash. clone ( ) ) ;
117+
118+ ImportOutcome { inserted : LeafSetItem { hash, number } , removed }
119+ }
120+
121+ /// Update the leaf list on removal.
122+ ///
123+ /// Note that the leaves set structure doesn't have the information to decide if the
124+ /// leaf we're removing is the last children of the parent. Follows that this method requires
125+ /// the caller to check this condition and optionally pass the `parent_hash` if `hash` is
126+ /// its last child.
127+ ///
128+ /// Returns `None` if no modifications are applied.
129+ pub fn remove (
130+ & mut self ,
131+ hash : H ,
132+ number : N ,
133+ parent_hash : Option < H > ,
134+ ) -> Option < RemoveOutcome < H , N > > {
135+ let number = Reverse ( number) ;
136+
137+ if !self . remove_leaf ( & number, & hash) {
138+ return None
139+ }
140+
141+ let inserted = parent_hash. and_then ( |parent_hash| {
142+ if number. 0 != N :: zero ( ) {
143+ let parent_number = Reverse ( number. 0 . clone ( ) - N :: one ( ) ) ;
144+ self . insert_leaf ( parent_number, parent_hash. clone ( ) ) ;
145+ Some ( parent_hash)
146+ } else {
147+ None
148+ }
149+ } ) ;
150+
151+ Some ( RemoveOutcome { inserted, removed : LeafSetItem { hash, number } } )
123152 }
124153
125154 /// Note a block height finalized, displacing all leaves with number less than the finalized
@@ -129,32 +158,32 @@ where
129158 /// same number as the finalized block, but with different hashes, the current behavior
130159 /// is simpler and our assumptions about how finalization works means that those leaves
131160 /// will be pruned soon afterwards anyway.
132- pub fn finalize_height ( & mut self , number : N ) -> FinalizationDisplaced < H , N > {
161+ pub fn finalize_height ( & mut self , number : N ) -> FinalizationOutcome < H , N > {
133162 let boundary = if number == N :: zero ( ) {
134- return FinalizationDisplaced { leaves : BTreeMap :: new ( ) }
163+ return FinalizationOutcome { removed : BTreeMap :: new ( ) }
135164 } else {
136165 number - N :: one ( )
137166 } ;
138167
139168 let below_boundary = self . storage . split_off ( & Reverse ( boundary) ) ;
140- FinalizationDisplaced { leaves : below_boundary }
169+ FinalizationOutcome { removed : below_boundary }
141170 }
142171
143172 /// The same as [`Self::finalize_height`], but it only simulates the operation.
144173 ///
145174 /// This means that no changes are done.
146175 ///
147176 /// Returns the leaves that would be displaced by finalizing the given block.
148- pub fn displaced_by_finalize_height ( & self , number : N ) -> FinalizationDisplaced < H , N > {
177+ pub fn displaced_by_finalize_height ( & self , number : N ) -> FinalizationOutcome < H , N > {
149178 let boundary = if number == N :: zero ( ) {
150- return FinalizationDisplaced { leaves : BTreeMap :: new ( ) }
179+ return FinalizationOutcome { removed : BTreeMap :: new ( ) }
151180 } else {
152181 number - N :: one ( )
153182 } ;
154183
155184 let below_boundary = self . storage . range ( & Reverse ( boundary) ..) ;
156- FinalizationDisplaced {
157- leaves : below_boundary. map ( |( k, v) | ( k. clone ( ) , v. clone ( ) ) ) . collect ( ) ,
185+ FinalizationOutcome {
186+ removed : below_boundary. map ( |( k, v) | ( k. clone ( ) , v. clone ( ) ) ) . collect ( ) ,
158187 }
159188 }
160189
@@ -276,16 +305,30 @@ where
276305 H : Clone + PartialEq + Decode + Encode ,
277306 N : std:: fmt:: Debug + Clone + AtLeast32Bit + Decode + Encode ,
278307{
279- /// Undo an imported block by providing the displaced leaf.
280- pub fn undo_import ( & mut self , displaced : ImportDisplaced < H , N > ) {
281- let new_number = Reverse ( displaced. displaced . number . 0 . clone ( ) + N :: one ( ) ) ;
282- self . inner . remove_leaf ( & new_number, & displaced. new_hash ) ;
283- self . inner . insert_leaf ( displaced. displaced . number , displaced. displaced . hash ) ;
308+ /// Undo an imported block by providing the import operation outcome.
309+ /// No additional operations should be performed between import and undo.
310+ pub fn undo_import ( & mut self , outcome : ImportOutcome < H , N > ) {
311+ if let Some ( removed_hash) = outcome. removed {
312+ let removed_number = Reverse ( outcome. inserted . number . 0 . clone ( ) - N :: one ( ) ) ;
313+ self . inner . insert_leaf ( removed_number, removed_hash) ;
314+ }
315+ self . inner . remove_leaf ( & outcome. inserted . number , & outcome. inserted . hash ) ;
316+ }
317+
318+ /// Undo a removed block by providing the displaced leaf.
319+ /// No additional operations should be performed between remove and undo.
320+ pub fn undo_remove ( & mut self , outcome : RemoveOutcome < H , N > ) {
321+ if let Some ( inserted_hash) = outcome. inserted {
322+ let inserted_number = Reverse ( outcome. removed . number . 0 . clone ( ) - N :: one ( ) ) ;
323+ self . inner . remove_leaf ( & inserted_number, & inserted_hash) ;
324+ }
325+ self . inner . insert_leaf ( outcome. removed . number , outcome. removed . hash ) ;
284326 }
285327
286328 /// Undo a finalization operation by providing the displaced leaves.
287- pub fn undo_finalization ( & mut self , mut displaced : FinalizationDisplaced < H , N > ) {
288- self . inner . storage . append ( & mut displaced. leaves ) ;
329+ /// No additional operations should be performed between finalization and undo.
330+ pub fn undo_finalization ( & mut self , mut outcome : FinalizationOutcome < H , N > ) {
331+ self . inner . storage . append ( & mut outcome. removed ) ;
289332 }
290333}
291334
@@ -295,7 +338,7 @@ mod tests {
295338 use std:: sync:: Arc ;
296339
297340 #[ test]
298- fn it_works ( ) {
341+ fn import_works ( ) {
299342 let mut set = LeafSet :: new ( ) ;
300343 set. import ( 0u32 , 0u32 , 0u32 ) ;
301344
@@ -317,6 +360,90 @@ mod tests {
317360 assert ! ( set. contains( 3 , 3_1 ) ) ;
318361 assert ! ( set. contains( 2 , 2_2 ) ) ;
319362 assert ! ( set. contains( 2 , 2_3 ) ) ;
363+
364+ // Finally test the undo feature
365+
366+ let outcome = set. import ( 2_4 , 2 , 1_1 ) ;
367+ assert_eq ! ( outcome. inserted. hash, 2_4 ) ;
368+ assert_eq ! ( outcome. removed, None ) ;
369+ assert_eq ! ( set. count( ) , 4 ) ;
370+ assert ! ( set. contains( 2 , 2_4 ) ) ;
371+
372+ set. undo ( ) . undo_import ( outcome) ;
373+ assert_eq ! ( set. count( ) , 3 ) ;
374+ assert ! ( set. contains( 3 , 3_1 ) ) ;
375+ assert ! ( set. contains( 2 , 2_2 ) ) ;
376+ assert ! ( set. contains( 2 , 2_3 ) ) ;
377+
378+ let outcome = set. import ( 3_2 , 3 , 2_3 ) ;
379+ assert_eq ! ( outcome. inserted. hash, 3_2 ) ;
380+ assert_eq ! ( outcome. removed, Some ( 2_3 ) ) ;
381+ assert_eq ! ( set. count( ) , 3 ) ;
382+ assert ! ( set. contains( 3 , 3_2 ) ) ;
383+
384+ set. undo ( ) . undo_import ( outcome) ;
385+ assert_eq ! ( set. count( ) , 3 ) ;
386+ assert ! ( set. contains( 3 , 3_1 ) ) ;
387+ assert ! ( set. contains( 2 , 2_2 ) ) ;
388+ assert ! ( set. contains( 2 , 2_3 ) ) ;
389+ }
390+
391+ #[ test]
392+ fn removal_works ( ) {
393+ let mut set = LeafSet :: new ( ) ;
394+ set. import ( 10_1u32 , 10u32 , 0u32 ) ;
395+ set. import ( 11_1 , 11 , 10_1 ) ;
396+ set. import ( 11_2 , 11 , 10_1 ) ;
397+ set. import ( 12_1 , 12 , 11_1 ) ;
398+
399+ let outcome = set. remove ( 12_1 , 12 , Some ( 11_1 ) ) . unwrap ( ) ;
400+ assert_eq ! ( outcome. removed. hash, 12_1 ) ;
401+ assert_eq ! ( outcome. inserted, Some ( 11_1 ) ) ;
402+ assert_eq ! ( set. count( ) , 2 ) ;
403+ assert ! ( set. contains( 11 , 11_1 ) ) ;
404+ assert ! ( set. contains( 11 , 11_2 ) ) ;
405+
406+ let outcome = set. remove ( 11_1 , 11 , None ) . unwrap ( ) ;
407+ assert_eq ! ( outcome. removed. hash, 11_1 ) ;
408+ assert_eq ! ( outcome. inserted, None ) ;
409+ assert_eq ! ( set. count( ) , 1 ) ;
410+ assert ! ( set. contains( 11 , 11_2 ) ) ;
411+
412+ let outcome = set. remove ( 11_2 , 11 , Some ( 10_1 ) ) . unwrap ( ) ;
413+ assert_eq ! ( outcome. removed. hash, 11_2 ) ;
414+ assert_eq ! ( outcome. inserted, Some ( 10_1 ) ) ;
415+ assert_eq ! ( set. count( ) , 1 ) ;
416+ assert ! ( set. contains( 10 , 10_1 ) ) ;
417+
418+ set. undo ( ) . undo_remove ( outcome) ;
419+ assert_eq ! ( set. count( ) , 1 ) ;
420+ assert ! ( set. contains( 11 , 11_2 ) ) ;
421+ }
422+
423+ #[ test]
424+ fn finalization_works ( ) {
425+ let mut set = LeafSet :: new ( ) ;
426+ set. import ( 9_1u32 , 9u32 , 0u32 ) ;
427+ set. import ( 10_1 , 10 , 9_1 ) ;
428+ set. import ( 10_2 , 10 , 9_1 ) ;
429+ set. import ( 11_1 , 11 , 10_1 ) ;
430+ set. import ( 11_2 , 11 , 10_1 ) ;
431+ set. import ( 12_1 , 12 , 11_2 ) ;
432+
433+ let outcome = set. finalize_height ( 11 ) ;
434+ assert_eq ! ( set. count( ) , 2 ) ;
435+ assert ! ( set. contains( 11 , 11_1 ) ) ;
436+ assert ! ( set. contains( 12 , 12_1 ) ) ;
437+ assert_eq ! (
438+ outcome. removed,
439+ [ ( Reverse ( 10 ) , vec![ 10_2 ] ) ] . into_iter( ) . collect:: <BTreeMap <_, _>>( ) ,
440+ ) ;
441+
442+ set. undo ( ) . undo_finalization ( outcome) ;
443+ assert_eq ! ( set. count( ) , 3 ) ;
444+ assert ! ( set. contains( 11 , 11_1 ) ) ;
445+ assert ! ( set. contains( 12 , 12_1 ) ) ;
446+ assert ! ( set. contains( 10 , 10_2 ) ) ;
320447 }
321448
322449 #[ test]
@@ -383,44 +510,4 @@ mod tests {
383510 let set2 = LeafSet :: read_from_db ( & * db, 0 , PREFIX ) . unwrap ( ) ;
384511 assert_eq ! ( set, set2) ;
385512 }
386-
387- #[ test]
388- fn undo_import ( ) {
389- let mut set = LeafSet :: new ( ) ;
390- set. import ( 10_1u32 , 10u32 , 0u32 ) ;
391- set. import ( 11_1 , 11 , 10_1 ) ;
392- set. import ( 11_2 , 11 , 10_1 ) ;
393-
394- let displaced = set. import ( 12_1 , 12 , 11_1 ) . unwrap ( ) ;
395- assert_eq ! ( set. count( ) , 2 ) ;
396- assert ! ( set. contains( 11 , 11_2 ) ) ;
397- assert ! ( set. contains( 12 , 12_1 ) ) ;
398-
399- set. undo ( ) . undo_import ( displaced) ;
400- assert_eq ! ( set. count( ) , 2 ) ;
401- assert ! ( set. contains( 11 , 11_1 ) ) ;
402- assert ! ( set. contains( 11 , 11_2 ) ) ;
403- }
404-
405- #[ test]
406- fn undo_finalization ( ) {
407- let mut set = LeafSet :: new ( ) ;
408- set. import ( 9_1u32 , 9u32 , 0u32 ) ;
409- set. import ( 10_1 , 10 , 9_1 ) ;
410- set. import ( 10_2 , 10 , 9_1 ) ;
411- set. import ( 11_1 , 11 , 10_1 ) ;
412- set. import ( 11_2 , 11 , 10_1 ) ;
413- set. import ( 12_1 , 12 , 11_2 ) ;
414-
415- let displaced = set. finalize_height ( 11 ) ;
416- assert_eq ! ( set. count( ) , 2 ) ;
417- assert ! ( set. contains( 11 , 11_1 ) ) ;
418- assert ! ( set. contains( 12 , 12_1 ) ) ;
419-
420- set. undo ( ) . undo_finalization ( displaced) ;
421- assert_eq ! ( set. count( ) , 3 ) ;
422- assert ! ( set. contains( 11 , 11_1 ) ) ;
423- assert ! ( set. contains( 12 , 12_1 ) ) ;
424- assert ! ( set. contains( 10 , 10_2 ) ) ;
425- }
426513}
0 commit comments