Skip to content

Commit

Permalink
Merge branch 'main' into rf/eip7251
Browse files Browse the repository at this point in the history
  • Loading branch information
refcell authored Jan 28, 2025
2 parents aa73cc3 + 46d4a1e commit 2103d4e
Show file tree
Hide file tree
Showing 99 changed files with 205 additions and 9,978 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ reqwest = "0.12.12"
async-trait = "0.1.85"
linked_list_allocator = "0.10.5"
rstest = "0.24.0"
tempfile = "3.15.0"

# General
sha2 = { version = "0.10.8", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions crates/executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ alloy-rpc-client.workspace = true
alloy-transport.workspace = true
alloy-transport-http.workspace = true
kona-host.workspace = true
tempfile.workspace = true
17 changes: 14 additions & 3 deletions crates/executor/src/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
syscalls::{
ensure_create2_deployer_canyon, pre_block_beacon_root_contract_call,
pre_block_block_hash_contract_call, pre_block_consolidation_requests_contract_call,
pre_block_withdrawals_request_contract_call,
},
ExecutorError, ExecutorResult, TrieDBProvider,
};
Expand Down Expand Up @@ -149,6 +150,15 @@ where
&payload,
)?;

// Apply the pre-block EIP-7002 contract call.
pre_block_withdrawals_request_contract_call(
&mut state,
self.config,
&initialized_cfg,
&initialized_block_env,
&payload,
)?;

// Apply the pre-block EIP-7251 contract call.
pre_block_consolidation_requests_contract_call(
&mut state,
Expand Down Expand Up @@ -526,16 +536,17 @@ mod test {

#[rstest]
#[case::small_block(22884230)]
#[case::small_block_2(22880574)]
#[case::small_block_3(22887258)]
#[case::small_block_2(22884231)]
#[case::small_block_3(22880574)]
#[case::small_block_4(22887258)]
#[case::medium_block(22886464)]
#[case::medium_block_2(22886311)]
#[case::medium_block_3(22880944)]
#[tokio::test]
async fn test_statelessly_execute_block(#[case] block_number: u64) {
let fixture_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("testdata")
.join(format!("block-{block_number}"));
.join(format!("block-{block_number}.tar.gz"));

run_test_fixture(fixture_dir).await;
}
Expand Down
154 changes: 154 additions & 0 deletions crates/executor/src/syscalls/eip7002.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//! Contains the logic for executing the pre-block withdrawals request call.
use crate::{
db::TrieDB,
errors::{ExecutorError, ExecutorResult},
TrieDBProvider,
};
use alloc::{boxed::Box, vec::Vec};
use alloy_primitives::{Address, Bytes, U256};
use kona_mpt::TrieHinter;
use maili_genesis::RollupConfig;
use op_alloy_rpc_types_engine::OpPayloadAttributes;
use revm::{
db::State,
primitives::{
BlockEnv, CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg, OptimismFields, TransactTo, TxEnv,
},
DatabaseCommit, Evm,
};

/// Execute the EIP-7002 pre-block withdrawals request contract call.
pub(crate) fn pre_block_withdrawals_request_contract_call<F, H>(
db: &mut State<&mut TrieDB<F, H>>,
config: &RollupConfig,
initialized_cfg: &CfgEnvWithHandlerCfg,
initialized_block_env: &BlockEnv,
payload: &OpPayloadAttributes,
) -> ExecutorResult<()>
where
F: TrieDBProvider,
H: TrieHinter,
{
// apply pre-block EIP-4788 contract call
let mut evm_pre_block = Evm::builder()
.with_db(db)
.with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env(
initialized_cfg.clone(),
initialized_block_env.clone(),
Default::default(),
))
.build();

// initialize a block from the env, because the pre block call needs the block itself
apply_withdrawals_request_contract_call(
config,
payload.payload_attributes.timestamp,
&mut evm_pre_block,
)
}

/// Apply the EIP-7002 pre-block withdrawals request contract call to a given EVM instance.
fn apply_withdrawals_request_contract_call<F, H>(
config: &RollupConfig,
timestamp: u64,
evm: &mut Evm<'_, (), &mut State<&mut TrieDB<F, H>>>,
) -> ExecutorResult<()>
where
F: TrieDBProvider,
H: TrieHinter,
{
if !config.is_isthmus_active(timestamp) {
return Ok(());
}

// Get the previous environment
let previous_env = Box::new(evm.context.evm.env().clone());

// modify env for pre block call
fill_tx_env_with_withdrawals_request_contract_call(&mut evm.context.evm.env);

let mut state = match evm.transact() {
Ok(res) => res.state,
Err(e) => {
evm.context.evm.env = previous_env;
return Err(ExecutorError::ExecutionError(e));
}
};

state.remove(&alloy_eips::eip7002::SYSTEM_ADDRESS);
state.remove(&evm.block().coinbase);

evm.context.evm.db.commit(state);

// re-set the previous env
evm.context.evm.env = previous_env;

Ok(())
}

/// Fill transaction environment with the EIP-7002 system contract message data.
///
/// This requirements for the beacon root contract call are defined by
/// [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002).
fn fill_tx_env_with_withdrawals_request_contract_call(env: &mut Env) {
fill_tx_env_with_system_contract_call(
env,
alloy_eips::eip7002::SYSTEM_ADDRESS,
alloy_eips::eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS,
Bytes::new(),
);
}

/// Fill transaction environment with the system caller and the system contract address and message
/// data.
///
/// This is a system operation and therefore:
/// * the call must execute to completion
/// * the call does not count against the block’s gas limit
/// * the call does not follow the EIP-1559 burn semantics - no value should be transferred as part
/// of the call
/// * if no code exists at the provided address, the call will fail silently
fn fill_tx_env_with_system_contract_call(
env: &mut Env,
caller: Address,
contract: Address,
data: Bytes,
) {
env.tx = TxEnv {
caller,
transact_to: TransactTo::Call(contract),
// Explicitly set nonce to None so revm does not do any nonce checks
nonce: None,
gas_limit: 30_000_000,
value: U256::ZERO,
data,
// Setting the gas price to zero enforces that no value is transferred as part of the call,
// and that the call will not count against the block's gas limit
gas_price: U256::ZERO,
// The chain ID check is not relevant here and is disabled if set to None
chain_id: None,
// Setting the gas priority fee to None ensures the effective gas price is derived from the
// `gas_price` field, which we need to be zero
gas_priority_fee: None,
access_list: Vec::new(),
authorization_list: None,
// blob fields can be None for this tx
blob_hashes: Vec::new(),
max_fee_per_blob_gas: None,
optimism: OptimismFields {
source_hash: None,
mint: None,
is_system_transaction: Some(false),
// The L1 fee is not charged for the EIP-4788 transaction, submit zero bytes for the
// enveloped tx size.
enveloped_tx: Some(Bytes::default()),
},
};

// ensure the block gas limit is >= the tx
env.block.gas_limit = U256::from(env.tx.gas_limit);

// disable the base fee check for this call by setting the base fee to zero
env.block.basefee = U256::ZERO;
}
5 changes: 4 additions & 1 deletion crates/executor/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
mod eip2935;
pub(crate) use eip2935::pre_block_block_hash_contract_call;

mod eip7002;
pub(crate) use eip7002::pre_block_withdrawals_request_contract_call;

mod eip7251;
pub(crate) use eip7251::pre_block_consolidation_requests_contract_call;

mod eip4788;
pub(crate) use eip4788::pre_block_beacon_root_contract_call;

mod canyon;
pub(crate) use canyon::ensure_create2_deployer_canyon;
pub(crate) use canyon::ensure_create2_deployer_canyon;
34 changes: 30 additions & 4 deletions crates/executor/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use maili_genesis::RollupConfig;
use maili_registry::ROLLUP_CONFIGS;
use op_alloy_rpc_types_engine::OpPayloadAttributes;
use serde::{Deserialize, Serialize};
use std::{path::PathBuf, sync::Arc};
use std::{env::temp_dir, path::PathBuf, sync::Arc};
use tokio::{fs, runtime::Handle, sync::Mutex};

#[derive(Debug, thiserror::Error)]
Expand Down Expand Up @@ -154,7 +154,21 @@ impl ExecutorTestFixtureCreator {
produced_header, executing_header.inner,
"Produced header does not match the expected header"
);
fs::write(fixture_path, serde_json::to_vec(&fixture).unwrap()).await.unwrap();
fs::write(fixture_path.as_path(), serde_json::to_vec(&fixture).unwrap()).await.unwrap();

// Tar the fixture.
let data_dir = fixture_path.parent().unwrap();
tokio::process::Command::new("tar")
.arg("-czf")
.arg(data_dir.with_extension("tar.gz").file_name().unwrap())
.arg(data_dir.file_name().unwrap())
.current_dir(data_dir.parent().unwrap())
.output()
.await
.expect("Failed to tar fixture");

// Remove the leftover directory.
fs::remove_dir_all(data_dir).await.expect("Failed to remove temporary directory");
}
}

