Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Update Ethereum Execution Tests to 13.1 #96

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
11 changes: 11 additions & 0 deletions lib/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,17 @@ impl ChainSpec {
pub fn chain_id(&self) -> ChainId {
self.chain_id
}
/// Validates a [SpecId].
pub fn validate_spec_id(&self, spec_id: SpecId) -> Result<()> {
let (min_spec_id, _) = self.hard_forks.first_key_value().unwrap();
if spec_id < *min_spec_id {
bail!("expected >= {:?}, got {:?}", min_spec_id, spec_id);
}
if spec_id > self.max_spec_id {
bail!("expected <= {:?}, got {:?}", self.max_spec_id, spec_id);
}
Ok(())
}
/// Returns the [SpecId] for a given block number and timestamp or an error if not
/// supported.
pub fn active_fork(&self, block_number: BlockNumber, timestamp: &U256) -> Result<SpecId> {
Expand Down
3 changes: 0 additions & 3 deletions lib/src/mem_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,6 @@ impl DatabaseCommit for MemDb {
}
};

// it is not possible to delete a deleted account
debug_assert!(db_account.state != AccountState::Deleted);

// clear the account and mark it as deleted
db_account.storage.clear();
db_account.state = AccountState::Deleted;
Expand Down
12 changes: 6 additions & 6 deletions testing/ef-tests/src/ethtests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ use std::{fs::File, io::BufReader, path::PathBuf};

use revm::primitives::SpecId;
use serde_json::Value;
use zeth_lib::consts::{ChainSpec, ETH_MAINNET_EIP1559_CONSTANTS};
use zeth_lib::consts::{ChainSpec, ETH_MAINNET_CHAIN_SPEC, ETH_MAINNET_EIP1559_CONSTANTS};
use zeth_primitives::block::Header;

use crate::TestJson;

pub struct EthTestCase {
pub name: String,
pub json: TestJson,
pub genesis: Header,
pub chain_spec: ChainSpec,
Expand All @@ -36,13 +37,11 @@ pub fn read_eth_test(path: PathBuf) -> Vec<EthTestCase> {
.unwrap()
.into_iter()
.filter_map(|(name, test)| {
println!("test '{}'", name);
let json: TestJson = serde_json::from_value(test.take()).unwrap();

let spec: SpecId = json.network.as_str().into();
// skip tests with an unsupported network version
if spec < SpecId::MERGE || spec > SpecId::SHANGHAI {
println!("skipping ({})", json.network);
let spec: SpecId = json.network.replace("Paris", "Merge").as_str().into();
if let Err(err) = ETH_MAINNET_CHAIN_SPEC.validate_spec_id(spec) {
println!("skipping '{}': {}", name, err);
return None;
}
let chain_spec = ChainSpec::new_single(1, spec, ETH_MAINNET_EIP1559_CONSTANTS);
Expand All @@ -51,6 +50,7 @@ pub fn read_eth_test(path: PathBuf) -> Vec<EthTestCase> {
assert_eq!(genesis.hash(), json.genesis.hash);

Some(EthTestCase {
name: name.clone(),
json,
genesis,
chain_spec,
Expand Down
62 changes: 42 additions & 20 deletions testing/ef-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use zeth_primitives::{
},
trie::{self, MptNode, MptNodeData, StateAccount},
withdrawal::Withdrawal,
Address, Bloom, Bytes, StorageKey, B256, B64, U256, U64,
Address, Bloom, Bytes, Parity, StorageKey, B256, B64, U256, U64, U8,
};

use crate::ethers::TestProvider;
Expand Down Expand Up @@ -79,8 +79,7 @@ pub struct TestBlock {
#[serde(default)]
pub transactions: Vec<TestTransaction>,
#[serde(default)]
pub uncle_headers: Vec<TestHeader>,
pub withdrawals: Option<Vec<Withdrawal>>,
pub withdrawals: Vec<TestWithdrawal>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
Expand Down Expand Up @@ -176,16 +175,19 @@ impl From<TestHeader> for Header {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TestTransaction {
pub data: Bytes,
pub access_list: Option<TestAccessList>,
pub chain_id: Option<U64>,
pub data: Bytes,
pub gas_limit: U256,
pub gas_price: Option<U256>,
pub max_fee_per_gas: Option<U256>,
pub max_priority_fee_per_gas: Option<U256>,
pub value: U256,
pub nonce: U64,
#[serde_as(as = "NoneAsEmptyString")]
pub to: Option<Address>,
pub nonce: U64,
#[serde(rename = "type")]
pub type_id: Option<U8>,
pub value: U256,
pub v: U64,
pub r: U256,
pub s: U256,
Expand All @@ -198,9 +200,9 @@ impl From<TestTransaction> for EthereumTransaction {
r: tx.r,
s: tx.s,
};
let essence = if tx.access_list.is_none() {
EthereumTxEssence::Legacy(TxEssenceLegacy {
chain_id: None,
let essence = match tx.type_id.map(|v| u8::try_from(v).unwrap()) {
None | Some(0) => EthereumTxEssence::Legacy(TxEssenceLegacy {
chain_id: Parity::try_from(tx.v).unwrap().chain_id(), // derive chain ID from sig
nonce: tx.nonce.try_into().unwrap(),
gas_price: tx.gas_price.unwrap(),
gas_limit: tx.gas_limit,
Expand All @@ -210,10 +212,9 @@ impl From<TestTransaction> for EthereumTransaction {
},
value: tx.value,
data: tx.data,
})
} else if tx.max_fee_per_gas.is_none() {
EthereumTxEssence::Eip2930(TxEssenceEip2930 {
chain_id: 1,
}),
Some(1) => EthereumTxEssence::Eip2930(TxEssenceEip2930 {
chain_id: tx.chain_id.unwrap().try_into().unwrap(),
nonce: tx.nonce.try_into().unwrap(),
gas_price: tx.gas_price.unwrap(),
gas_limit: tx.gas_limit,
Expand All @@ -224,10 +225,9 @@ impl From<TestTransaction> for EthereumTransaction {
value: tx.value,
data: tx.data,
access_list: tx.access_list.unwrap().into(),
})
} else {
EthereumTxEssence::Eip1559(TxEssenceEip1559 {
chain_id: 1,
}),
Some(2) => EthereumTxEssence::Eip1559(TxEssenceEip1559 {
chain_id: tx.chain_id.unwrap().try_into().unwrap(),
nonce: tx.nonce.try_into().unwrap(),
max_priority_fee_per_gas: tx.max_priority_fee_per_gas.unwrap(),
max_fee_per_gas: tx.max_fee_per_gas.unwrap(),
Expand All @@ -239,7 +239,8 @@ impl From<TestTransaction> for EthereumTransaction {
value: tx.value,
data: tx.data,
access_list: tx.access_list.unwrap().into(),
})
}),
v @ _ => panic!("invalid transaction type: {}", v.unwrap()),
};
EthereumTransaction { essence, signature }
}
Expand Down Expand Up @@ -270,6 +271,26 @@ impl From<TestAccessList> for AccessList {
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TestWithdrawal {
pub address: Address,
pub amount: U64,
pub index: U64,
pub validator_index: U64,
}

impl From<TestWithdrawal> for Withdrawal {
fn from(w: TestWithdrawal) -> Self {
Withdrawal {
address: w.address,
amount: w.amount.try_into().unwrap(),
index: w.index.try_into().unwrap(),
validator_index: w.validator_index.try_into().unwrap(),
}
}
}

/// Computes the Merkle proof for the given key in the trie.
pub fn mpt_proof(root: &MptNode, key: impl AsRef<[u8]>) -> Result<Vec<Vec<u8>>, anyhow::Error> {
let mut path = proof_internal(root, &trie::to_nibs(key.as_ref()))?;
Expand Down Expand Up @@ -314,7 +335,7 @@ pub fn create_input(
parent_state: TestState,
header: Header,
transactions: Vec<TestTransaction>,
withdrawals: Vec<Withdrawal>,
withdrawals: Vec<TestWithdrawal>,
state: TestState,
) -> BlockBuildInput<EthereumTxEssence> {
// create the provider DB
Expand All @@ -327,10 +348,11 @@ pub fn create_input(
parent_header.number,
);

let transactions: Vec<EthereumTransaction> = transactions
let transactions: Vec<_> = transactions
.into_iter()
.map(EthereumTransaction::from)
.collect();
let withdrawals: Vec<_> = withdrawals.into_iter().map(Withdrawal::from).collect();
let input = BlockBuildInput {
state_input: StateInput {
beneficiary: header.beneficiary,
Expand Down
2 changes: 1 addition & 1 deletion testing/ef-tests/testdata
14 changes: 10 additions & 4 deletions testing/ef-tests/tests/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,27 @@ fn evm(
.try_init();

for EthTestCase {
name,
mut json,
genesis,
chain_spec,
} in read_eth_test(path)
{
// only one block supported for now
assert_eq!(json.blocks.len(), 1);
if json.blocks.len() > 1 {
println!("skipping '{}': more than one block", name);
continue;
}
let block = json.blocks.pop().unwrap();

// skip failing tests for now
if let Some(message) = block.expect_exception {
println!("skipping ({})", message);
break;
println!("skipping '{}': {}", name, message);
continue;
}

println!("running '{}'", name);

let block_header = block.block_header.unwrap();
let expected_header: Header = block_header.clone().into();
assert_eq!(&expected_header.hash(), &block_header.hash);
Expand All @@ -69,7 +75,7 @@ fn evm(
json.pre,
expected_header.clone(),
block.transactions,
block.withdrawals.unwrap_or_default(),
block.withdrawals,
post_state,
);
let input_state_input_hash = input.state_input.hash();
Expand Down
5 changes: 4 additions & 1 deletion testing/ef-tests/tests/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ fn executor(
.try_init();

for EthTestCase {
name,
json,
genesis,
chain_spec,
Expand All @@ -57,6 +58,8 @@ fn executor(
break;
}

println!("running: {}", name);

let block_header = block.block_header.unwrap();
let expected_header: Header = block_header.clone().into();
assert_eq!(&expected_header.hash(), &block_header.hash);
Expand All @@ -67,7 +70,7 @@ fn executor(
json.pre,
expected_header.clone(),
block.transactions,
block.withdrawals.unwrap_or_default(),
block.withdrawals,
json.post.unwrap(),
);

Expand Down
Loading