@@ -8,14 +8,15 @@ use std::sync::Arc;
88use alloy_consensus:: Header ;
99use alpen_reth_evm:: { accumulate_logs_bloom, evm:: AlpenEvmFactory , extract_withdrawal_intents} ;
1010use reth_chainspec:: ChainSpec ;
11+ use reth_consensus_common:: validation:: validate_body_against_header;
1112use reth_evm:: execute:: { BasicBlockExecutor , Executor } ;
1213use reth_evm_ethereum:: EthEvmConfig ;
1314use reth_primitives:: EthPrimitives ;
1415use revm:: database:: WrapDatabaseRef ;
1516use rsp_client_executor:: BlockValidator ;
1617use strata_acct_types:: { AccountId , BitcoinAmount , MsgPayload , SentMessage } ;
1718use strata_ee_acct_types:: {
18- BlockAssembler , EnvError , EnvResult , ExecBlockOutput , ExecHeader , ExecPayload ,
19+ BlockAssembler , EnvError , EnvResult , ExecBlockOutput , ExecPartialState , ExecPayload ,
1920 ExecutionEnvironment ,
2021} ;
2122use strata_ee_chain_types:: { BlockInputs , BlockOutputs } ;
@@ -93,7 +94,11 @@ impl ExecutionEnvironment for EvmExecutionEnvironment {
9394 )
9495 . map_err ( |_| EnvError :: InvalidBlock ) ?;
9596
96- // Step 2a: Validate deposits from BlockInputs against block withdrawals
97+ // Step 2b: Validate body against header (transactions_root, ommers_hash, withdrawals_root)
98+ validate_body_against_header ( block. body ( ) , block. header ( ) )
99+ . map_err ( |_| EnvError :: InvalidBlock ) ?;
100+
101+ // Step 2c: Validate deposits from BlockInputs against block withdrawals
97102 // The withdrawals header field is hijacked to represent deposits from the OL.
98103 // We need to ensure the authenticated deposits from BlockInputs match what's in the block.
99104 validate_deposits_against_block ( & block, inputs) ?;
@@ -129,14 +134,17 @@ impl ExecutionEnvironment for EvmExecutionEnvironment {
129134 extract_withdrawal_intents ( & transactions, & execution_output. receipts ) . collect ( ) ;
130135
131136 // Step 9: Convert execution outcome to HashedPostState
132- let block_number = exec_payload. header_intrinsics ( ) . number ;
133- let hashed_post_state = compute_hashed_post_state ( execution_output, block_number) ;
137+ let header_intrinsics = exec_payload. header_intrinsics ( ) ;
138+ let hashed_post_state =
139+ compute_hashed_post_state ( execution_output, header_intrinsics. number ) ;
134140
135- // Step 10: Compute state root
136- let state_root = pre_state. compute_state_root_with_changes ( & hashed_post_state) ;
141+ // Step 10: Get state root from header intrinsics (verification happens during merge)
142+ // This avoids an expensive state clone that would be needed to compute the root here.
143+ let intrinsics_state_root = header_intrinsics. state_root ;
137144
138- // Step 11: Create WriteBatch with computed metadata
139- let write_batch = EvmWriteBatch :: new ( hashed_post_state, state_root. into ( ) , logs_bloom) ;
145+ // Step 11: Create WriteBatch with intrinsics state root (to be verified during merge)
146+ let write_batch =
147+ EvmWriteBatch :: new ( hashed_post_state, intrinsics_state_root. into ( ) , logs_bloom) ;
140148
141149 // Step 12: Create BlockOutputs with withdrawal intent messages
142150 let mut outputs = BlockOutputs :: new_empty ( ) ;
@@ -147,22 +155,16 @@ impl ExecutionEnvironment for EvmExecutionEnvironment {
147155
148156 fn verify_outputs_against_header (
149157 & self ,
150- header : & <Self :: Block as strata_ee_acct_types:: ExecBlock >:: Header ,
151- outputs : & ExecBlockOutput < Self > ,
158+ _header : & <Self :: Block as strata_ee_acct_types:: ExecBlock >:: Header ,
159+ _outputs : & ExecBlockOutput < Self > ,
152160 ) -> EnvResult < ( ) > {
153- // Verify that the outputs match what's committed in the header
154-
155- // Check state root matches
156- let computed_state_root = outputs. write_batch ( ) . state_root ( ) ;
157- let header_state_root = header. get_state_root ( ) ;
158-
159- if computed_state_root != header_state_root {
160- //FIXME: is it correct enum to represent this error?
161- return Err ( EnvError :: MismatchedCurStateData ) ;
162- }
163-
164- // Note: transactions_root and receipts_root are verified during execution
165- // by validate_block_post_execution() in execute_block_body()
161+ // State root verification is deferred to merge_write_into_state to avoid
162+ // an expensive state clone. The actual verification happens when the state
163+ // is mutated and we can compute the root directly without cloning.
164+ //
165+ // Note: The following are verified during execution in execute_block_body():
166+ // - transactions_root, ommers_hash, withdrawals_root: by validate_body_against_header()
167+ // - receipts_root, logs_bloom, gas_used: by validate_block_post_execution()
166168
167169 Ok ( ( ) )
168170 }
@@ -174,6 +176,16 @@ impl ExecutionEnvironment for EvmExecutionEnvironment {
174176 ) -> EnvResult < ( ) > {
175177 // Merge the HashedPostState into the EthereumState
176178 state. merge_write_batch ( wb) ;
179+
180+ // Verify state root AFTER merge (avoids expensive clone that would be needed
181+ // to compute the root before mutation)
182+ let computed_state_root = state. compute_state_root ( ) ?;
183+ let intrinsics_state_root = wb. intrinsics_state_root ( ) ;
184+
185+ if computed_state_root != intrinsics_state_root {
186+ return Err ( EnvError :: InvalidBlock ) ;
187+ }
188+
177189 Ok ( ( ) )
178190 }
179191}
@@ -185,7 +197,7 @@ impl BlockAssembler for EvmExecutionEnvironment {
185197 output : & ExecBlockOutput < Self > ,
186198 ) -> EnvResult < <Self :: Block as strata_ee_acct_types:: ExecBlock >:: Header > {
187199 let intrinsics = exec_payload. header_intrinsics ( ) ;
188- let state_root = output. write_batch ( ) . state_root ( ) ;
200+ let state_root = output. write_batch ( ) . intrinsics_state_root ( ) ;
189201 let logs_bloom = output. write_batch ( ) . logs_bloom ( ) ;
190202
191203 let header = Header {
0 commit comments