Skip to content
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
23 changes: 17 additions & 6 deletions crates/context/src/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pub use context_interface::Cfg;

use context_interface::cfg::GasParams;
use primitives::{eip170, eip3860, eip7825, hardfork::SpecId};
use primitives::{eip170, eip3860, eip7825, eip7954, hardfork::SpecId};

/// EVM configuration
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand Down Expand Up @@ -33,7 +33,7 @@ pub struct CfgEnv<SPEC = SpecId> {

/// Contract code size limit override.
///
/// If None, the limit will be determined by the SpecId (EIP-170 or EIP-7907) at runtime.
/// If None, the limit will be determined by the SpecId (EIP-170 or EIP-7954) at runtime.
/// If Some, this specific limit will be used regardless of SpecId.
///
/// Useful to increase this because of tests.
Expand All @@ -42,7 +42,7 @@ pub struct CfgEnv<SPEC = SpecId> {
///
/// If None, the limit will check if `limit_contract_code_size` is set.
/// If it is set, it will double it for a limit.
/// If it is not set, the limit will be determined by the SpecId (EIP-170 or EIP-7907) at runtime.
/// If it is not set, the limit will be determined by the SpecId (EIP-170 or EIP-7954) at runtime.
///
/// Useful to increase this because of tests.
pub limit_contract_initcode_size: Option<usize>,
Expand Down Expand Up @@ -408,8 +408,13 @@ impl<SPEC: Into<SpecId> + Clone> Cfg for CfgEnv<SPEC> {
}

fn max_code_size(&self) -> usize {
self.limit_contract_code_size
.unwrap_or(eip170::MAX_CODE_SIZE)
self.limit_contract_code_size.unwrap_or(
if self.spec.clone().into().is_enabled_in(SpecId::AMSTERDAM) {
eip7954::MAX_CODE_SIZE
} else {
eip170::MAX_CODE_SIZE
},
)
}

fn max_initcode_size(&self) -> usize {
Expand All @@ -418,7 +423,13 @@ impl<SPEC: Into<SpecId> + Clone> Cfg for CfgEnv<SPEC> {
self.limit_contract_code_size
.map(|size| size.saturating_mul(2))
})
.unwrap_or(eip3860::MAX_INITCODE_SIZE)
.unwrap_or(
if self.spec.clone().into().is_enabled_in(SpecId::AMSTERDAM) {
eip7954::MAX_INITCODE_SIZE
} else {
eip3860::MAX_INITCODE_SIZE
},
)
}

fn is_eip3541_disabled(&self) -> bool {
Expand Down
30 changes: 14 additions & 16 deletions crates/context/src/journal/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use context_interface::{
use core::mem;
use database_interface::Database;
use primitives::{
eip7708::{ETH_TRANSFER_LOG_ADDRESS, ETH_TRANSFER_LOG_TOPIC, SELFDESTRUCT_LOG_TOPIC},
eip7708::{BURN_LOG_TOPIC, ETH_TRANSFER_LOG_ADDRESS, ETH_TRANSFER_LOG_TOPIC},
hardfork::SpecId::{self, *},
hash_map::Entry,
hints_util::unlikely,
Expand Down Expand Up @@ -123,7 +123,7 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
#[inline]
pub fn take_logs(&mut self) -> Vec<Log> {
// EIP-7708: Emit logs for self-destructed accounts with remaining balance
self.eip7708_emit_selfdestruct_remaining_balance_logs();
self.eip7708_emit_burn_remaining_balance_logs();
mem::take(&mut self.logs)
}

Expand Down Expand Up @@ -237,7 +237,7 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
///
/// This should be called before `take_logs()` at the end of transaction execution.
/// It checks all accounts that were self-destructed in this transaction and emits
/// a `SelfBalanceLog` for any that still have a non-zero balance.
/// a `Burn` log for any that still have a non-zero balance.
///
/// This can happen when an account receives ETH after being self-destructed
/// in the same transaction.
Expand All @@ -246,7 +246,7 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
///
/// [EIP-7708](https://eips.ethereum.org/EIPS/eip-7708)
#[inline]
pub fn eip7708_emit_selfdestruct_remaining_balance_logs(&mut self) {
pub fn eip7708_emit_burn_remaining_balance_logs(&mut self) {
if !self.cfg.spec.is_enabled_in(AMSTERDAM)
|| self.cfg.eip7708_disabled
|| self.cfg.eip7708_delayed_burn_disabled
Expand All @@ -271,7 +271,7 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {

// Emit logs in sorted order
for (address, balance) in addresses_with_balance {
self.eip7708_selfdestruct_to_self_log(address, balance);
self.eip7708_burn_log(address, balance);
}
}

Expand Down Expand Up @@ -657,8 +657,8 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
// Transfer log for balance transferred to different address
self.eip7708_transfer_log(address, target, balance);
} else {
// Selfdestruct to self log
self.eip7708_selfdestruct_to_self_log(address, balance);
// Burn log for selfdestruct to self
self.eip7708_burn_log(address, balance);
}
Some(ENTRY::account_destroyed(
address,
Expand Down Expand Up @@ -1089,28 +1089,26 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
});
}

/// Creates and pushes an EIP-7708 selfdestruct-to-self log.
/// Creates and pushes an EIP-7708 burn log.
///
/// This emits a LOG2 when a contract self-destructs to itself.
/// This emits a LOG2 when a contract self-destructs to itself or when a
/// self-destructed account still has remaining balance at end of transaction.
/// Only emitted if EIP-7708 is enabled (Amsterdam and later) and balance is non-zero.
///
/// [EIP-7708](https://eips.ethereum.org/EIPS/eip-7708)
#[inline]
pub fn eip7708_selfdestruct_to_self_log(&mut self, address: Address, balance: U256) {
pub fn eip7708_burn_log(&mut self, address: Address, balance: U256) {
// Only emit log if EIP-7708 is enabled and balance is non-zero
if !self.cfg.spec.is_enabled_in(AMSTERDAM) || self.cfg.eip7708_disabled || balance.is_zero()
{
return;
}

// Create LOG2 with SelfBalanceLog(address,uint256) event signature
// Topic[0]: SelfBalanceLog event signature
// Create LOG2 with Burn(address,uint256) event signature
// Topic[0]: Burn event signature
// Topic[1]: account address (zero-padded to 32 bytes)
// Data: amount in wei (big-endian uint256)
let topics = std::vec![
SELFDESTRUCT_LOG_TOPIC,
B256::left_padding_from(address.as_slice()),
];
let topics = std::vec![BURN_LOG_TOPIC, B256::left_padding_from(address.as_slice()),];
let data = Bytes::copy_from_slice(&balance.to_be_bytes::<32>());

self.logs.push(Log {
Expand Down
16 changes: 7 additions & 9 deletions crates/ee-tests/src/revm_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,7 @@ fn test_disable_balance_check() {
// EIP-7708: ETH transfers emit a log
// ============================================================================

use revm::primitives::eip7708::{
ETH_TRANSFER_LOG_ADDRESS, ETH_TRANSFER_LOG_TOPIC, SELFDESTRUCT_LOG_TOPIC,
};
use revm::primitives::eip7708::{BURN_LOG_TOPIC, ETH_TRANSFER_LOG_ADDRESS, ETH_TRANSFER_LOG_TOPIC};
use revm::primitives::B256;

/// Test EIP-7708 transfer log emission for transaction value transfer
Expand Down Expand Up @@ -485,18 +483,18 @@ fn test_eip7708_selfdestruct_to_self() {

assert!(result.is_success(), "Transaction should succeed");

// Find the selfdestruct-to-self log
// Find the burn log
let logs = result.logs();
let selfdestruct_to_self_log = logs
let burn_log = logs
.iter()
.find(|log| log.data.topics().len() == 2 && log.data.topics()[0] == SELFDESTRUCT_LOG_TOPIC);
.find(|log| log.data.topics().len() == 2 && log.data.topics()[0] == BURN_LOG_TOPIC);

assert!(
selfdestruct_to_self_log.is_some(),
"Expected selfdestruct-to-self log, got logs: {:?}",
burn_log.is_some(),
"Expected burn log, got logs: {:?}",
logs
);
let log = selfdestruct_to_self_log.unwrap();
let log = burn_log.unwrap();
assert_eq!(log.address, ETH_TRANSFER_LOG_ADDRESS);
// The log data should contain the create value
assert_eq!(log.data.data.as_ref(), &create_value.to_be_bytes::<32>());
Expand Down
2 changes: 1 addition & 1 deletion crates/handler/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ pub fn return_create<JOURNAL: JournalTr, CFG: Cfg>(
}

// EIP-170: Contract code size limit to 0x6000 (~25kb)
// EIP-7907 increased this limit to 0xc000 (~49kb).
// EIP-7954 increased this limit to 0x8000 (~32kb).
if spec_id.is_enabled_in(SPURIOUS_DRAGON) && interpreter_result.output.len() > max_code_size {
journal.checkpoint_revert(checkpoint);
interpreter_result.result = InstructionResult::CreateContractSizeLimit;
Expand Down
51 changes: 41 additions & 10 deletions crates/handler/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ mod tests {
Context, ContextTr, TxEnv,
};
use database::{CacheDB, EmptyDB};
use primitives::{address, eip3860, eip7907, hardfork::SpecId, Bytes, TxKind, B256};
use primitives::{address, eip3860, eip7954, hardfork::SpecId, Bytes, TxKind, B256};
use state::{AccountInfo, Bytecode};

fn deploy_contract(
Expand Down Expand Up @@ -312,10 +312,10 @@ mod tests {
}

#[test]
fn test_eip7907_initcode_size_limit_failure_osaka() {
let large_bytecode = vec![opcode::STOP; eip7907::MAX_INITCODE_SIZE + 1];
fn test_eip7954_initcode_size_limit_failure_amsterdam() {
let large_bytecode = vec![opcode::STOP; eip7954::MAX_INITCODE_SIZE + 1];
let bytecode: Bytes = large_bytecode.into();
let result = deploy_contract(bytecode, Some(SpecId::OSAKA));
let result = deploy_contract(bytecode, Some(SpecId::AMSTERDAM));
assert!(matches!(
result,
Err(EVMError::Transaction(
Expand All @@ -325,19 +325,50 @@ mod tests {
}

#[test]
fn test_eip7907_code_size_limit_failure() {
// EIP-7907: MAX_CODE_SIZE = 0x40000
// use the simplest method to return a contract code size greater than 0x40000
// PUSH3 0x40001 (greater than 0x40000) - return size
fn test_eip7954_initcode_size_limit_success_amsterdam() {
let large_bytecode = vec![opcode::STOP; eip7954::MAX_INITCODE_SIZE];
let bytecode: Bytes = large_bytecode.into();
let result = deploy_contract(bytecode, Some(SpecId::AMSTERDAM));
assert!(matches!(result, Ok(ExecutionResult::Success { .. })));
}

#[test]
fn test_eip7954_initcode_between_old_and_new_limit() {
// Size between old limit (0xC000) and new limit (0x10000):
// should fail pre-Amsterdam, succeed at Amsterdam
let size = eip3860::MAX_INITCODE_SIZE + 1; // 0xC001
let large_bytecode = vec![opcode::STOP; size];

// Pre-Amsterdam (Prague): should fail
let bytecode: Bytes = large_bytecode.clone().into();
let result = deploy_contract(bytecode, Some(SpecId::PRAGUE));
assert!(matches!(
result,
Err(EVMError::Transaction(
InvalidTransaction::CreateInitCodeSizeLimit
))
));

// Amsterdam: should succeed
let bytecode: Bytes = large_bytecode.into();
let result = deploy_contract(bytecode, Some(SpecId::AMSTERDAM));
assert!(matches!(result, Ok(ExecutionResult::Success { .. })));
}

#[test]
fn test_eip7954_code_size_limit_failure() {
// EIP-7954: MAX_CODE_SIZE = 0x8000
// use the simplest method to return a contract code size greater than 0x8000
// PUSH3 0x8001 (greater than 0x8000) - return size
// PUSH1 0x00 - memory position 0
// RETURN - return uninitialized memory, will be filled with 0
let init_code = vec![
0x62, 0x04, 0x00, 0x01, // PUSH3 0x40001 (greater than 0x40000)
0x62, 0x00, 0x80, 0x01, // PUSH3 0x8001 (greater than 0x8000)
0x60, 0x00, // PUSH1 0
0xf3, // RETURN
];
let bytecode: Bytes = init_code.into();
let result = deploy_contract(bytecode, Some(SpecId::OSAKA));
let result = deploy_contract(bytecode, Some(SpecId::AMSTERDAM));
assert!(
matches!(
result,
Expand Down
23 changes: 9 additions & 14 deletions crates/interpreter/src/instructions/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,23 +115,18 @@ pub fn exchange<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'
}

fn decode_single(x: usize) -> Option<usize> {
if x <= 90 {
Some(x + 17)
} else if x >= 128 {
Some(x - 20)
if x <= 90 || x >= 128 {
Some((x + 145) % 256)
} else {
None
}
}

fn decode_pair(x: usize) -> Option<(usize, usize)> {
let k = if x <= 79 {
x
} else if x >= 128 {
x - 48
} else {
if x > 81 && x < 128 {
return None;
};
}
let k = x ^ 143;
let q = k / 16;
let r = k % 16;
if q < r {
Expand Down Expand Up @@ -174,7 +169,7 @@ mod tests {
fn test_dupn() {
let interpreter = run_bytecode(&[
PUSH1, 0x01, PUSH1, 0x00, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1,
DUP1, DUP1, DUP1, DUP1, DUP1, DUPN, 0x00,
DUP1, DUP1, DUP1, DUP1, DUP1, DUPN, 0x80,
]);
assert_eq!(interpreter.stack.len(), 18);
assert_eq!(interpreter.stack.data()[17], U256::from(1));
Expand All @@ -188,7 +183,7 @@ mod tests {
fn test_swapn() {
let interpreter = run_bytecode(&[
PUSH1, 0x01, PUSH1, 0x00, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1,
DUP1, DUP1, DUP1, DUP1, DUP1, PUSH1, 0x02, SWAPN, 0x00,
DUP1, DUP1, DUP1, DUP1, DUP1, PUSH1, 0x02, SWAPN, 0x80,
]);
assert_eq!(interpreter.stack.len(), 18);
assert_eq!(interpreter.stack.data()[17], U256::from(1));
Expand All @@ -200,7 +195,7 @@ mod tests {

#[test]
fn test_exchange() {
let interpreter = run_bytecode(&[PUSH1, 0x00, PUSH1, 0x01, PUSH1, 0x02, EXCHANGE, 0x01]);
let interpreter = run_bytecode(&[PUSH1, 0x00, PUSH1, 0x01, PUSH1, 0x02, EXCHANGE, 0x8E]);
assert_eq!(interpreter.stack.len(), 3);
assert_eq!(interpreter.stack.data()[2], U256::from(2));
assert_eq!(interpreter.stack.data()[1], U256::from(0));
Expand All @@ -222,7 +217,7 @@ mod tests {
#[test]
fn test_exchange_with_iszero() {
let interpreter = run_bytecode(&[
PUSH1, 0x00, PUSH1, 0x00, PUSH1, 0x00, EXCHANGE, 0x01, ISZERO,
PUSH1, 0x00, PUSH1, 0x00, PUSH1, 0x00, EXCHANGE, 0x8E, ISZERO,
]);
assert_eq!(interpreter.stack.len(), 3);
assert_eq!(interpreter.stack.data()[2], U256::from(1));
Expand Down
8 changes: 4 additions & 4 deletions crates/primitives/src/eip7708.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ pub const ETH_TRANSFER_LOG_ADDRESS: Address =
pub const ETH_TRANSFER_LOG_TOPIC: B256 =
b256!("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef");

/// The topic hash for selfdestruct events (burn).
/// The topic hash for burn events.
///
/// This is emitted when a contract self-destructs to itself or when a
/// self-destructed account still has remaining balance at end of transaction.
/// `keccak256("Selfdestruct(address,uint256)")`
pub const SELFDESTRUCT_LOG_TOPIC: B256 =
b256!("0x4bfaba3443c1a1836cd362418edc679fc96cae8449cbefccb6457cdf2c943083");
/// `keccak256("Burn(address,uint256)")`
pub const BURN_LOG_TOPIC: B256 =
b256!("0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5");
9 changes: 9 additions & 0 deletions crates/primitives/src/eip7954.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//! EIP-7954: Increase Maximum Contract Size
//!
//! Increases the contract code size limit and initcode size limit.

/// EIP-7954: Maximum contract code size: 32,768 bytes (0x8000).
pub const MAX_CODE_SIZE: usize = 0x8000;

/// EIP-7954: Maximum initcode size: 65,536 bytes (0x10000).
pub const MAX_INITCODE_SIZE: usize = 0x10000;
1 change: 1 addition & 0 deletions crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub mod eip7708;
pub mod eip7823;
pub mod eip7825;
pub mod eip7907;
pub mod eip7954;
pub mod hardfork;
pub mod hints_util;
mod once_lock;
Expand Down
7 changes: 5 additions & 2 deletions scripts/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ run_tests() {
echo "Running main develop statetests..."
$RUST_RUNNER run $CARGO_OPTS -p revme -- statetest $KEEP_GOING_FLAG "$MAIN_DEVELOP_DIR/state_tests"

echo "Running devnet statetests..."
$RUST_RUNNER run $CARGO_OPTS -p revme -- statetest $KEEP_GOING_FLAG "$DEVNET_DIR/state_tests"
echo "SKIP Running devnet statetests..."
#$RUST_RUNNER run $CARGO_OPTS -p revme -- statetest $KEEP_GOING_FLAG "$DEVNET_DIR/state_tests"

echo "Running legacy Cancun tests..."
$RUST_RUNNER run $CARGO_OPTS -p revme -- statetest $KEEP_GOING_FLAG "$LEGACY_DIR/Cancun/GeneralStateTests"
Expand All @@ -170,6 +170,9 @@ run_tests() {

echo "Running main stable blockchain tests..."
$RUST_RUNNER run $CARGO_OPTS -p revme -- btest $KEEP_GOING_FLAG "$MAIN_STABLE_DIR/blockchain_tests"

echo "SKIP Running devnet blockchain tests..."
#$RUST_RUNNER run $CARGO_OPTS -p revme -- btest $KEEP_GOING_FLAG "$DEVNET_DIR/blockchain_tests"
}

##############################
Expand Down
Loading