1- use alloy_rpc_types_eth:: Withdrawals ;
2- use reth:: core:: primitives:: InMemorySize ;
3- use reth_node_api:: NodePrimitives ;
4- use reth_optimism_evm:: BasicOpReceiptBuilder ;
5- use reth_optimism_evm:: { OpReceiptBuilder , ReceiptBuilderCtx } ;
6- use reth_optimism_payload_builder:: OpPayloadPrimitives ;
7- use reth_transaction_pool:: PoolTransaction ;
8- use std:: { fmt:: Display , sync:: Arc , time:: Instant } ;
9-
101use crate :: generator:: BlockPayloadJobGenerator ;
112use crate :: generator:: BuildArguments ;
123use crate :: {
134 generator:: { BlockCell , PayloadBuilder } ,
145 metrics:: OpRBuilderMetrics ,
156 tx_signer:: Signer ,
167} ;
8+ use alloy_consensus:: constants:: EMPTY_WITHDRAWALS ;
179use alloy_consensus:: {
1810 Eip658Value , Header , Transaction , TxEip1559 , Typed2718 , EMPTY_OMMER_ROOT_HASH ,
1911} ;
2012use alloy_eips:: merge:: BEACON_NONCE ;
13+ use alloy_primitives:: private:: alloy_rlp:: Encodable ;
2114use alloy_primitives:: { Address , Bytes , TxKind , B256 , U256 } ;
2215use alloy_rpc_types_engine:: PayloadId ;
16+ use alloy_rpc_types_eth:: Withdrawals ;
2317use op_alloy_consensus:: { OpDepositReceipt , OpTypedTransaction } ;
2418use reth:: builder:: { components:: PayloadServiceBuilder , node:: FullNodeTypes , BuilderContext } ;
19+ use reth:: core:: primitives:: InMemorySize ;
2520use reth:: payload:: PayloadBuilderHandle ;
26- use reth_basic_payload_builder:: commit_withdrawals;
2721use reth_basic_payload_builder:: {
2822 BasicPayloadJobGeneratorConfig , BuildOutcome , BuildOutcomeKind , PayloadConfig ,
2923} ;
@@ -34,19 +28,25 @@ use reth_evm::{
3428 EvmError , InvalidTxError , NextBlockEnvAttributes ,
3529} ;
3630use reth_execution_types:: ExecutionOutcome ;
31+ use reth_node_api:: NodePrimitives ;
3732use reth_node_api:: NodeTypesWithEngine ;
3833use reth_node_api:: TxTy ;
3934use reth_optimism_chainspec:: OpChainSpec ;
4035use reth_optimism_consensus:: calculate_receipt_root_no_memo_optimism;
36+ use reth_optimism_evm:: BasicOpReceiptBuilder ;
4137use reth_optimism_evm:: OpEvmConfig ;
38+ use reth_optimism_evm:: { OpReceiptBuilder , ReceiptBuilderCtx } ;
4239use reth_optimism_forks:: OpHardforks ;
4340use reth_optimism_node:: OpEngineTypes ;
41+ use reth_optimism_payload_builder:: config:: { OpBuilderConfig , OpDAConfig } ;
42+ use reth_optimism_payload_builder:: OpPayloadPrimitives ;
4443use reth_optimism_payload_builder:: {
4544 error:: OpPayloadBuilderError ,
4645 payload:: { OpBuiltPayload , OpPayloadBuilderAttributes } ,
4746} ;
48- use reth_optimism_primitives:: OpPrimitives ;
49- use reth_optimism_primitives:: OpTransactionSigned ;
47+ use reth_optimism_primitives:: {
48+ OpPrimitives , OpTransactionSigned , ADDRESS_L2_TO_L1_MESSAGE_PASSER ,
49+ } ;
5050use reth_payload_builder:: PayloadBuilderService ;
5151use reth_payload_builder_primitives:: PayloadBuilderError ;
5252use reth_payload_primitives:: PayloadBuilderAttributes ;
@@ -63,13 +63,15 @@ use reth_provider::{
6363} ;
6464use reth_revm:: database:: StateProviderDatabase ;
6565use reth_transaction_pool:: BestTransactionsAttributes ;
66+ use reth_transaction_pool:: PoolTransaction ;
6667use reth_transaction_pool:: TransactionPool ;
6768use revm:: {
6869 db:: { states:: bundle_state:: BundleRetention , State } ,
6970 primitives:: { ExecutionResult , ResultAndState } ,
7071 DatabaseCommit ,
7172} ;
7273use std:: error:: Error as StdError ;
74+ use std:: { fmt:: Display , sync:: Arc , time:: Instant } ;
7375use tokio_util:: sync:: CancellationToken ;
7476use tracing:: { info, trace, warn} ;
7577
@@ -183,6 +185,8 @@ pub struct OpPayloadBuilderVanilla<Pool, Client, EvmConfig, N: NodePrimitives, T
183185 pub pool : Pool ,
184186 /// Node client
185187 pub client : Client ,
188+ /// Settings for the builder, e.g. DA settings.
189+ pub config : OpBuilderConfig ,
186190 /// The type responsible for yielding the best transactions for the payload if mempool
187191 /// transactions are allowed.
188192 pub best_transactions : Txs ,
@@ -203,14 +207,33 @@ impl<Pool, Client, EvmConfig, N: NodePrimitives>
203207 client : Client ,
204208 receipt_builder : Arc < dyn OpReceiptBuilder < N :: SignedTx , Receipt = N :: Receipt > > ,
205209 ) -> Self {
206- Self {
210+ Self :: with_builder_config (
207211 evm_config,
208212 builder_signer,
209213 pool,
210214 client,
215+ receipt_builder,
216+ Default :: default ( ) ,
217+ )
218+ }
219+
220+ pub fn with_builder_config (
221+ evm_config : EvmConfig ,
222+ builder_signer : Option < Signer > ,
223+ pool : Pool ,
224+ client : Client ,
225+ receipt_builder : Arc < dyn OpReceiptBuilder < N :: SignedTx , Receipt = N :: Receipt > > ,
226+ config : OpBuilderConfig ,
227+ ) -> Self {
228+ Self {
229+ pool,
230+ client,
231+ receipt_builder,
232+ config,
233+ evm_config,
211234 best_transactions : ( ) ,
212235 metrics : Default :: default ( ) ,
213- receipt_builder ,
236+ builder_signer ,
214237 }
215238 }
216239}
@@ -301,6 +324,7 @@ where
301324
302325 let ctx = OpPayloadBuilderCtx {
303326 evm_config : self . evm_config . clone ( ) ,
327+ da_config : self . config . da_config . clone ( ) ,
304328 chain_spec : self . client . chain_spec ( ) ,
305329 config,
306330 evm_env,
@@ -421,14 +445,34 @@ impl<Txs> OpBuilder<'_, Txs> {
421445 . builder_signer ( )
422446 . map_or ( 0 , |_| estimate_gas_for_builder_tx ( message. clone ( ) ) ) ;
423447 let block_gas_limit = ctx. block_gas_limit ( ) - builder_tx_gas;
448+ // Save some space in the block_da_limit for builder tx
449+ let builder_tx_da_size = ctx
450+ . estimate_builder_tx_da_size ( state, builder_tx_gas, message. clone ( ) )
451+ . unwrap_or ( 0 ) ;
452+ let block_da_limit = ctx
453+ . da_config
454+ . max_da_block_size ( )
455+ . map ( |da_size| da_size - builder_tx_da_size as u64 ) ;
456+ // Check that it's possible to create builder tx, considering max_da_tx_size, otherwise panic
457+ if let Some ( tx_da_limit) = ctx. da_config . max_da_tx_size ( ) {
458+ // Panic indicate max_da_tx_size misconfiguration
459+ assert ! ( tx_da_limit >= builder_tx_da_size as u64 ) ;
460+ }
461+
424462 if !ctx. attributes ( ) . no_tx_pool {
425463 let best_txs_start_time = Instant :: now ( ) ;
426464 let best_txs = best ( ctx. best_transaction_attributes ( ) ) ;
427465 ctx. metrics
428466 . transaction_pool_fetch_duration
429467 . record ( best_txs_start_time. elapsed ( ) ) ;
430468 if ctx
431- . execute_best_transactions ( & mut info, state, best_txs, block_gas_limit) ?
469+ . execute_best_transactions (
470+ & mut info,
471+ state,
472+ best_txs,
473+ block_gas_limit,
474+ block_da_limit,
475+ ) ?
432476 . is_some ( )
433477 {
434478 return Ok ( BuildOutcomeKind :: Cancelled ) ;
@@ -438,8 +482,6 @@ impl<Txs> OpBuilder<'_, Txs> {
438482 // Add builder tx to the block
439483 ctx. add_builder_tx ( & mut info, state, builder_tx_gas, message) ;
440484
441- let withdrawals_root = ctx. commit_withdrawals ( state) ?;
442-
443485 let state_merge_start_time = Instant :: now ( ) ;
444486
445487 // merge all transitions into bundle state, this would apply the withdrawal balance changes
@@ -453,12 +495,27 @@ impl<Txs> OpBuilder<'_, Txs> {
453495 . payload_num_tx
454496 . record ( info. executed_transactions . len ( ) as f64 ) ;
455497
456- Ok ( BuildOutcomeKind :: Better {
457- payload : ExecutedPayload {
458- info,
459- withdrawals_root,
460- } ,
461- } )
498+ let withdrawals_root = if ctx. is_isthmus_active ( ) {
499+ // withdrawals root field in block header is used for storage root of L2 predeploy
500+ // `l2tol1-message-passer`
501+ Some (
502+ state
503+ . database
504+ . as_ref ( )
505+ . storage_root ( ADDRESS_L2_TO_L1_MESSAGE_PASSER , Default :: default ( ) ) ?,
506+ )
507+ } else if ctx. is_canyon_active ( ) {
508+ Some ( EMPTY_WITHDRAWALS )
509+ } else {
510+ None
511+ } ;
512+
513+ let payload = ExecutedPayload {
514+ info,
515+ withdrawals_root,
516+ } ;
517+
518+ Ok ( BuildOutcomeKind :: Better { payload } )
462519 }
463520
464521 /// Builds the payload on top of the state.
@@ -651,6 +708,8 @@ pub struct ExecutionInfo<N: NodePrimitives> {
651708 pub receipts : Vec < N :: Receipt > ,
652709 /// All gas used so far
653710 pub cumulative_gas_used : u64 ,
711+ /// Estimated DA size
712+ pub cumulative_da_bytes_used : u64 ,
654713 /// Tracks fees from executed mempool transactions
655714 pub total_fees : U256 ,
656715}
@@ -663,16 +722,45 @@ impl<N: NodePrimitives> ExecutionInfo<N> {
663722 executed_senders : Vec :: with_capacity ( capacity) ,
664723 receipts : Vec :: with_capacity ( capacity) ,
665724 cumulative_gas_used : 0 ,
725+ cumulative_da_bytes_used : 0 ,
666726 total_fees : U256 :: ZERO ,
667727 }
668728 }
729+
730+ /// Returns true if the transaction would exceed the block limits:
731+ /// - block gas limit: ensures the transaction still fits into the block.
732+ /// - tx DA limit: if configured, ensures the tx does not exceed the maximum allowed DA limit
733+ /// per tx.
734+ /// - block DA limit: if configured, ensures the transaction's DA size does not exceed the
735+ /// maximum allowed DA limit per block.
736+ pub fn is_tx_over_limits (
737+ & self ,
738+ tx : & N :: SignedTx ,
739+ block_gas_limit : u64 ,
740+ tx_data_limit : Option < u64 > ,
741+ block_data_limit : Option < u64 > ,
742+ ) -> bool {
743+ if tx_data_limit. is_some_and ( |da_limit| tx. length ( ) as u64 > da_limit) {
744+ return true ;
745+ }
746+
747+ if block_data_limit
748+ . is_some_and ( |da_limit| self . cumulative_da_bytes_used + ( tx. length ( ) as u64 ) > da_limit)
749+ {
750+ return true ;
751+ }
752+
753+ self . cumulative_gas_used + tx. gas_limit ( ) > block_gas_limit
754+ }
669755}
670756
671757/// Container type that holds all necessities to build a new payload.
672758#[ derive( Debug ) ]
673759pub struct OpPayloadBuilderCtx < EvmConfig : ConfigureEvmEnv , ChainSpec , N : NodePrimitives > {
674760 /// The type that knows how to perform system calls and configure the evm.
675761 pub evm_config : EvmConfig ,
762+ /// The DA config for the payload builder
763+ pub da_config : OpDAConfig ,
676764 /// The chainspec
677765 pub chain_spec : Arc < ChainSpec > ,
678766 /// How to build the payload.
@@ -802,8 +890,13 @@ where
802890 . is_holocene_active_at_timestamp ( self . attributes ( ) . timestamp ( ) )
803891 }
804892
893+ /// Returns true if isthmus is active for the payload.
894+ pub fn is_isthmus_active ( & self ) -> bool {
895+ self . chain_spec
896+ . is_isthmus_active_at_timestamp ( self . attributes ( ) . timestamp ( ) )
897+ }
898+
805899 /// Returns the chain id
806- /// #
807900 pub fn chain_id ( & self ) -> u64 {
808901 self . chain_spec . chain_id ( )
809902 }
@@ -813,19 +906,6 @@ where
813906 self . builder_signer
814907 }
815908
816- /// Commits the withdrawals from the payload attributes to the state.
817- pub fn commit_withdrawals < DB > ( & self , db : & mut State < DB > ) -> Result < Option < B256 > , ProviderError >
818- where
819- DB : Database < Error = ProviderError > ,
820- {
821- commit_withdrawals (
822- db,
823- & self . chain_spec ,
824- self . attributes ( ) . payload_attributes . timestamp ,
825- & self . attributes ( ) . payload_attributes . withdrawals ,
826- )
827- }
828-
829909 /// Ensure that the create2deployer is force-deployed at the canyon transition. Optimism
830910 /// blocks will always have at least a single transaction in them (the L1 info transaction),
831911 /// so we can safely assume that this will always be triggered upon the transition and that
@@ -1020,6 +1100,7 @@ where
10201100 Transaction : PoolTransaction < Consensus = EvmConfig :: Transaction > ,
10211101 > ,
10221102 block_gas_limit : u64 ,
1103+ block_da_limit : Option < u64 > ,
10231104 ) -> Result < Option < ( ) > , PayloadBuilderError >
10241105 where
10251106 DB : Database < Error = ProviderError > ,
@@ -1030,14 +1111,14 @@ where
10301111 let mut num_txs_simulated_success = 0 ;
10311112 let mut num_txs_simulated_fail = 0 ;
10321113 let base_fee = self . base_fee ( ) ;
1033-
1114+ let tx_da_limit = self . da_config . max_da_tx_size ( ) ;
10341115 let mut evm = self . evm_config . evm_with_env ( & mut * db, self . evm_env . clone ( ) ) ;
10351116
10361117 while let Some ( tx) = best_txs. next ( ( ) ) {
10371118 let tx = tx. into_consensus ( ) ;
10381119 num_txs_considered += 1 ;
10391120 // ensure we still have capacity for this transaction
1040- if info. cumulative_gas_used + tx. gas_limit ( ) > block_gas_limit {
1121+ if info. is_tx_over_limits ( tx. tx ( ) , block_gas_limit, tx_da_limit , block_da_limit ) {
10411122 // we can't fit this transaction into the block, so we need to mark it as
10421123 // invalid which also removes all dependent transaction from
10431124 // the iterator before we can continue
@@ -1207,6 +1288,54 @@ where
12071288 None
12081289 } )
12091290 }
1291+
1292+ /// Calculates EIP 2718 builder transaction size
1293+ pub fn estimate_builder_tx_da_size < DB > (
1294+ & self ,
1295+ db : & mut State < DB > ,
1296+ builder_tx_gas : u64 ,
1297+ message : Vec < u8 > ,
1298+ ) -> Option < usize >
1299+ where
1300+ DB : Database < Error = ProviderError > ,
1301+ {
1302+ self . builder_signer ( )
1303+ . map ( |signer| {
1304+ let base_fee = self . base_fee ( ) ;
1305+ // Create message with block number for the builder to sign
1306+ let nonce = db
1307+ . load_cache_account ( signer. address )
1308+ . map ( |acc| acc. account_info ( ) . unwrap_or_default ( ) . nonce )
1309+ . map_err ( |_| {
1310+ PayloadBuilderError :: other ( OpPayloadBuilderError :: AccountLoadFailed (
1311+ signer. address ,
1312+ ) )
1313+ } ) ?;
1314+
1315+ // Create the EIP-1559 transaction
1316+ let eip1559 = OpTypedTransaction :: Eip1559 ( TxEip1559 {
1317+ chain_id : self . chain_id ( ) ,
1318+ nonce,
1319+ gas_limit : builder_tx_gas,
1320+ max_fee_per_gas : base_fee. into ( ) ,
1321+ max_priority_fee_per_gas : 0 ,
1322+ to : TxKind :: Call ( Address :: ZERO ) ,
1323+ // Include the message as part of the transaction data
1324+ input : message. into ( ) ,
1325+ ..Default :: default ( )
1326+ } ) ;
1327+ let tx = eip1559;
1328+ // Sign the transaction
1329+ let builder_tx = signer. sign_tx ( tx) . map_err ( PayloadBuilderError :: other) ?;
1330+
1331+ Ok ( builder_tx. length ( ) )
1332+ } )
1333+ . transpose ( )
1334+ . unwrap_or_else ( |err : PayloadBuilderError | {
1335+ warn ! ( target: "payload_builder" , %err, "Failed to add builder transaction" ) ;
1336+ None
1337+ } )
1338+ }
12101339}
12111340
12121341fn estimate_gas_for_builder_tx ( input : Vec < u8 > ) -> u64 {
0 commit comments