Skip to content

Commit

Permalink
Feat: refactore EIP-4844 (#42)
Browse files Browse the repository at this point in the history
* Extend tests output and refactore tests runner

* Refactored CLI for recursive tests and extended information

* Set Shanghai spec as default

* Extend output for tests

* evm-tests: extend state statistics for failed results

* evm-tests: extended debug info

* Extend gas cost analyzer

* Extend tests and fixes for Cancun hard fork

* Fix: Apply CREATE storage reset - changed logic. GAS cost for MCOPY - improved calculation

* EIP-3607 implementation. DeepCall bug fixes. KZG-boilerplate

* KZG precompile

* EIP-3860 test flow fixes

* Fix Shanghai tests

* Removev debug info

* Separate check_exit_reason func

* Remove printing

* Added `as_deref`  to  check_create_exit_reason

* Fix: tests for EIP-3860 (#41)

undefined

* ForkSpec string error. Refactored usage as constantn USIZE_MAX

* Remove already fixed tests from skipping list

* Refactore blob-hash logic and tests

* Added KzgInput

* Gas price fix and investigations for blob-transactions

* Refactored skipped-match and clippy

* Refactored gas price and should-skip logic

* Fix tests for KZG-precompiles and SSTORE gas cost

* Added print-debug feature

* Fix randomness validation

* Refactore transactions validation

* Extend expected check for call-transaction and empty-create assertion

* Edit doc comments
  • Loading branch information
mrLSD authored Jun 5, 2024
1 parent 1133628 commit 38adacd
Show file tree
Hide file tree
Showing 22 changed files with 719 additions and 216 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ force-debug = [
"evm-gasometer/force-debug",
]
create-fixed = []
print-debug = ["evm-gasometer/print-debug"]

[workspace]
members = [
Expand Down
4 changes: 3 additions & 1 deletion benches/loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ fn run_loop_contract() {

let vicinity = MemoryVicinity {
gas_price: U256::zero(),
effective_gas_price: U256::zero(),
origin: H160::default(),
block_hashes: Vec::new(),
block_number: Default::default(),
Expand All @@ -20,7 +21,8 @@ fn run_loop_contract() {
chain_id: U256::one(),
block_base_fee_per_gas: U256::zero(),
block_randomness: None,
blob_base_fee: None,
blob_gas_price: None,
blob_hashes: Vec::new(),
};

let mut state = BTreeMap::new();
Expand Down
161 changes: 161 additions & 0 deletions core/src/opcode.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::fmt::{Display, Formatter};

/// Opcode enum. One-to-one corresponding to an `u8` value.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(
Expand Down Expand Up @@ -286,3 +288,162 @@ impl Opcode {
self.0 as usize
}
}

impl Display for Opcode {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let name = match *self {
Self::STOP => "STOP",
Self::ADD => "ADD",
Self::MUL => "MUL",
Self::SUB => "SUB",
Self::DIV => "DIV",
Self::SDIV => "SDIV",
Self::MOD => "MOD",
Self::SMOD => "SMOD",
Self::ADDMOD => "ADDMOD",
Self::MULMOD => "MULMOD",
Self::EXP => "EXP",
Self::SIGNEXTEND => "SIGNEXTEND",
Self::LT => "LT",
Self::GT => "GT",
Self::SLT => "SLT",
Self::SGT => "SGT",
Self::EQ => "EQ",
Self::ISZERO => "ISZERO",
Self::AND => "AND",
Self::OR => "OR",
Self::XOR => "XOR",
Self::NOT => "NOT",
Self::BYTE => "BYTE",
Self::CALLDATALOAD => "CALLDATALOAD",
Self::CALLDATASIZE => "CALLDATASIZE",
Self::CALLDATACOPY => "CALLDATACOPY",
Self::CODESIZE => "CODESIZE",
Self::CODECOPY => "CODECOPY",
Self::SHL => "SHL",
Self::SHR => "SHR",
Self::SAR => "SAR",
Self::POP => "POP",
Self::MLOAD => "MLOAD",
Self::MSTORE => "MSTORE",
Self::MSTORE8 => "MSTORE8",
Self::JUMP => "JUMP",
Self::JUMPI => "JUMPI",
Self::PC => "PC",
Self::MSIZE => "MSIZE",
Self::JUMPDEST => "JUMPDEST",
Self::TLOAD => "TLOAD",
Self::TSTORE => "TSTORE",
Self::MCOPY => "MCOPY",
Self::PUSH0 => "PUSH0",
Self::PUSH1 => "PUSH1",
Self::PUSH2 => "PUSH2",
Self::PUSH3 => "PUSH3",
Self::PUSH4 => "PUSH4",
Self::PUSH5 => "PUSH5",
Self::PUSH6 => "PUSH6",
Self::PUSH7 => "PUSH7",
Self::PUSH8 => "PUSH8",
Self::PUSH9 => "PUSH9",
Self::PUSH10 => "PUSH10",
Self::PUSH11 => "PUSH11",
Self::PUSH12 => "PUSH12",
Self::PUSH13 => "PUSH13",
Self::PUSH14 => "PUSH14",
Self::PUSH15 => "PUSH15",
Self::PUSH16 => "PUSH16",
Self::PUSH17 => "PUSH17",
Self::PUSH18 => "PUSH18",
Self::PUSH19 => "PUSH19",
Self::PUSH20 => "PUSH20",
Self::PUSH21 => "PUSH21",
Self::PUSH22 => "PUSH22",
Self::PUSH23 => "PUSH23",
Self::PUSH24 => "PUSH24",
Self::PUSH25 => "PUSH25",
Self::PUSH26 => "PUSH26",
Self::PUSH27 => "PUSH27",
Self::PUSH28 => "PUSH28",
Self::PUSH29 => "PUSH29",
Self::PUSH30 => "PUSH30",
Self::PUSH31 => "PUSH31",
Self::PUSH32 => "PUSH32",
Self::DUP1 => "DUP1",
Self::DUP2 => "DUP2",
Self::DUP3 => "DUP3",
Self::DUP4 => "DUP4",
Self::DUP5 => "DUP5",
Self::DUP6 => "DUP6",
Self::DUP7 => "DUP7",
Self::DUP8 => "DUP8",
Self::DUP9 => "DUP9",
Self::DUP10 => "DUP10",
Self::DUP11 => "DUP11",
Self::DUP12 => "DUP12",
Self::DUP13 => "DUP13",
Self::DUP14 => "DUP14",
Self::DUP15 => "DUP15",
Self::DUP16 => "DUP16",
Self::SWAP1 => "SWAP1",
Self::SWAP2 => "SWAP2",
Self::SWAP3 => "SWAP3",
Self::SWAP4 => "SWAP4",
Self::SWAP5 => "SWAP5",
Self::SWAP6 => "SWAP6",
Self::SWAP7 => "SWAP7",
Self::SWAP8 => "SWAP8",
Self::SWAP9 => "SWAP9",
Self::SWAP10 => "SWAP10",
Self::SWAP11 => "SWAP11",
Self::SWAP12 => "SWAP12",
Self::SWAP13 => "SWAP13",
Self::SWAP14 => "SWAP14",
Self::SWAP15 => "SWAP15",
Self::SWAP16 => "SWAP16",
Self::RETURN => "RETURN",
Self::REVERT => "REVERT",
Self::INVALID => "INVALID",
Self::EOFMAGIC => "EOFMAGIC",
Self::SHA3 => "SHA3",
Self::ADDRESS => "ADDRESS",
Self::BALANCE => "BALANCE",
Self::SELFBALANCE => "SELFBALANCE",
Self::BASEFEE => "BASEFEE",
Self::BLOBHASH => "BLOBHASH",
Self::BLOBBASEFEE => "BLOBBASEFEE",
Self::ORIGIN => "ORIGIN",
Self::CALLER => "CALLER",
Self::CALLVALUE => "CALLVALUE",
Self::GASPRICE => "GASPRICE",
Self::EXTCODESIZE => "EXTCODESIZE",
Self::EXTCODECOPY => "EXTCODECOPY",
Self::EXTCODEHASH => "EXTCODEHASH",
Self::RETURNDATASIZE => "RETURNDATASIZE",
Self::RETURNDATACOPY => "RETURNDATACOPY",
Self::BLOCKHASH => "BLOCKHASH",
Self::COINBASE => "COINBASE",
Self::TIMESTAMP => "TIMESTAMP",
Self::NUMBER => "NUMBER",
Self::DIFFICULTY => "DIFFICULTY",
Self::GASLIMIT => "GASLIMIT",
Self::SLOAD => "SLOAD",
Self::SSTORE => "SSTORE",
Self::GAS => "GAS",
Self::LOG0 => "LOG0",
Self::LOG1 => "LOG1",
Self::LOG2 => "LOG2",
Self::LOG3 => "LOG3",
Self::LOG4 => "LOG4",
Self::CREATE => "CREATE",
Self::CREATE2 => "CREATE2",
Self::CALL => "CALL",
Self::CALLCODE => "CALLCODE",
Self::DELEGATECALL => "DELEGATECALL",
Self::STATICCALL => "STATICCALL",
Self::SUICIDE => "SUICIDE",
Self::CHAINID => "CHAINID",
_ => "UNKNOWN",
};
write!(f, "{name} [{}]", self.0)
}
}
26 changes: 25 additions & 1 deletion core/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,38 @@ pub fn fake_exponential(factor: u64, numerator: u64, denominator: u64) -> u128 {
/// See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers)
/// (`get_blob_gasprice`).
#[inline]
pub fn calc_blob_gasprice(excess_blob_gas: u64) -> u128 {
pub fn calc_blob_gas_price(excess_blob_gas: u64) -> u128 {
fake_exponential(
MIN_BLOB_GASPRICE,
excess_blob_gas,
BLOB_GASPRICE_UPDATE_FRACTION,
)
}

/// Calculates the [EIP-4844] `data_fee` of the transaction.
///
/// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844
#[inline]
pub fn calc_max_data_fee(max_fee_per_blob_gas: U256, blob_hashes_len: usize) -> U256 {
max_fee_per_blob_gas.saturating_mul(U256::from(get_total_blob_gas(blob_hashes_len)))
}

/// Calculates the [EIP-4844] `data_fee` of the transaction.
///
/// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844
#[inline]
pub fn calc_data_fee(blob_gas_price: u128, blob_hashes_len: usize) -> U256 {
U256::from(blob_gas_price).saturating_mul(U256::from(get_total_blob_gas(blob_hashes_len)))
}

/// See [EIP-4844], [`calc_max_data_fee`]
///
/// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844
#[inline]
pub const fn get_total_blob_gas(blob_hashes_len: usize) -> u64 {
GAS_PER_BLOB * blob_hashes_len as u64
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Sign {
Plus,
Expand Down
5 changes: 1 addition & 4 deletions evm-tests/ethcore-builtin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1342,14 +1342,11 @@ impl Implementation for Kzg {
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> {
// Get and verify KZG input.
let kzg_input: kzg::KzgInput = input.try_into()?;
if output.is_empty() {
return Err("BlobInvalidOutputLength");
}
let kzg_settings = kzg::EnvKzgSettings::Default;
if !kzg_input.verify_kzg_proof(&kzg_settings.get()) {
return Err("BlobVerifyKzgProofFailed");
}
output.copy_from_slice(kzg::RETURN_VALUE.as_slice());
output.write(0, kzg::RETURN_VALUE.as_slice());
Ok(())
}
}
Expand Down
42 changes: 26 additions & 16 deletions evm-tests/ethjson/src/spec/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ use std::io::Read;
/// Fork spec definition
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize)]
pub enum ForkSpec {
/// Byzantium transition test-net
EIP158ToByzantiumAt5,
/// Homestead transition test-net
FrontierToHomesteadAt5,
/// Homestead transition test-net
HomesteadToDaoAt5,
/// EIP158/EIP161 transition test-net
HomesteadToEIP150At5,
/// ConstantinopleFix transition test-net
ByzantiumToConstantinopleFixAt5,
/// Istanbul transition test-net
ConstantinopleFixToIstanbulAt5,
/// EIP 150 Tangerine Whistle: Gas cost changes for IO-heavy operations (#2,463,000, 2016-10-18)
EIP150,
/// EIP 158/EIP 161 Spurious Dragon: State trie clearing (#2,675,000, 2016-11-22)
Expand All @@ -43,6 +55,7 @@ pub enum ForkSpec {
Istanbul,
/// Berlin (#12,244,000, 2021-04-15)
Berlin,

/// London (#12,965,000, 2021-08-05)
London,
/// Paris - The Merge (#15,537,394, 2022-09-15)
Expand All @@ -53,28 +66,25 @@ pub enum ForkSpec {
Shanghai,
/// Cancun (2024-03-13)
Cancun,

/// Byzantium transition test-net
EIP158ToByzantiumAt5,
/// Homestead transition test-net
FrontierToHomesteadAt5,
/// Homestead transition test-net
HomesteadToDaoAt5,
/// EIP158/EIP161 transition test-net
HomesteadToEIP150At5,
/// ConstantinopleFix transition test-net
ByzantiumToConstantinopleFixAt5,
/// Istanbul transition test-net
ConstantinopleFixToIstanbulAt5,
}

impl ForkSpec {
/// Returns true if the fork is at or after the merge.
pub const fn is_eth2(&self) -> bool {
// NOTE: Include new forks in this match arm.
matches!(
!matches!(
*self,
Self::Cancun | Self::London | Self::Merge | Self::Paris | Self::Shanghai
Self::EIP158ToByzantiumAt5
| Self::FrontierToHomesteadAt5
| Self::HomesteadToDaoAt5
| Self::HomesteadToEIP150At5
| Self::ByzantiumToConstantinopleFixAt5
| Self::ConstantinopleFixToIstanbulAt5
| Self::EIP150 | Self::EIP158
| Self::Frontier | Self::Homestead
| Self::Byzantium
| Self::Constantinople
| Self::ConstantinopleFix
| Self::Istanbul | Self::Berlin
)
}
}
Expand Down
37 changes: 4 additions & 33 deletions evm-tests/ethjson/src/test_helpers/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,11 @@ pub struct MultiTransaction {
/// Gas limit set.
pub gas_limit: Vec<Uint>,
/// Gas price.
#[serde(default)]
pub gas_price: Uint,
pub gas_price: Option<Uint>,
/// for details on `maxFeePerGas` see EIP-1559
#[serde(default)]
pub max_fee_per_gas: Uint,
pub max_fee_per_gas: Option<Uint>,
/// for details on `maxPriorityFeePerGas` see EIP-1559
#[serde(default)]
pub max_priority_fee_per_gas: Uint,
pub max_priority_fee_per_gas: Option<Uint>,
/// Nonce.
pub nonce: Uint,
/// Secret key.
Expand All @@ -79,30 +76,12 @@ pub struct MultiTransaction {

/// EIP-4844
#[serde(default)]
pub blob_versioned_hashes: Vec<H256>,
pub blob_versioned_hashes: Vec<U256>,
/// EIP-4844
pub max_fee_per_blob_gas: Option<Uint>,
}

impl MultiTransaction {
/// max_priority_fee_per_gas (see EIP-1559)
pub const fn max_priority_fee_per_gas(&self) -> U256 {
if self.max_priority_fee_per_gas.0.is_zero() {
self.gas_price.0
} else {
self.max_priority_fee_per_gas.0
}
}

/// max_fee_per_gas (see EIP-1559)
pub const fn max_fee_per_gas(&self) -> U256 {
if self.max_fee_per_gas.0.is_zero() {
self.gas_price.0
} else {
self.max_fee_per_gas.0
}
}

/// Build transaction with given indexes.
pub fn select(&self, indexes: &PostStateIndexes) -> Transaction {
let data_index = indexes.data as usize;
Expand All @@ -120,17 +99,9 @@ impl MultiTransaction {
Vec::new()
};

let gas_price = if self.gas_price.0.is_zero() {
self.max_fee_per_gas.0 + self.max_priority_fee_per_gas.0
} else {
self.gas_price.0
};

Transaction {
data: self.data[data_index].clone(),
gas_limit: self.gas_limit[indexes.gas as usize],
gas_price: Uint(gas_price),
nonce: self.nonce,
to: self.to.clone(),
value: self.value[indexes.value as usize],
r: Default::default(),
Expand Down
Loading

0 comments on commit 38adacd

Please sign in to comment.