Skip to content

Commit

Permalink
shanghai hardfork
Browse files Browse the repository at this point in the history
  • Loading branch information
zjb0807 committed Jan 24, 2024
1 parent 767a1f0 commit a214e67
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 23 deletions.
11 changes: 11 additions & 0 deletions ethjson/src/spec/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,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/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ keywords = ["no_std", "ethereum"]
edition = "2021"

[dependencies]
ethereum = "^0.14"
ethereum = "0.15.0"
scale-info = { version = "^2.9", features = ["derive"] }
codec = { package = "parity-scale-codec", version = "^3.0" }
serde = { version = "^1.0", features = ["derive"] }
Expand Down
67 changes: 52 additions & 15 deletions jsontests/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use crate::mock::{deposit, get_state, new_test_ext, setup_state, withdraw, Runtime, EVM};
use crate::utils::*;
use ethjson::spec::ForkSpec;
use evm_utility::evm::{backend::MemoryAccount, Config};
use evm_utility::evm::{backend::MemoryAccount, executor::stack::PrecompileFn, Config};
use libsecp256k1::SecretKey;
use module_evm::{
precompiles::{
Blake2F, Bn128Add, Bn128Mul, Bn128Pairing, ECRecover, Identity, IstanbulModexp, Modexp,
Precompile, Ripemd160, Sha256,
},
runner::state::{PrecompileFn, StackState},
runner::state::StackState,
StackExecutor, StackSubstateMetadata, SubstrateStackState, Vicinity,
};
use primitives::convert_decimals_to_evm;
Expand Down Expand Up @@ -77,6 +77,23 @@ 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(Vicinity {
gas_price,
origin: self.unwrap_caller(),
Expand All @@ -88,6 +105,7 @@ impl Test {
block_gas_limit: Some(self.0.env.gas_limit.into()),
// chain_id: U256::one(),
block_base_fee_per_gas: Some(block_base_fee_per_gas),
block_randomness,
})
}
}
Expand All @@ -99,24 +117,40 @@ impl JsonPrecompile {
match spec {
ForkSpec::Istanbul => {
let mut map = BTreeMap::<H160, PrecompileFn>::new();
map.insert(H160::from_low_u64_be(1), <ECRecover as Precompile>::execute);
map.insert(H160::from_low_u64_be(2), <Sha256 as Precompile>::execute);
map.insert(H160::from_low_u64_be(3), <Ripemd160 as Precompile>::execute);
map.insert(H160::from_low_u64_be(4), <Identity as Precompile>::execute);
map.insert(H160::from_low_u64_be(5), IstanbulModexp::execute);
map.insert(H160::from_low_u64_be(6), Bn128Add::execute);
map.insert(H160::from_low_u64_be(7), Bn128Mul::execute);
map.insert(H160::from_low_u64_be(8), Bn128Pairing::execute);
map.insert(H160::from_low_u64_be(9), Blake2F::execute);
map.insert(
H160::from_low_u64_be(1),
<ECRecover as Precompile>::execute_ext,
);
map.insert(
H160::from_low_u64_be(2),
<Sha256 as Precompile>::execute_ext,
);
map.insert(
H160::from_low_u64_be(3),
<Ripemd160 as Precompile>::execute_ext,
);
map.insert(
H160::from_low_u64_be(4),
<Identity as Precompile>::execute_ext,
);
map.insert(H160::from_low_u64_be(5), IstanbulModexp::execute_ext);
map.insert(H160::from_low_u64_be(6), Bn128Add::execute_ext);
map.insert(H160::from_low_u64_be(7), Bn128Mul::execute_ext);
map.insert(H160::from_low_u64_be(8), Bn128Pairing::execute_ext);
map.insert(H160::from_low_u64_be(9), Blake2F::execute_ext);
Some(map)
}
ForkSpec::Berlin => {
let mut map = Self::precompile(&ForkSpec::Istanbul).unwrap();
map.insert(H160::from_low_u64_be(5), Modexp::execute);
map.insert(H160::from_low_u64_be(5), Modexp::execute_ext);
Some(map)
}
// precompiles for London and Berlin are the same
ForkSpec::London => Self::precompile(&ForkSpec::Berlin),
// precompiles for Merge and Berlin are the same
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 @@ -173,8 +207,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:?}");
return;
}
};
Expand Down Expand Up @@ -291,8 +327,9 @@ fn test_run(name: &str, test: Test) {
}

let actual_fee = executor.fee(vicinity.gas_price).saturated_into::<i128>();
let miner_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();
Expand Down
24 changes: 22 additions & 2 deletions jsontests/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use evm_utility::evm::backend::MemoryAccount;
use evm_utility::evm::Config;
use module_evm::{StackExecutor, StackSubstateMetadata, SubstrateStackState, Vicinity};
use serde::Deserialize;
use sp_core::H160;
use sp_core::{H160, H256};
use std::collections::BTreeMap;
use std::rc::Rc;

Expand All @@ -17,13 +17,27 @@ impl Test {
}

pub fn unwrap_to_vicinity(&self) -> Vicinity {
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)
});

Vicinity {
gas_price: self.0.transaction.gas_price.into(),
origin: self.0.transaction.origin.into(),
block_gas_limit: Some(self.0.env.gas_limit.into()),
block_difficulty: Some(self.0.env.difficulty.into()),
block_coinbase: Some(self.0.env.author.into()),
block_base_fee_per_gas: Some(self.0.env.block_base_fee_per_gas.0),
block_randomness,
}
}

Expand Down Expand Up @@ -78,7 +92,13 @@ 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 = module_evm::evm::Runtime::new(code, data, context, &config);
let mut runtime = module_evm::evm::Runtime::new(
code,
data,
context,
config.stack_limit,
config.memory_limit,
);

let reason = executor.execute(&mut runtime);

Expand Down
8 changes: 5 additions & 3 deletions jsontests/tests/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ pub fn run(dir: &str) {
continue;
}

let file = File::open(path).expect("Open file failed");
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)
.unwrap_or_else(|e| {
panic!("Parsing test case {:?} failed: {:?}", path, e);
});

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

0 comments on commit a214e67

Please sign in to comment.