1- use alloy_consensus:: TxEip1559 ;
2- use alloy_eips:: { eip7623:: TOTAL_COST_FLOOR_PER_TOKEN , Encodable2718 } ;
31use alloy_evm:: Database ;
42use alloy_primitives:: {
53 map:: foldhash:: { HashSet , HashSetExt } ,
6- Address , TxKind ,
4+ Address ,
75} ;
86use core:: fmt:: Debug ;
9- use op_alloy_consensus:: OpTypedTransaction ;
107use op_revm:: OpTransactionError ;
118use reth_evm:: { eth:: receipt_builder:: ReceiptBuilderCtx , ConfigureEvm , Evm } ;
129use reth_node_api:: PayloadBuilderError ;
1310use reth_optimism_primitives:: OpTransactionSigned ;
1411use reth_primitives:: Recovered ;
1512use reth_provider:: { ProviderError , StateProvider } ;
16- use reth_revm:: State ;
13+ use reth_revm:: {
14+ database:: StateProviderDatabase , db:: states:: bundle_state:: BundleRetention , State ,
15+ } ;
1716use revm:: {
1817 context:: result:: { EVMError , ResultAndState } ,
1918 DatabaseCommit ,
2019} ;
2120use tracing:: { debug, warn} ;
2221
23- use crate :: {
24- builders:: context:: OpPayloadBuilderCtx , primitives:: reth:: ExecutionInfo , tx_signer:: Signer ,
25- } ;
22+ use crate :: { builders:: context:: OpPayloadBuilderCtx , primitives:: reth:: ExecutionInfo } ;
2623
24+ #[ derive( Debug , Clone ) ]
2725pub struct BuilderTransactionCtx {
2826 pub gas_used : u64 ,
2927 pub da_size : u64 ,
@@ -70,20 +68,20 @@ impl From<BuilderTransactionError> for PayloadBuilderError {
7068 }
7169}
7270
73- pub trait BuilderTransactions : Debug {
71+ pub trait BuilderTransactions < ExtraCtx : Debug + Default = ( ) > : Debug {
7472 fn simulate_builder_txs < Extra : Debug + Default > (
7573 & self ,
7674 state_provider : impl StateProvider + Clone ,
7775 info : & mut ExecutionInfo < Extra > ,
78- ctx : & OpPayloadBuilderCtx ,
76+ ctx : & OpPayloadBuilderCtx < ExtraCtx > ,
7977 db : & mut State < impl Database > ,
8078 ) -> Result < Vec < BuilderTransactionCtx > , BuilderTransactionError > ;
8179
8280 fn add_builder_txs < Extra : Debug + Default > (
8381 & self ,
8482 state_provider : impl StateProvider + Clone ,
8583 info : & mut ExecutionInfo < Extra > ,
86- builder_ctx : & OpPayloadBuilderCtx ,
84+ builder_ctx : & OpPayloadBuilderCtx < ExtraCtx > ,
8785 db : & mut State < impl Database > ,
8886 ) -> Result < ( ) , BuilderTransactionError > {
8987 {
@@ -92,7 +90,7 @@ pub trait BuilderTransactions: Debug {
9290 . evm_with_env ( & mut * db, builder_ctx. evm_env . clone ( ) ) ;
9391
9492 let mut invalid: HashSet < Address > = HashSet :: new ( ) ;
95- // simulate builder txs on the top of block state
93+
9694 let builder_txs =
9795 self . simulate_builder_txs ( state_provider, info, builder_ctx, evm. db_mut ( ) ) ?;
9896 for builder_tx in builder_txs {
@@ -139,108 +137,33 @@ pub trait BuilderTransactions: Debug {
139137 Ok ( ( ) )
140138 }
141139 }
142- }
143-
144- // Scaffolding for how to construct the end of block builder transaction
145- // This will be the regular end of block transaction without the TEE key
146- #[ derive( Debug , Clone ) ]
147- pub struct StandardBuilderTx {
148- #[ allow( dead_code) ]
149- pub signer : Option < Signer > ,
150- }
151-
152- impl StandardBuilderTx {
153- pub fn new ( signer : Option < Signer > ) -> Self {
154- Self { signer }
155- }
156140
157- pub fn simulate_builder_tx (
141+ fn simulate_builder_txs_state < Extra : Debug + Default > (
158142 & self ,
159- ctx : & OpPayloadBuilderCtx ,
143+ state_provider : impl StateProvider + Clone ,
144+ builder_txs : Vec < & BuilderTransactionCtx > ,
145+ ctx : & OpPayloadBuilderCtx < ExtraCtx > ,
160146 db : & mut State < impl Database > ,
161- ) -> Result < Option < BuilderTransactionCtx > , BuilderTransactionError > {
162- match self . signer {
163- Some ( signer) => {
164- let message: Vec < u8 > = format ! ( "Block Number: {}" , ctx. block_number( ) ) . into_bytes ( ) ;
165- let gas_used = self . estimate_builder_tx_gas ( & message) ;
166- let signed_tx = self . signed_builder_tx ( ctx, db, signer, gas_used, message) ?;
167- let da_size = op_alloy_flz:: tx_estimated_size_fjord_bytes (
168- signed_tx. encoded_2718 ( ) . as_slice ( ) ,
169- ) ;
170- Ok ( Some ( BuilderTransactionCtx {
171- gas_used,
172- da_size,
173- signed_tx,
174- } ) )
175- }
176- None => Ok ( None ) ,
147+ ) -> Result < State < StateProviderDatabase < impl StateProvider > > , BuilderTransactionError > {
148+ let state = StateProviderDatabase :: new ( state_provider. clone ( ) ) ;
149+ let mut simulation_state = State :: builder ( )
150+ . with_database ( state)
151+ . with_bundle_prestate ( db. bundle_state . clone ( ) )
152+ . with_bundle_update ( )
153+ . build ( ) ;
154+ let mut evm = ctx
155+ . evm_config
156+ . evm_with_env ( & mut simulation_state, ctx. evm_env . clone ( ) ) ;
157+
158+ for builder_tx in builder_txs {
159+ let ResultAndState { state, .. } = evm
160+ . transact ( & builder_tx. signed_tx )
161+ . map_err ( |err| BuilderTransactionError :: EvmExecutionError ( Box :: new ( err) ) ) ?;
162+
163+ evm. db_mut ( ) . commit ( state) ;
164+ evm. db_mut ( ) . merge_transitions ( BundleRetention :: Reverts ) ;
177165 }
178- }
179166
180- fn estimate_builder_tx_gas ( & self , input : & [ u8 ] ) -> u64 {
181- // Count zero and non-zero bytes
182- let ( zero_bytes, nonzero_bytes) = input. iter ( ) . fold ( ( 0 , 0 ) , |( zeros, nonzeros) , & byte| {
183- if byte == 0 {
184- ( zeros + 1 , nonzeros)
185- } else {
186- ( zeros, nonzeros + 1 )
187- }
188- } ) ;
189-
190- // Calculate gas cost (4 gas per zero byte, 16 gas per non-zero byte)
191- let zero_cost = zero_bytes * 4 ;
192- let nonzero_cost = nonzero_bytes * 16 ;
193-
194- // Tx gas should be not less than floor gas https://eips.ethereum.org/EIPS/eip-7623
195- let tokens_in_calldata = zero_bytes + nonzero_bytes * 4 ;
196- let floor_gas = 21_000 + tokens_in_calldata * TOTAL_COST_FLOOR_PER_TOKEN ;
197-
198- std:: cmp:: max ( zero_cost + nonzero_cost + 21_000 , floor_gas)
199- }
200-
201- fn signed_builder_tx (
202- & self ,
203- ctx : & OpPayloadBuilderCtx ,
204- db : & mut State < impl Database > ,
205- signer : Signer ,
206- gas_used : u64 ,
207- message : Vec < u8 > ,
208- ) -> Result < Recovered < OpTransactionSigned > , BuilderTransactionError > {
209- let nonce = db
210- . load_cache_account ( signer. address )
211- . map ( |acc| acc. account_info ( ) . unwrap_or_default ( ) . nonce )
212- . map_err ( |_| BuilderTransactionError :: AccountLoadFailed ( signer. address ) ) ?;
213-
214- // Create the EIP-1559 transaction
215- let tx = OpTypedTransaction :: Eip1559 ( TxEip1559 {
216- chain_id : ctx. chain_id ( ) ,
217- nonce,
218- gas_limit : gas_used,
219- max_fee_per_gas : ctx. base_fee ( ) . into ( ) ,
220- max_priority_fee_per_gas : 0 ,
221- to : TxKind :: Call ( Address :: ZERO ) ,
222- // Include the message as part of the transaction data
223- input : message. into ( ) ,
224- ..Default :: default ( )
225- } ) ;
226- // Sign the transaction
227- let builder_tx = signer
228- . sign_tx ( tx)
229- . map_err ( BuilderTransactionError :: SigningError ) ?;
230-
231- Ok ( builder_tx)
232- }
233- }
234-
235- impl BuilderTransactions for StandardBuilderTx {
236- fn simulate_builder_txs < Extra : Debug + Default > (
237- & self ,
238- _state_provider : impl StateProvider + Clone ,
239- _info : & mut ExecutionInfo < Extra > ,
240- ctx : & OpPayloadBuilderCtx ,
241- db : & mut State < impl Database > ,
242- ) -> Result < Vec < BuilderTransactionCtx > , BuilderTransactionError > {
243- let builder_tx = self . simulate_builder_tx ( ctx, db) ?;
244- Ok ( builder_tx. into_iter ( ) . collect ( ) )
167+ Ok ( simulation_state)
245168 }
246169}
0 commit comments