Expand Down Expand Up @@ -301,10 +315,22 @@ impl TrieDBProvider for DiskTrieNodeProvider {
/// Executes a [ExecutorTestFixture] stored at the passed `fixture_path` and asserts that the
/// produced block hash matches the expected block hash.
pub(crate) async fn run_test_fixture(fixture_path: PathBuf) {
let kv_store = DiskKeyValueStore::new(fixture_path.join("kv"));
// First, untar the fixture.
let mut fixture_dir = tempfile::tempdir().expect("Failed to create temporary directory");
let untar = tokio::process::Command::new("tar")
.arg("-xvf")
.arg(fixture_path.as_path())
.arg("-C")
.arg(fixture_dir.path())
.arg("--strip-components=1")
.output()
.await
.expect("Failed to untar fixture");

let kv_store = DiskKeyValueStore::new(fixture_dir.path().join("kv"));
let provider = DiskTrieNodeProvider::new(kv_store);
let fixture: ExecutorTestFixture =
serde_json::from_slice(&fs::read(fixture_path.join("fixture.json")).await.unwrap())
serde_json::from_slice(&fs::read(fixture_dir.path().join("fixture.json")).await.unwrap())
.expect("Failed to deserialize fixture");

let mut executor =
Expand Down
Binary file added crates/executor/testdata/block-22880574.tar.gz
Binary file not shown.
1 change: 0 additions & 1 deletion crates/executor/testdata/block-22880574/fixture.json

This file was deleted.

Binary file not shown.
Empty file.
1 change: 0 additions & 1 deletion crates/executor/testdata/block-22880574/kv/CURRENT

This file was deleted.

1 change: 0 additions & 1 deletion crates/executor/testdata/block-22880574/kv/IDENTITY

This file was deleted.

Empty file.
Empty file.
Loading

0 comments on commit 2103d4e

Please sign in to comment.