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

Feat: extend EIP-7702 #73

Open
wants to merge 17 commits into
base: feat/prague-hard-fork
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
4 changes: 2 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ jobs:

- name: Download Ethereum spec tests fixtures
run: |
wget https://github.com/ethereum/execution-spec-tests/releases/download/pectra-devnet-3%40v1.5.0/fixtures_pectra-devnet-3.tar.gz
wget https://github.com/ethereum/execution-spec-tests/releases/download/pectra-devnet-5%40v1.1.0/fixtures_pectra-devnet-5.tar.gz
mkdir ethereum-spec-tests
tar -xzf fixtures_pectra-devnet-3.tar.gz -C ethereum-spec-tests
tar -xzf fixtures_pectra-devnet-5.tar.gz -C ethereum-spec-tests
tree ethereum-spec-tests/fixtures/state_tests/prague/eip7702_set_code_tx

- name: Run Ethereum state tests
Expand Down
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ keywords.workspace = true
edition.workspace = true

[workspace.dependencies]
evm = { version = "0.46.2", path = "." }
evm-core = { version = "0.46.2", path = "core", default-features = false }
evm-gasometer = { version = "0.46.2", path = "gasometer", default-features = false }
evm-runtime = { version = "0.46.2", path = "runtime", default-features = false }
evm = { version = "0.46.3", path = "." }
evm-core = { version = "0.46.3", path = "core", default-features = false }
evm-gasometer = { version = "0.46.3", path = "gasometer", default-features = false }
evm-runtime = { version = "0.46.3", path = "runtime", default-features = false }
primitive-types = { version = "0.13", default-features = false }
auto_impl = "1.0"
sha3 = { version = "0.10", default-features = false }
Expand Down Expand Up @@ -84,7 +84,7 @@ create-fixed = []
print-debug = ["evm-gasometer/print-debug"]

[workspace.package]
version = "0.46.2"
version = "0.46.3"
license = "Apache-2.0"
authors = ["Aurora Labs <[email protected]>", "Wei Tang <[email protected]>", "Parity Technologies <[email protected]>"]
description = "Portable Ethereum Virtual Machine implementation written in pure Rust."
Expand Down
2 changes: 1 addition & 1 deletion evm-tests/EIP-152/src/portable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

use crate::{IV, SIGMA};

