@@ -80,6 +80,18 @@ pub trait BlockBuildingHelper: Send + Sync {
8080 /// Name of the builder that pregenerated this block.
8181 /// BE CAREFUL: Might be ambiguous if several building parts were involved...
8282 fn builder_name ( & self ) -> & str ;
83+
84+ fn prefinalize_block (
85+ & mut self ,
86+ local_ctx : & mut ThreadBlockBuildingContext ,
87+ ) -> Result < ( ) , BlockBuildingHelperError > ;
88+
89+ fn finalize_prefinalized_block (
90+ & mut self ,
91+ local_ctx : & mut ThreadBlockBuildingContext ,
92+ payout_tx_value : U256 ,
93+ seen_competition_bid : Option < U256 > ,
94+ ) -> Result < FinalizeBlockResult , BlockBuildingHelperError > ;
8395}
8496
8597/// Wraps a BlockBuildingHelper with a valid true_block_value which makes it ready to bid.
@@ -134,6 +146,13 @@ pub struct BlockBuildingHelperFromProvider<
134146 built_block_trace : BuiltBlockTrace ,
135147 /// Token to cancel in case of fatal error (if we believe that it's impossible to build for this block).
136148 cancel_on_fatal_error : CancellationToken ,
149+
150+ prefinalize_state : Option < PrefinalizeState > ,
151+ }
152+
153+ #[ derive( Debug , Clone ) ]
154+ pub struct PrefinalizeState {
155+ builder_nonce : u64 ,
137156}
138157
139158#[ derive( Debug , thiserror:: Error ) ]
@@ -152,6 +171,8 @@ pub enum BlockBuildingHelperError {
152171 FinalizeError ( #[ from] FinalizeError ) ,
153172 #[ error( "Provider historical block hashes error: {0}" ) ]
154173 HistoricalBlockError ( #[ from] HistoricalBlockError ) ,
174+ #[ error( "Block is not prefinalized" ) ]
175+ BlockIsNotPrefinalized ,
155176}
156177
157178impl BlockBuildingHelperError {
@@ -250,6 +271,7 @@ impl<
250271 building_ctx,
251272 built_block_trace,
252273 cancel_on_fatal_error,
274+ prefinalize_state : None ,
253275 } )
254276 }
255277
@@ -472,4 +494,109 @@ impl<
472494 self . built_block_trace
473495 . set_filtered_build_statistics ( considered_orders_statistics, failed_orders_statistics) ;
474496 }
497+
498+ // prepare block for fast finalization
499+ // executes the most expensive part of finalization so that adding a bid transaction is fast
500+ fn prefinalize_block (
501+ & mut self ,
502+ local_ctx : & mut ThreadBlockBuildingContext ,
503+ ) -> Result < ( ) , BlockBuildingHelperError > {
504+ self . built_block_trace
505+ . verify_bundle_consistency ( & self . building_ctx . blocklist ) ?;
506+
507+ let builder_nonce = self
508+ . partial_block
509+ . insert_combined_refunds_two_step_finalize (
510+ & self . building_ctx ,
511+ local_ctx,
512+ & mut self . block_state ,
513+ ) ?;
514+
515+ self . prefinalize_state = Some ( PrefinalizeState { builder_nonce } ) ;
516+
517+ Ok ( ( ) )
518+ }
519+
520+ fn finalize_prefinalized_block (
521+ & mut self ,
522+ local_ctx : & mut ThreadBlockBuildingContext ,
523+ payout_tx_value : U256 ,
524+ seen_competition_bid : Option < U256 > ,
525+ ) -> Result < FinalizeBlockResult , BlockBuildingHelperError > {
526+ let start_time = Instant :: now ( ) ;
527+
528+ let prefinalize_state = if let Some ( state) = self . prefinalize_state . as_mut ( ) {
529+ state
530+ } else {
531+ return Err ( BlockBuildingHelperError :: BlockIsNotPrefinalized ) ;
532+ } ;
533+
534+ let mut partial_block = self . partial_block . clone ( ) ;
535+ let mut block_state = self . block_state . clone ( ) ;
536+
537+ let payout_tx_gas = self . payout_tx_gas ;
538+ partial_block. insert_refund_tx_two_step_finalize (
539+ & self . building_ctx ,
540+ local_ctx,
541+ & mut block_state,
542+ payout_tx_gas,
543+ payout_tx_value,
544+ prefinalize_state. builder_nonce ,
545+ ) ?;
546+
547+ let fee_recipient_balance_after = block_state. balance (
548+ self . building_ctx . attributes . suggested_fee_recipient ,
549+ & self . building_ctx . shared_cached_reads ,
550+ & mut local_ctx. cached_reads ,
551+ ) ?;
552+ let fee_recipient_balance_diff = fee_recipient_balance_after
553+ . checked_sub ( self . _fee_recipient_balance_start )
554+ . unwrap_or_default ( ) ;
555+
556+ self . built_block_trace . bid_value = max ( payout_tx_value, fee_recipient_balance_diff) ;
557+ self . built_block_trace . true_bid_value =
558+ partial_block. get_proposer_payout_tx_value ( payout_tx_gas, & self . building_ctx ) ?;
559+
560+ let sim_gas_used = partial_block. tracer . used_gas ;
561+ let block_number = self . building_context ( ) . block ( ) ;
562+
563+ let finalized_block =
564+ match partial_block. finalize ( block_state, & self . building_ctx , local_ctx) {
565+ Ok ( finalized_block) => finalized_block,
566+ Err ( err) => {
567+ if err. is_consistent_db_view_err ( ) {
568+ debug ! (
569+ block_number,
570+ payload_id = self . building_ctx. payload_id,
571+ "Can't build on this head, cancelling slot"
572+ ) ;
573+ self . cancel_on_fatal_error . cancel ( ) ;
574+ }
575+ return Err ( BlockBuildingHelperError :: FinalizeError ( err) ) ;
576+ }
577+ } ;
578+
579+ self . built_block_trace . update_orders_sealed_at ( ) ;
580+ self . built_block_trace . root_hash_time = finalized_block. root_hash_time ;
581+ self . built_block_trace . finalize_time = start_time. elapsed ( ) ;
582+ self . built_block_trace . seen_competition_bid = seen_competition_bid;
583+
584+ Self :: trace_finalized_block (
585+ & finalized_block,
586+ & self . builder_name ,
587+ & self . building_ctx ,
588+ & self . built_block_trace ,
589+ sim_gas_used,
590+ ) ;
591+
592+ let block = Block {
593+ trace : self . built_block_trace . clone ( ) ,
594+ sealed_block : finalized_block. sealed_block ,
595+ txs_blobs_sidecars : finalized_block. txs_blob_sidecars ,
596+ builder_name : self . builder_name . clone ( ) ,
597+ execution_requests : finalized_block. execution_requests ,
598+ bid_adjustments : finalized_block. bid_adjustments ,
599+ } ;
600+ Ok ( FinalizeBlockResult { block } )
601+ }
475602}
0 commit comments