Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions crates/evm-ee/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use alloy_consensus::Header;
use alpen_reth_evm::{accumulate_logs_bloom, evm::AlpenEvmFactory, extract_withdrawal_intents};
use reth_chainspec::ChainSpec;
use reth_consensus_common::validation::validate_body_against_header;
use reth_evm::execute::{BasicBlockExecutor, Executor};
use reth_evm::execute::{BasicBlockExecutor, BlockExecutionOutput, Executor};
use reth_evm_ethereum::EthEvmConfig;
use reth_primitives::EthPrimitives;
use revm::database::WrapDatabaseRef;
use reth_primitives::{EthPrimitives, Receipt as EthereumReceipt};
use revm::{database::WrapDatabaseRef, state::Bytecode};
use rsp_client_executor::BlockValidator;
use strata_acct_types::{AccountId, BitcoinAmount, MsgPayload};
use strata_codec::encode_to_vec;
Expand Down Expand Up @@ -148,6 +148,7 @@ impl ExecutionEnvironment for EvmExecutionEnvironment {
let transactions = block.into_transactions();
let withdrawal_intents =
extract_withdrawal_intents(&transactions, &execution_output.receipts).collect();
let created_bytecodes = collect_created_bytecodes(&execution_output);

// Step 9: Convert execution outcome to HashedPostState
let header_intrinsics = exec_payload.header_intrinsics();
Expand All @@ -168,6 +169,7 @@ impl ExecutionEnvironment for EvmExecutionEnvironment {
hashed_post_state,
intrinsics_state_root.0.into(),
logs_bloom,
created_bytecodes,
);

// Step 12: Create ExecOutputs with withdrawal intent messages
Expand Down Expand Up @@ -201,6 +203,7 @@ impl ExecutionEnvironment for EvmExecutionEnvironment {
) -> EnvResult<()> {
// Merge the HashedPostState into the EthereumState
state.merge_write_batch(wb);
state.add_bytecodes(wb.created_bytecodes().cloned().collect());

// Verify state root AFTER merge (avoids expensive clone that would be needed
// to compute the root before mutation)
Expand All @@ -224,6 +227,12 @@ impl ExecutionEnvironment for EvmExecutionEnvironment {
}
}

fn collect_created_bytecodes(
execution_output: &BlockExecutionOutput<EthereumReceipt>,
) -> Vec<Bytecode> {
execution_output.state.contracts.values().cloned().collect()
}

impl BlockAssembler for EvmExecutionEnvironment {
fn complete_header(
&self,
Expand Down
7 changes: 6 additions & 1 deletion crates/evm-ee/src/types/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,12 @@ fn test_evm_write_batch_codec_roundtrip() {
let intrinsics_state_root = Hash::from([42u8; 32]);
let logs_bloom = Bloom::from([0xAB; 256]);

let write_batch = EvmWriteBatch::new(hashed_post_state, intrinsics_state_root, logs_bloom);
let write_batch = EvmWriteBatch::new(
hashed_post_state,
intrinsics_state_root,
logs_bloom,
Vec::new(),
);

// Encode
let encoded = encode_to_vec(&write_batch).expect("encode failed");
Expand Down
48 changes: 46 additions & 2 deletions crates/evm-ee/src/types/write_batch.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
//! EVM write batch implementation.

use std::collections::BTreeMap;

use reth_trie::HashedPostState;
use revm_primitives::alloy_primitives::Bloom;
use revm::state::Bytecode;
use revm_primitives::{B256, alloy_primitives::Bloom};
use strata_acct_types::Hash;
use strata_codec::{Codec, CodecError};

use crate::codec_shims::{decode_hashed_post_state, encode_hashed_post_state};
use crate::codec_shims::{
decode_bytes_with_length, decode_hashed_post_state, encode_bytes_with_length,
encode_hashed_post_state,
};

/// Write batch for EVM execution containing state changes.
///
Expand All @@ -28,6 +34,8 @@ pub struct EvmWriteBatch {
intrinsics_state_root: Hash,
/// The accumulated logs bloom from all receipts
logs_bloom: Bloom,
/// Bytecodes created while executing this block, keyed by code hash.
created_bytecodes: BTreeMap<B256, Bytecode>,
}

impl EvmWriteBatch {
Expand All @@ -36,11 +44,19 @@ impl EvmWriteBatch {
hashed_post_state: HashedPostState,
intrinsics_state_root: Hash,
logs_bloom: Bloom,
created_bytecodes: Vec<Bytecode>,
) -> Self {
let created_bytecodes = created_bytecodes
.into_iter()
.filter(|bytecode| !bytecode.original_bytes().is_empty())
.map(|bytecode| (bytecode.hash_slow(), bytecode))
.collect();

Self {
hashed_post_state,
intrinsics_state_root,
logs_bloom,
created_bytecodes,
}
}

Expand All @@ -62,6 +78,11 @@ impl EvmWriteBatch {
self.logs_bloom
}

/// Gets the bytecodes created while executing this block.
pub fn created_bytecodes(&self) -> impl Iterator<Item = &Bytecode> {
self.created_bytecodes.values()
}

/// Consumes self and returns the underlying HashedPostState.
pub fn into_hashed_post_state(self) -> HashedPostState {
self.hashed_post_state
Expand All @@ -79,6 +100,13 @@ impl Codec for EvmWriteBatch {
// Encode logs_bloom (256 bytes)
enc.write_buf(self.logs_bloom.as_slice())?;

// Encode bytecodes in deterministic hash order.
(self.created_bytecodes.len() as u32).encode(enc)?;
for (hash, bytecode) in &self.created_bytecodes {
encode_bytes_with_length(&bytecode.original_bytes(), enc)?;
enc.write_buf(hash.as_slice())?;
}

Ok(())
}

Expand All @@ -96,10 +124,26 @@ impl Codec for EvmWriteBatch {
dec.read_buf(&mut logs_bloom_bytes)?;
let logs_bloom = Bloom::from(logs_bloom_bytes);

// Decode bytecodes with their pre-computed hashes.
let bytecode_count = u32::decode(dec)? as usize;
let mut created_bytecodes = BTreeMap::new();
for _ in 0..bytecode_count {
let bytes = decode_bytes_with_length(dec)?;
let bytecode = Bytecode::new_raw_checked(bytes.into())
.map_err(|_| CodecError::MalformedField("Bytecode decode failed"))?;

let mut hash_bytes = [0u8; 32];
dec.read_buf(&mut hash_bytes)?;
let hash = B256::from(hash_bytes);

created_bytecodes.insert(hash, bytecode);
}

Ok(Self {
hashed_post_state,
intrinsics_state_root,
logs_bloom,
created_bytecodes,
})
}
}
Loading