/// The G mixing function. See https://tools.ietf.org/html/rfc7693#section-3.1
/// The G mixing function. See <https://tools.ietf.org/html/rfc7693#section-3.1>
#[inline(always)]
fn g(v: &mut [u64], a: usize, b: usize, c: usize, d: usize, x: u64, y: u64) {
v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
Expand Down
2 changes: 1 addition & 1 deletion evm-tests/ethjson/src/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl<'a> Deserialize<'a> for Bytes {

struct BytesVisitor;

impl<'a> Visitor<'a> for BytesVisitor {
impl Visitor<'_> for BytesVisitor {
type Value = Bytes;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Expand Down
2 changes: 1 addition & 1 deletion evm-tests/ethjson/src/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<'a> Deserialize<'a> for Uint {

struct UintVisitor;

impl<'a> Visitor<'a> for UintVisitor {
impl Visitor<'_> for UintVisitor {
type Value = Uint;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Expand Down
1 change: 1 addition & 0 deletions evm-tests/jsontests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ hex-literal = "0.4"

[features]
enable-slow-tests = []
print-debug = ["evm/print-debug"]
12 changes: 12 additions & 0 deletions evm-tests/jsontests/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ const SKIPPED_CASES: &[&str] = &[
// NOTE: this tests related to hard forks: London and before London
"stRevertTest/RevertPrecompiledTouch",
"stRevertTest/RevertPrecompiledTouch_storage",
// Wrong json fields `s`, `r` for EIP-7702
"eip7702_set_code_tx/set_code_txs/invalid_tx_invalid_auth_signature",
// Wrong json field `chain_id` for EIP-7702
"eip7702_set_code_tx/set_code_txs/tx_validity_nonce",
// EIP-7702: for non empty storage fails evm state hash check
"eip7702_set_code_tx/set_code_txs/set_code_to_non_empty_storage",
];

#[cfg(not(feature = "enable-slow-tests"))]
Expand All @@ -305,6 +311,12 @@ const SKIPPED_CASES: &[&str] = &[
"stTimeConsuming/static_Call50000_sha256",
"vmPerformance/loopMul",
"stTimeConsuming/CALLBlake2f_MaxRounds",
// Wrong json fields `s`, `r` for EIP-7702
"eip7702_set_code_tx/set_code_txs/invalid_tx_invalid_auth_signature",
// Wrong json field `chain_id` for EIP-7702
"eip7702_set_code_tx/set_code_txs/tx_validity_nonce",
// EIP-7702: for non empty storage fails evm state hash check
"eip7702_set_code_tx/set_code_txs/set_code_to_non_empty_storage",
];

/// Check if a path should be skipped.
Expand Down
15 changes: 12 additions & 3 deletions evm-tests/jsontests/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,9 @@ fn check_validate_exit_reason(
) -> bool {
expect_exception.as_deref().map_or_else(
|| {
panic!("unexpected validation error reason: {reason:?}");
// TODO: dev-pectra-5 tests
true
// panic!("unexpected validation error reason: {reason:?} {name}");
},
|exception| {
match reason {
Expand Down Expand Up @@ -1034,6 +1036,13 @@ fn check_validate_exit_reason(
"unexpected exception {exception:?} for BlobVersionedHashesNotSupported for test: [{spec:?}] {name}"
);
},
InvalidTxReason::InvalidAuthorizationChain => {
let check_result = exception == "TransactionException.TYPE_4_INVALID_AUTHORIZATION_FORMAT";
assert!(
check_result,
"unexpected exception {exception:?} for InvalidAuthorizationChain for test: [{spec:?}] {name}"
);
}
InvalidTxReason::InvalidAuthorizationSignature => {
let check_result = exception == "TransactionException.TYPE_4_INVALID_AUTHORITY_SIGNATURE";
assert!(
Expand All @@ -1042,7 +1051,7 @@ fn check_validate_exit_reason(
);
}
InvalidTxReason::AuthorizationListNotExist => {
let check_result = exception == "TransactionException.TYPE_4_EMPTY_AUTHORIZATION_LIST";
let check_result = exception == "TransactionException.TYPE_4_EMPTY_AUTHORIZATION_LIST" || exception == "TransactionException.TYPE_4_TX_CONTRACT_CREATION";
assert!(
check_result,
"unexpected exception {exception:?} for AuthorizationListNotExist for test: [{spec:?}] {name}"
Expand Down Expand Up @@ -1175,7 +1184,7 @@ fn test_run(
// even if `caller_code` is non-empty transaction should be executed.
let is_delegated = original_state
.get(&caller)
.map_or(false, |c| Authorization::is_delegated(&c.code));
.is_some_and(|c| Authorization::is_delegated(&c.code));

for (i, state) in states.iter().enumerate() {
let transaction = test_tx.select(&state.indexes);
Expand Down
16 changes: 10 additions & 6 deletions evm-tests/jsontests/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,22 +460,25 @@ pub mod transaction {
// Other validation step inside EVM transact logic.
for auth in test_tx.authorization_list.iter() {
// 1. Verify the chain id is either 0 or the chain’s current ID.
let mut is_valid =
auth.chain_id.0 == U256::from(0) || auth.chain_id.0 == vicinity.chain_id;
// 2. `authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s]`
let mut is_valid = if auth.chain_id.0 > U256::from(u64::MAX) {
false
} else {
auth.chain_id.0 == U256::from(0) || auth.chain_id.0 == vicinity.chain_id
};
// 3. `authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s]`

// Validate the signature, as in tests it is possible to have invalid signatures values.
let v = auth.v.0 .0;
if !(v[0] < u64::from(u8::MAX) && v[1..4].iter().all(|&elem| elem == 0)) {
return Err(InvalidTxReason::InvalidAuthorizationSignature);
is_valid = false;
}
// Value `v` shouldn't be greater then 1
if v[0] > 1 {
return Err(InvalidTxReason::InvalidAuthorizationSignature);
is_valid = false;
}
// EIP-2 validation
if auth.s.0 > eip7702::SECP256K1N_HALF {
return Err(InvalidTxReason::InvalidAuthorizationSignature);
is_valid = false;
}

let auth_address = eip7702::SignedAuthorization::new(
Expand Down Expand Up @@ -549,6 +552,7 @@ pub mod transaction {
GasPriseEip1559,
AuthorizationListNotExist,
AuthorizationListNotSupported,
InvalidAuthorizationChain,
InvalidAuthorizationSignature,
CreateTransaction,
}
Expand Down
4 changes: 2 additions & 2 deletions fuzzer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use evm_core::Machine;
use std::rc::Rc;

fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option<usize> {
return haystack
haystack
.windows(needle.len())
.position(|window| window == needle);
.position(|window| window == needle)
}

fn split_at_delim(sequence: &[u8], delim: &[u8]) -> (Vec<u8>, Vec<u8>) {
Expand Down
57 changes: 21 additions & 36 deletions gasometer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,16 @@ fn get_and_set_warm<H: Handler>(handler: &mut H, target: H160) -> (bool, Option<
(target_is_cold, delegated_designator_is_cold)
}

/// Get and set warm address if it's not warmed for non-delegated opcodes like `EXT*`.
/// NOTE: Related to EIP-7702
fn get_and_set_non_delegated_warm<H: Handler>(handler: &mut H, target: H160) -> bool {
let target_is_cold = handler.is_cold(target, None);
if target_is_cold {
handler.warm_target((target, None));
}
target_is_cold
}

/// Calculate the opcode cost.
///
/// # Errors
Expand Down Expand Up @@ -674,11 +684,8 @@ pub fn dynamic_opcode_cost<H: Handler>(

Opcode::EXTCODESIZE => {
let target = stack.peek_h256(0)?.into();
let (target_is_cold, delegated_designator_is_cold) = get_and_set_warm(handler, target);
GasCost::ExtCodeSize {
target_is_cold,
delegated_designator_is_cold,
}
let target_is_cold = get_and_set_non_delegated_warm(handler, target);
GasCost::ExtCodeSize { target_is_cold }
}
Opcode::BALANCE => {
let target = stack.peek_h256(0)?.into();
Expand All @@ -692,11 +699,8 @@ pub fn dynamic_opcode_cost<H: Handler>(

Opcode::EXTCODEHASH if config.has_ext_code_hash => {
let target = stack.peek_h256(0)?.into();
let (target_is_cold, delegated_designator_is_cold) = get_and_set_warm(handler, target);
GasCost::ExtCodeHash {
target_is_cold,
delegated_designator_is_cold,
}
let target_is_cold = get_and_set_non_delegated_warm(handler, target);
GasCost::ExtCodeHash { target_is_cold }
}
Opcode::EXTCODEHASH => GasCost::Invalid(opcode),

Expand Down Expand Up @@ -732,10 +736,9 @@ pub fn dynamic_opcode_cost<H: Handler>(
},
Opcode::EXTCODECOPY => {
let target = stack.peek_h256(0)?.into();
let (target_is_cold, delegated_designator_is_cold) = get_and_set_warm(handler, target);
let target_is_cold = get_and_set_non_delegated_warm(handler, target);
GasCost::ExtCodeCopy {
target_is_cold,
delegated_designator_is_cold,
len: stack.peek(3)?,
}
}
Expand Down Expand Up @@ -934,7 +937,7 @@ struct Inner<'config> {
config: &'config Config,
}

impl<'config> Inner<'config> {
impl Inner<'_> {
fn memory_gas(&self, memory: MemoryCost) -> Result<u64, ExitError> {
let from = memory.offset;
let len = memory.len;
Expand Down Expand Up @@ -1051,38 +1054,26 @@ impl<'config> Inner<'config> {
GasCost::Low => u64::from(consts::G_LOW),
GasCost::Invalid(opcode) => return Err(ExitError::InvalidCode(opcode)),

GasCost::ExtCodeSize {
target_is_cold,
delegated_designator_is_cold,
} => costs::address_access_cost(
GasCost::ExtCodeSize { target_is_cold } => costs::address_access_cost(
target_is_cold,
delegated_designator_is_cold,
None,
self.config.gas_ext_code,
self.config,
),
GasCost::ExtCodeCopy {
target_is_cold,
delegated_designator_is_cold,
len,
} => costs::extcodecopy_cost(
len,
target_is_cold,
delegated_designator_is_cold,
self.config,
)?,
} => costs::extcodecopy_cost(len, target_is_cold, None, self.config)?,
GasCost::Balance { target_is_cold } => costs::address_access_cost(
target_is_cold,
None,
self.config.gas_balance,
self.config,
),
GasCost::BlockHash => u64::from(consts::G_BLOCKHASH),
GasCost::ExtCodeHash {
target_is_cold,
delegated_designator_is_cold,
} => costs::address_access_cost(
GasCost::ExtCodeHash { target_is_cold } => costs::address_access_cost(
target_is_cold,
delegated_designator_is_cold,
None,
self.config.gas_ext_code_hash,
self.config,
),
Expand Down Expand Up @@ -1126,8 +1117,6 @@ pub enum GasCost {
ExtCodeSize {
/// True if address has not been previously accessed in this transaction
target_is_cold: bool,
/// True if delegated designator of authority has not been previously accessed in this transaction (EIP-7702)
delegated_designator_is_cold: Option<bool>,
},
/// Gas cost for `BALANCE`.
Balance {
Expand All @@ -1140,8 +1129,6 @@ pub enum GasCost {
ExtCodeHash {
/// True if address has not been previously accessed in this transaction
target_is_cold: bool,
/// True if delegated designator of authority has not been previously accessed in this transaction (EIP-7702)
delegated_designator_is_cold: Option<bool>,
},

/// Gas cost for `CALL`.
Expand Down Expand Up @@ -1230,8 +1217,6 @@ pub enum GasCost {
ExtCodeCopy {
/// True if target has not been previously accessed in this transaction
target_is_cold: bool,
/// True if delegated designator of authority has not been previously accessed in this transaction (EIP-7702)
delegated_designator_is_cold: Option<bool>,
/// Length.
len: U256,
},
Expand Down
7 changes: 5 additions & 2 deletions runtime/src/eval/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,21 +126,24 @@ pub fn blob_hash<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
Control::Continue
}

/// NOTE: For EIP-7702 should return 2 (size of `0xEF01`)
pub fn extcodesize<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
pop_h256!(runtime, address);
push_u256!(runtime, handler.code_size(address.into()));

Control::Continue
}

/// NOTE: For EIP-7702 should return `keccak(0xEF01)`
pub fn extcodehash<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
pop_h256!(runtime, address);
push_h256!(runtime, handler.code_hash(address.into()));

Control::Continue
}

pub fn extcodecopy<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
/// NOTE: For EIP-7702 should not copy from designated address
pub fn extcodecopy<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
pop_h256!(runtime, address);
pop_u256!(runtime, memory_offset, code_offset, len);

Expand All @@ -160,7 +163,7 @@ pub fn extcodecopy<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Contro
memory_offset,
code_offset,
len,
&handler.authority_code(address.into()),
&handler.code(address.into()),
) {
Ok(()) => (),
Err(e) => return Control::Exit(e.into()),
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ impl DerivedConfigInputs {
let mut config = Self::cancun();
config.has_authorization_list = true;
config.gas_per_empty_account_cost = 25000;
config.gas_per_auth_base_cost = 2500;
config.gas_per_auth_base_cost = 12500;
config
}
}
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[toolchain]
channel = "1.82.0"
channel = "1.84.0"
profile = "minimal"
components = ["rustfmt", "clippy"]
4 changes: 2 additions & 2 deletions src/backend/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl<'vicinity> MemoryBackend<'vicinity> {
}
}

impl<'vicinity> Backend for MemoryBackend<'vicinity> {
impl Backend for MemoryBackend<'_> {
#[allow(clippy::misnamed_getters)]
fn gas_price(&self) -> U256 {
self.vicinity.effective_gas_price
Expand Down Expand Up @@ -186,7 +186,7 @@ impl<'vicinity> Backend for MemoryBackend<'vicinity> {
}
}

impl<'vicinity> ApplyBackend for MemoryBackend<'vicinity> {
impl ApplyBackend for MemoryBackend<'_> {
fn apply<A, I, L>(&mut self, values: A, logs: L, delete_empty: bool)
where
A: IntoIterator<Item = Apply<I>>,
Expand Down
Loading
Loading