66mod sequencer_consensus_context_test;
77
88use std:: cmp:: max;
9- use std:: collections:: { BTreeMap , HashMap , VecDeque } ;
9+ use std:: collections:: { BTreeMap , HashMap } ;
1010use std:: sync:: { Arc , Mutex } ;
1111use std:: time:: Duration ;
1212
@@ -235,9 +235,8 @@ pub struct SequencerConsensusContext {
235235 l2_gas_price : GasPrice ,
236236 l1_da_mode : L1DataAvailabilityMode ,
237237 previous_proposal_init : Option < PreviousProposalInitInfo > ,
238- /// SNIP-35: sliding window of recent fee_proposal values (size from
239- /// `FEE_PROPOSAL_WINDOW_SIZE`).
240- fee_proposals_window : VecDeque < GasPrice > ,
238+ /// SNIP-35 fee_proposals window. `None` = pre-V0_14_3.
239+ fee_proposals_window : BTreeMap < BlockNumber , Option < GasPrice > > ,
241240}
242241
243242#[ derive( Clone ) ]
@@ -288,16 +287,25 @@ impl SequencerConsensusContext {
288287 l2_gas_price : VersionedConstants :: latest_constants ( ) . min_gas_price ,
289288 l1_da_mode,
290289 previous_proposal_init : None ,
291- fee_proposals_window : VecDeque :: with_capacity ( FEE_PROPOSAL_WINDOW_SIZE ) ,
290+ fee_proposals_window : BTreeMap :: new ( ) ,
292291 }
293292 }
294293
295- /// FIFO append into the SNIP-35 sliding window.
296- fn push_fee_proposal ( & mut self , fee_proposal : GasPrice ) {
297- if self . fee_proposals_window . len ( ) >= FEE_PROPOSAL_WINDOW_SIZE {
298- self . fee_proposals_window . pop_front ( ) ;
299- }
300- self . fee_proposals_window . push_back ( fee_proposal) ;
294+ fn record_fee_proposal ( & mut self , height : BlockNumber , fee_proposal_fri : Option < GasPrice > ) {
295+ self . fee_proposals_window . insert ( height, fee_proposal_fri) ;
296+ }
297+
298+ /// Drop fee_proposals older than the SNIP-35 window so only heights in
299+ /// `[current_height - FEE_PROPOSAL_WINDOW_SIZE, ..)` remain.
300+ ///
301+ /// `BTreeMap::split_off(&cutoff)` is inclusive on `cutoff`: it returns the entries with
302+ /// key `>= cutoff` and leaves keys `< cutoff` in `self`. Reassigning the returned half
303+ /// back to the field keeps `[cutoff, ..)` and drops everything strictly below.
304+ fn prune_fee_proposals_window ( & mut self , current_height : BlockNumber ) {
305+ let window_size =
306+ u64:: try_from ( FEE_PROPOSAL_WINDOW_SIZE ) . expect ( "FEE_PROPOSAL_WINDOW_SIZE fits in u64" ) ;
307+ let cutoff = BlockNumber ( current_height. 0 . saturating_sub ( window_size) ) ;
308+ self . fee_proposals_window = self . fee_proposals_window . split_off ( & cutoff) ;
301309 }
302310
303311 /// SNIP-35: bootstrap the fee_proposals window from state_sync on startup so `fee_actual` is
@@ -315,11 +323,13 @@ impl SequencerConsensusContext {
315323 u64:: try_from ( FEE_PROPOSAL_WINDOW_SIZE ) . expect ( "FEE_PROPOSAL_WINDOW_SIZE fits in u64" ) ;
316324 let start = height. 0 . saturating_sub ( window_size) ;
317325 for h in start..height. 0 {
318- match self . deps . state_sync_client . get_block ( BlockNumber ( h) ) . await {
326+ let block_number = BlockNumber ( h) ;
327+ match self . deps . state_sync_client . get_block ( block_number) . await {
319328 Ok ( block) => {
320- if let Some ( fee_proposal) = block. block_header_without_hash . fee_proposal_fri {
321- self . push_fee_proposal ( fee_proposal) ;
322- }
329+ self . record_fee_proposal (
330+ block_number,
331+ block. block_header_without_hash . fee_proposal_fri ,
332+ ) ;
323333 }
324334 Err ( e) => {
325335 warn ! (
@@ -436,9 +446,7 @@ impl SequencerConsensusContext {
436446 let DecisionReachedResponse { state_diff, central_objects } = decision_reached_response;
437447
438448 self . update_l2_gas_price ( height, l2_gas_used) ;
439- if let Some ( fee_proposal) = init. fee_proposal_fri {
440- self . push_fee_proposal ( fee_proposal) ;
441- }
449+ self . record_fee_proposal ( height, init. fee_proposal_fri ) ;
442450
443451 // A hash map of (possibly failed) transactions, where the key is the transaction hash
444452 // and the value is the transaction itself.
@@ -891,9 +899,10 @@ impl ConsensusContext for SequencerConsensusContext {
891899 sync_block. block_header_without_hash . next_l2_gas_price ,
892900 VersionedConstants :: latest_constants ( ) . min_gas_price ,
893901 ) ;
894- if let Some ( fee_proposal) = sync_block. block_header_without_hash . fee_proposal_fri {
895- self . push_fee_proposal ( fee_proposal) ;
896- }
902+ self . record_fee_proposal (
903+ sync_block. block_header_without_hash . block_number ,
904+ sync_block. block_header_without_hash . fee_proposal_fri ,
905+ ) ;
897906
898907 // TODO(Asmaa): validate starknet_version and parent_hash when they are stored.
899908 let block_number = sync_block. block_header_without_hash . block_number ;
@@ -958,6 +967,7 @@ impl ConsensusContext for SequencerConsensusContext {
958967 }
959968 self . current_height = Some ( height) ;
960969 self . current_round = round;
970+ self . prune_fee_proposals_window ( height) ;
961971 self . queued_proposals . clear ( ) ;
962972 // The Batcher must be told when we begin to work on a new height. The implicit model is
963973 // that consensus works on a given height until it is done (either a decision is reached
0 commit comments