@@ -3,7 +3,12 @@ use std::error::Error;
33use std:: marker:: PhantomData ;
44
55use apollo_committer_config:: config:: CommitterConfig ;
6- use apollo_committer_types:: committer_types:: { CommitBlockRequest , CommitBlockResponse } ;
6+ use apollo_committer_types:: committer_types:: {
7+ CommitBlockRequest ,
8+ CommitBlockResponse ,
9+ RevertBlockRequest ,
10+ RevertBlockResponse ,
11+ } ;
712use apollo_committer_types:: errors:: { CommitterError , CommitterResult } ;
813use starknet_api:: block:: BlockNumber ;
914use starknet_api:: block_hash:: state_diff_hash:: calculate_state_diff_hash;
@@ -123,6 +128,55 @@ impl<S: StorageConstructor, CB: CommitBlockTrait> Committer<S, CB> {
123128 Ok ( CommitBlockResponse { state_root : global_root } )
124129 }
125130
131+ /// Applies the given state diff to revert the changes of the given height.
132+ pub async fn revert_block (
133+ & mut self ,
134+ RevertBlockRequest { reversed_state_diff, height } : RevertBlockRequest ,
135+ ) -> CommitterResult < RevertBlockResponse > {
136+ let Some ( last_committed_block) = self . offset . prev ( ) else {
137+ // No committed blocks. Nothing to revert.
138+ return Ok ( RevertBlockResponse :: Uncommitted ) ;
139+ } ;
140+
141+ if height > self . offset {
142+ // Request to revert a future height. Nothing to revert.
143+ return Ok ( RevertBlockResponse :: Uncommitted ) ;
144+ }
145+
146+ if height == self . offset {
147+ // Request to revert the next future height.
148+ // Nothing to revert, but we have the resulted state root.
149+ let db_state_root = self . load_global_root ( last_committed_block) . await ?;
150+ return Ok ( RevertBlockResponse :: AlreadyReverted ( db_state_root) ) ;
151+ }
152+
153+ if height < last_committed_block {
154+ // Request to revert an old height. Nothing to revert.
155+ // Returns an error, indicating the committer has a hole in the revert series.
156+ return Err ( CommitterError :: RevertHeightHole {
157+ input_height : height,
158+ last_committed_block,
159+ } ) ;
160+ }
161+ // Sanity.
162+ assert_eq ! ( height, last_committed_block) ;
163+ // Happy flow. Reverts the state diff and returns the computed global root.
164+ let ( filled_forest, revert_global_root) =
165+ self . commit_state_diff ( reversed_state_diff) . await ?;
166+
167+ // Ignore entries with block number key equals to or higher than the offset.
168+ let metadata = HashMap :: from ( [ (
169+ ForestMetadataType :: CommitmentOffset ,
170+ DbValue ( DbBlockNumber ( last_committed_block) . serialize ( ) . to_vec ( ) ) ,
171+ ) ] ) ;
172+ self . forest_storage
173+ . write_with_metadata ( & filled_forest, metadata)
174+ . await
175+ . map_err ( |err| self . map_internal_error ( err) ) ?;
176+ self . offset = last_committed_block;
177+ Ok ( RevertBlockResponse :: RevertedTo ( revert_global_root) )
178+ }
179+
126180 async fn load_state_diff_commitment (
127181 & mut self ,
128182 block_number : BlockNumber ,
0 commit comments