Skip to content
This repository was archived by the owner on Nov 20, 2023. It is now read-only.
Merged
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
18 changes: 17 additions & 1 deletion ethjson/src/spec/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,13 @@ pub enum ForkSpec {
Istanbul,
/// Berlin (#12,244,000, 2021-04-15)
Berlin,
/// London (To be announced)
/// London (#12,965,000, 2021-08-05)
London,
/// Paris - The Merge (#15,537,394, 2022-09-15)
Merge,
/// Shanghai (#17,034,870, 2023-04-12)
Shanghai,

/// Byzantium transition test-net
EIP158ToByzantiumAt5,
/// Homestead transition test-net
Expand All @@ -58,6 +63,17 @@ pub enum ForkSpec {
ConstantinopleFixToIstanbulAt5,
}

impl ForkSpec {
/// Returns true if the fork is at or after the merge.
pub fn is_eth2(&self) -> bool {
// NOTE: Include new forks in this match arm.
matches!(
*self,
ForkSpec::London | ForkSpec::Merge | ForkSpec::Shanghai
)
}
}

/// Spec deserialization.
#[derive(Debug, PartialEq, Deserialize)]
#[serde(deny_unknown_fields)]
Expand Down
10 changes: 8 additions & 2 deletions ethjson/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ pub struct Env {
#[serde(rename = "currentBaseFee")]
#[serde(default)]
pub block_base_fee_per_gas: Uint,
/// Pre-seeded random value for testing
#[serde(rename = "currentRandom")]
#[serde(default)]
pub random: Option<Uint>,
}

#[cfg(test)]
Expand All @@ -145,7 +149,8 @@ mod tests {
"currentDifficulty" : "0x0100",
"currentGasLimit" : "0x0f4240",
"currentNumber" : "0x00",
"currentTimestamp" : "0x01"
"currentTimestamp" : "0x01",
"currentRandom" : "0x01"
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
Expand Down Expand Up @@ -192,7 +197,8 @@ mod tests {
gas_limit: Uint(0x0f4240.into()),
number: Uint(0.into()),
timestamp: Uint(1.into()),
block_base_fee_per_gas: Uint(0.into())
block_base_fee_per_gas: Uint(0.into()),
random: Some(Uint(1.into())),
}
);
assert_eq!(
Expand Down
2 changes: 1 addition & 1 deletion jsontests/res/ethtests
53 changes: 41 additions & 12 deletions jsontests/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ impl Test {
}

pub fn unwrap_caller(&self) -> H160 {
let hash: H256 = self.0.transaction.secret.clone().unwrap().into();
let hash: H256 = self.0.transaction.secret.unwrap().into();
let mut secret_key = [0; 32];
secret_key.copy_from_slice(&hash.as_bytes()[..]);
secret_key.copy_from_slice(hash.as_bytes());
let secret = SecretKey::parse(&secret_key);
let public = libsecp256k1::PublicKey::from_secret_key(&secret.unwrap());
let mut res = [0u8; 64];
res.copy_from_slice(&public.serialize()[1..65]);

H160::from(H256::from_slice(Keccak256::digest(&res).as_slice()))
H160::from(H256::from_slice(Keccak256::digest(res).as_slice()))
}

pub fn unwrap_to_vicinity(&self, spec: &ForkSpec) -> Option<MemoryVicinity> {
Expand Down Expand Up @@ -70,17 +70,36 @@ impl Test {
return None;
}

let block_randomness = if spec.is_eth2() {
self.0.env.random.map(|r| {
// Convert between U256 and H256. U256 is in little-endian but since H256 is just
// a string-like byte array, it's big endian (MSB is the first element of the array).
//
// Byte order here is important because this opcode has the same value as DIFFICULTY
// (0x44), and so for older forks of Ethereum, the threshold value of 2^64 is used to
// distinguish between the two: if it's below, the value corresponds to the DIFFICULTY
// opcode, otherwise to the PREVRANDAO opcode.
let mut buf = [0u8; 32];
r.0.to_big_endian(&mut buf);
H256(buf)
})
} else {
None
};


Some(MemoryVicinity {
gas_price,
origin: self.unwrap_caller(),
block_hashes: Vec::new(),
block_number: self.0.env.number.clone().into(),
block_coinbase: self.0.env.author.clone().into(),
block_timestamp: self.0.env.timestamp.clone().into(),
block_difficulty: self.0.env.difficulty.clone().into(),
block_gas_limit: self.0.env.gas_limit.clone().into(),
block_number: self.0.env.number.into(),
block_coinbase: self.0.env.author.into(),
block_timestamp: self.0.env.timestamp.into(),
block_difficulty: self.0.env.difficulty.into(),
block_gas_limit: self.0.env.gas_limit.into(),
chain_id: U256::one(),
block_base_fee_per_gas,
block_randomness,
})
}
}
Expand Down Expand Up @@ -139,6 +158,10 @@ impl JsonPrecompile {
}
// precompiles for London and Berlin are the same
ForkSpec::London => Self::precompile(&ForkSpec::Berlin),
// precompiles for Merge and Berlin are the same
Comment thread
vimpunk marked this conversation as resolved.
ForkSpec::Merge => Self::precompile(&ForkSpec::Berlin),
// precompiles for Shanghai and Berlin are the same
ForkSpec::Shanghai => Self::precompile(&ForkSpec::Berlin),
_ => None,
}
}
Expand Down Expand Up @@ -211,8 +234,10 @@ fn test_run(name: &str, test: Test) {
ethjson::spec::ForkSpec::Istanbul => (Config::istanbul(), true),
ethjson::spec::ForkSpec::Berlin => (Config::berlin(), true),
ethjson::spec::ForkSpec::London => (Config::london(), true),
ethjson::spec::ForkSpec::Merge => (Config::merge(), true),
ethjson::spec::ForkSpec::Shanghai => (Config::shanghai(), true),
spec => {
println!("Skip spec {:?}", spec);
println!("Skip spec {spec:?}");
continue;
}
};
Expand Down Expand Up @@ -288,8 +313,9 @@ fn test_run(name: &str, test: Test) {
}

