diff --git a/evm-tests/jsontests/src/main.rs b/evm-tests/jsontests/src/main.rs index cfd12e55..46fb002c 100644 --- a/evm-tests/jsontests/src/main.rs +++ b/evm-tests/jsontests/src/main.rs @@ -184,16 +184,20 @@ fn short_test_file_name(name: &str) -> String { } const SKIPPED_CASES: &[&str] = &[ + // funky test with `bigint 0x00` value in json :) not possible to happen on mainnet and require + // custom json parser. https://github.com/ethereum/tests/issues/971 "stTransactionTest/ValueOverflow", "stTransactionTest/ValueOverflowParis", - "stTransactionTest/HighGasPrice", - "stTransactionTest/HighGasPriceParis", - "stCreateTest/CreateTransactionHighNonce", // Long execution "stTimeConsuming/static_Call50000_sha256", - "stTimeConsuming/CALLBlake2f_MaxRounds", "vmPerformance/loopMul", + "stTimeConsuming/CALLBlake2f_MaxRounds", + // Skip python-specific tests "Pyspecs", + // KZG-precompile not supported + "stPreCompiledContracts/precompsEIP2929Cancun", + "stEIP4844-blobtransactions/", + "stEIP3607", ]; fn should_skip(path: &Path) -> bool { diff --git a/evm-tests/jsontests/src/state.rs b/evm-tests/jsontests/src/state.rs index 697f8f08..0fcd73c0 100644 --- a/evm-tests/jsontests/src/state.rs +++ b/evm-tests/jsontests/src/state.rs @@ -331,6 +331,9 @@ fn test_run( .map_or_else(U256::zero, |acc| acc.balance); for (i, state) in states.iter().enumerate() { + // if i != 10 { + // continue; + // } let transaction = test.0.transaction.select(&state.indexes); let mut backend = MemoryBackend::new(&vicinity, original_state.clone()); diff --git a/evm-tests/jsontests/src/utils.rs b/evm-tests/jsontests/src/utils.rs index 1838fc90..b6657cbd 100644 --- a/evm-tests/jsontests/src/utils.rs +++ b/evm-tests/jsontests/src/utils.rs @@ -182,7 +182,16 @@ pub mod transaction { return Err(InvalidTxReason::GasLimitReached); } - let required_funds = tx.gas_limit.0 * tx.gas_price.0 + tx.value.0; + let required_funds = if let Some(x) = tx.gas_limit.0.checked_mul(tx.gas_price.0) { + if let Some(y) = x.checked_add(tx.value.0) { + y + } else { + return Err(InvalidTxReason::OutOfFund); + } + } else { + return Err(InvalidTxReason::OutOfFund); + }; + if caller_balance < required_funds { return Err(InvalidTxReason::OutOfFund); } diff --git a/evm-tests/jsontests/tests/state.rs b/evm-tests/jsontests/tests/state.rs index cdf3c5af..2062ffd9 100644 --- a/evm-tests/jsontests/tests/state.rs +++ b/evm-tests/jsontests/tests/state.rs @@ -16,8 +16,8 @@ fn short_test_file_name(name: &str) -> String { } pub fn run(dir: &str) { - // const SPEC: Option = Some(ForkSpec::Cancun); - const SPEC: Option = Some(ForkSpec::Shanghai); + const SPEC: Option = Some(ForkSpec::Cancun); + //const SPEC: Option = Some(ForkSpec::Shanghai); let _ = env_logger::try_init(); @@ -26,10 +26,10 @@ pub fn run(dir: &str) { let mut tests_result = TestExecutionResult::new(); let verbose_output = VerboseOutput { - verbose: true, - very_verbose: true, - verbose_failed: true, - print_state: true, + verbose: false, + very_verbose: false, + verbose_failed: false, + print_state: false, }; for entry in fs::read_dir(dest).unwrap() { let entry = entry.unwrap(); @@ -41,7 +41,6 @@ pub fn run(dir: &str) { let path = entry.path(); let filename = path.to_str().unwrap(); - // println!("RUM for: {}", short_test_file_name(filename)); if should_skip(&path) { println!("Skipping test case {}", short_test_file_name(filename)); @@ -58,9 +57,6 @@ pub fn run(dir: &str) { for (name, test) in test_suite { let test_res = statetests::test(verbose_output.clone(), &name, test, SPEC); - // println!("Tests count: {}", test_res.total); - // println!("Failed: {}\n", test_res.failed); - tests_result.merge(test_res); } } @@ -84,9 +80,12 @@ const SKIPPED_CASES: &[&str] = &[ "stTransactionTest/HighGasPrice", "stTransactionTest/HighGasPriceParis", "stCreateTest/CreateTransactionHighNonce", + // KZG-precompile not supported + "stPreCompiledContracts/precompsEIP2929Cancun", ]; fn should_skip(path: &Path) -> bool { + println!("{path:?}"); let matches = |case: &str| { let file_stem = path.file_stem().unwrap(); let dir_path = path.parent().unwrap(); diff --git a/gasometer/src/costs.rs b/gasometer/src/costs.rs index 6933caf3..61c6d60e 100644 --- a/gasometer/src/costs.rs +++ b/gasometer/src/costs.rs @@ -284,7 +284,7 @@ pub fn call_cost( + new_cost(is_call_or_staticcall, new_account, transfers_value, config) } -pub const fn address_access_cost(is_cold: bool, regular_value: u64, config: &Config) -> u64 { +pub fn address_access_cost(is_cold: bool, regular_value: u64, config: &Config) -> u64 { if config.increase_state_access_gas { if is_cold { config.gas_account_access_cold diff --git a/gasometer/src/lib.rs b/gasometer/src/lib.rs index 59f58689..ec7f7124 100644 --- a/gasometer/src/lib.rs +++ b/gasometer/src/lib.rs @@ -32,7 +32,8 @@ macro_rules! log_gas { ($self:expr, $($arg:tt)*) => ( log::trace!(target: "evm", "Gasometer {} [Gas used: {}, Gas left: {}]", format_args!($($arg)*), $self.total_used_gas(), $self.gas()); - println!(" Gasometer {} [Gas used: {}, Gas left: {}]", format_args!($($arg)*), $self.total_used_gas(), $self.gas()); + // TODOFEE + //println!(" Gasometer {} [Gas used: {}, Gas left: {}]", format_args!($($arg)*), $self.total_used_gas(), $self.gas()); ); } @@ -762,6 +763,15 @@ pub fn dynamic_opcode_cost( len: 32, }), + Opcode::MCOPY => Some(MemoryCost { + offset: { + let src = stack.peek_usize(0)?; + let dst = stack.peek_usize(1)?; + max(src, dst) + }, + len: stack.peek_usize(2)?, + }), + Opcode::MSTORE8 => Some(MemoryCost { offset: stack.peek_usize(0)?, len: 1, diff --git a/runtime/src/eval/mod.rs b/runtime/src/eval/mod.rs index 53338191..d0f1e77d 100644 --- a/runtime/src/eval/mod.rs +++ b/runtime/src/eval/mod.rs @@ -51,7 +51,10 @@ pub fn eval(state: &mut Runtime, opcode: Opcode, handler: &mut H) -> Opcode::LOG3 => system::log(state, 3, handler), Opcode::LOG4 => system::log(state, 4, handler), Opcode::SUICIDE => system::selfdestruct(state, handler), - Opcode::CREATE => system::create(state, false, handler), + Opcode::CREATE => { + let res = system::create(state, false, handler); + res + } Opcode::CREATE2 => system::create(state, true, handler), Opcode::CALL => system::call(state, CallScheme::Call, handler), Opcode::CALLCODE => system::call(state, CallScheme::CallCode, handler), diff --git a/src/executor/stack/executor.rs b/src/executor/stack/executor.rs index b586e6ac..977c550c 100644 --- a/src/executor/stack/executor.rs +++ b/src/executor/stack/executor.rs @@ -78,6 +78,7 @@ pub struct StackSubstateMetadata<'config> { is_static: bool, depth: Option, accessed: Option, + created: BTreeSet, } impl<'config> StackSubstateMetadata<'config> { @@ -92,6 +93,7 @@ impl<'config> StackSubstateMetadata<'config> { is_static: false, depth: None, accessed, + created: BTreeSet::new(), } } @@ -130,6 +132,7 @@ impl<'config> StackSubstateMetadata<'config> { is_static: is_static || self.is_static, depth: self.depth.map_or(Some(0), |n| Some(n + 1)), accessed: self.accessed.as_ref().map(|_| Accessed::default()), + created: self.created.clone(), } } @@ -196,7 +199,7 @@ pub trait StackState<'config>: Backend { fn is_empty(&self, address: H160) -> bool; fn deleted(&self, address: H160) -> bool; - fn created(&self, address: H160) -> bool; + fn is_created(&self, address: H160) -> bool; fn is_cold(&self, address: H160) -> bool; fn is_storage_cold(&self, address: H160, key: H256) -> bool; @@ -638,7 +641,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> let transaction_cost = gasometer::call_transaction_cost(&data, &access_list); // TODOFEE - println!("transaction_cost: {transaction_cost:?}"); + // println!("transaction_cost: {transaction_cost:?}"); let gasometer = &mut self.state.metadata_mut().gasometer; match gasometer.record_transaction(transaction_cost) { Ok(()) => (), @@ -868,7 +871,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> } // It needed for CANCUN hard fork EIP-6780 we should mark account as created // to handle SELFDESTRUCT in the same transaction - self.set_created(address); + self.state.set_created(address); if self.config.create_increase_nonce { if let Err(e) = self.state.inc_nonce(address) { @@ -1127,14 +1130,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> } } - /// Sed address created. - fn set_created(&mut self, address: H160) { - self.state.set_created(address) - } - /// Check whether an address has already been created. - fn created(&self, address: H160) -> bool { - self.state.created(address) + fn is_created(&self, address: H160) -> bool { + self.state.is_created(address) } } @@ -1170,7 +1168,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Interprete } // TODOFEE - println!("OPCODE: {opcode:?}"); + // println!("OPCODE: {opcode:?}"); if let Some(cost) = gasometer::static_opcode_cost(opcode) { self.state .metadata_mut() @@ -1355,7 +1353,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler /// Mark account as deleted /// - SELFDESTRUCT - CANCUN hard fork: EIP-6780 fn mark_delete(&mut self, address: H160, target: H160) -> Result<(), ExitError> { - let is_created = self.created(address); + let is_created = self.is_created(address); // SELFDESTRUCT - CANCUN hard fork: EIP-6780 - selfdestruct only if contract is created in the same tx if self.config.has_restricted_selfdestruct && !is_created && address == target { // State is not changed: @@ -1380,7 +1378,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler self.state.reset_balance(address); // For CANCUN hard fork SELFDESTRUCT (EIP-6780) state is not changed // or if SELFDESTRUCT in the same TX - account should selfdestruct - if !self.config.has_restricted_selfdestruct || self.created(address) { + if !self.config.has_restricted_selfdestruct || self.is_created(address) { self.state.set_deleted(address); } @@ -1401,7 +1399,6 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler emit_exit!(reason.clone()); return Capture::Exit((reason, None, Vec::new())); } - self.create_inner(caller, scheme, value, init_code, target_gas, true) } diff --git a/src/executor/stack/memory.rs b/src/executor/stack/memory.rs index 1c824cc6..e7a82ac2 100644 --- a/src/executor/stack/memory.rs +++ b/src/executor/stack/memory.rs @@ -155,6 +155,7 @@ impl<'config> MemoryStackSubstate<'config> { self.storages.append(&mut exited.storages); self.tstorages.append(&mut exited.tstorages); self.deletes.append(&mut exited.deletes); + self.creates.append(&mut exited.creates); Ok(()) } @@ -282,18 +283,6 @@ impl<'config> MemoryStackSubstate<'config> { false } - pub fn created(&self, address: H160) -> bool { - if self.creates.contains(&address) { - return true; - } - - if let Some(parent) = self.parent.as_ref() { - return parent.created(address); - } - - false - } - #[allow(clippy::map_entry)] fn account_mut(&mut self, address: H160, backend: &B) -> &mut MemoryStackAccount { if !self.accounts.contains_key(&address) { @@ -362,6 +351,18 @@ impl<'config> MemoryStackSubstate<'config> { self.creates.insert(address); } + pub fn is_created(&self, address: H160) -> bool { + if self.creates.contains(&address) { + return true; + } + + if let Some(parent) = self.parent.as_ref() { + return parent.is_created(address); + } + + false + } + pub fn set_code(&mut self, address: H160, code: Vec, backend: &B) { self.account_mut(address, backend).code = Some(code); } @@ -554,10 +555,6 @@ impl<'backend, 'config, B: Backend> StackState<'config> for MemoryStackState<'ba self.substate.deleted(address) } - fn created(&self, address: H160) -> bool { - self.substate.created(address) - } - fn is_cold(&self, address: H160) -> bool { self.substate.is_cold(address) } @@ -590,6 +587,10 @@ impl<'backend, 'config, B: Backend> StackState<'config> for MemoryStackState<'ba self.substate.set_created(address) } + fn is_created(&self, address: H160) -> bool { + self.substate.is_created(address) + } + fn set_code(&mut self, address: H160, code: Vec) { self.substate.set_code(address, code, self.backend) }