let actual_fee = executor.fee(vicinity.gas_price);
let mniner_reward = if let ForkSpec::London = spec {
// see EIP-1559
// Forks after London burn miner rewards and thus have different gas fee
// calculation (see EIP-1559)
let miner_reward = if spec.is_eth2() {
let max_priority_fee_per_gas = test.0.transaction.max_priority_fee_per_gas();
let max_fee_per_gas = test.0.transaction.max_fee_per_gas();
let base_fee_per_gas = vicinity.block_base_fee_per_gas;
Expand All @@ -299,11 +325,14 @@ fn test_run(name: &str, test: Test) {
} else {
actual_fee
};

executor
.state_mut()
.deposit(vicinity.block_coinbase, mniner_reward);
.deposit(vicinity.block_coinbase, miner_reward);
executor.state_mut().deposit(caller, total_fee - actual_fee);

let (values, logs) = executor.into_state().deconstruct();

backend.apply(values, logs, delete_empty);
}

Expand Down
6 changes: 3 additions & 3 deletions jsontests/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ pub fn assert_valid_hash(h: &H256, b: &BTreeMap<H160, MemoryAccount>) {
.collect::<Vec<_>>();

let root = ethereum::util::sec_trie_root(tree);
let expect = h.clone().into();
let expect = h;

if root != expect {
if root != *expect {
panic!(
"Hash not equal; calculated: {:?}, expect: {:?}\nState: {:#x?}",
root, expect, b
Expand All @@ -157,7 +157,7 @@ pub fn assert_valid_hash(h: &H256, b: &BTreeMap<H160, MemoryAccount>) {
pub fn flush() {
use std::io::{self, Write};

io::stdout().flush().ok().expect("Could not flush stdout");
io::stdout().flush().expect("Could not flush stdout");
}

pub mod transaction {
Expand Down
19 changes: 17 additions & 2 deletions jsontests/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::utils::*;
use evm::backend::{ApplyBackend, MemoryAccount, MemoryBackend, MemoryVicinity};
use evm::executor::stack::{MemoryStackState, StackExecutor, StackSubstateMetadata};
use evm::Config;
use primitive_types::{H160, U256};
use primitive_types::{H160, H256, U256};
use serde::Deserialize;
use std::collections::BTreeMap;
use std::rc::Rc;
Expand All @@ -16,6 +16,19 @@ impl Test {
}

pub fn unwrap_to_vicinity(&self) -> MemoryVicinity {
let block_randomness = self.0.env.random.map(|r| {
// Convert between U256 and H256. U256 is in little-endian but since H256 is just
// a string-like byte array, it's big endian (MSB is the first element of the array).
//
// Byte order here is important because this opcode has the same value as DIFFICULTY
// (0x44), and so for older forks of Ethereum, the threshold value of 2^64 is used to
// distinguish between the two: if it's below, the value corresponds to the DIFFICULTY
// opcode, otherwise to the PREVRANDAO opcode.
let mut buf = [0u8; 32];
r.0.to_big_endian(&mut buf);
H256(buf)
});

MemoryVicinity {
gas_price: self.0.transaction.gas_price.clone().into(),
origin: self.0.transaction.origin.clone().into(),
Expand All @@ -27,6 +40,7 @@ impl Test {
block_gas_limit: self.0.env.gas_limit.clone().into(),
chain_id: U256::zero(),
block_base_fee_per_gas: self.0.transaction.gas_price.clone().into(),
block_randomness,
}
}

Expand Down Expand Up @@ -75,7 +89,8 @@ pub fn test(name: &str, test: Test) {
let code = test.unwrap_to_code();
let data = test.unwrap_to_data();
let context = test.unwrap_to_context();
let mut runtime = evm::Runtime::new(code, data, context, config.stack_limit, config.memory_limit);
let mut runtime =
evm::Runtime::new(code, data, context, config.stack_limit, config.memory_limit);

let reason = executor.execute(&mut runtime);
let gas = executor.gas();
Expand Down
6 changes: 3 additions & 3 deletions jsontests/tests/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub fn run(dir: &str) {
for entry in fs::read_dir(dest).unwrap() {
let entry = entry.unwrap();
if let Some(s) = entry.file_name().to_str() {
if s.starts_with(".") {
if s.starts_with('.') {
continue;
}
}
Expand All @@ -23,8 +23,8 @@ pub fn run(dir: &str) {
let file = File::open(path).expect("Open file failed");

let reader = BufReader::new(file);
let coll = serde_json::from_reader::<_, HashMap<String, statetests::Test>>(reader)
.expect("Parse test cases failed");
let coll: HashMap<String, statetests::Test> =
serde_json::from_reader(reader).expect("Parse test cases failed");

for (name, test) in coll {
statetests::test(&name, test);
Expand Down