From 63a24d54f2a3fdceb9ca013f2f5c023189d051c2 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Wed, 26 Jun 2024 08:33:36 +0700 Subject: [PATCH 01/17] intitial --- crates/cheatcodes/spec/src/vm.rs | 4 ++++ crates/cheatcodes/src/evm.rs | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index f774fcbc7e1b..1edf06e02f87 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -2155,6 +2155,10 @@ interface Vm { /// Returns a random `address`. #[cheatcode(group = Utilities)] function randomAddress() external returns (address); + + /// Set blockhash for the current block. + #[cheatcode(group = Utilities)] + function setBlockhash(uint256 blockNumber, bytes32 blockHash) external; } } diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index 50265b4b12e0..dce5533d13c2 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -567,6 +567,14 @@ impl Cheatcode for stopAndReturnStateDiffCall { } } + +impl Cheatcode for setBlockhashCall{ + fn apply_full(&self, ccx: &mut CheatsCtxt) -> Result { + todo!() + } + +} + pub(super) fn get_nonce(ccx: &mut CheatsCtxt, address: &Address) -> Result { let (account, _) = ccx.ecx.journaled_state.load_account(*address, &mut ccx.ecx.db)?; Ok(account.info.nonce.abi_encode()) From d960794e05d80db6cb978932b5c78f33a1a127fc Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Wed, 26 Jun 2024 15:53:08 +0700 Subject: [PATCH 02/17] add set_blockhash method to DatabaseExt trait --- crates/cheatcodes/src/evm.rs | 4 +--- crates/evm/core/src/backend/mod.rs | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index dce5533d13c2..ca8495a3a27e 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -567,12 +567,10 @@ impl Cheatcode for stopAndReturnStateDiffCall { } } - -impl Cheatcode for setBlockhashCall{ +impl Cheatcode for setBlockhashCall { fn apply_full(&self, ccx: &mut CheatsCtxt) -> Result { todo!() } - } pub(super) fn get_nonce(ccx: &mut CheatsCtxt, address: &Address) -> Result { diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 1185b0d6f3ef..6689695e4152 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -8,7 +8,7 @@ use crate::{ InspectorExt, }; use alloy_genesis::GenesisAccount; -use alloy_primitives::{keccak256, uint, Address, B256, U256}; +use alloy_primitives::{keccak256, uint, Address, B256, B64, U256, U64}; use alloy_rpc_types::{Block, BlockNumberOrTag, BlockTransactions, Transaction}; use alloy_serde::WithOtherFields; use eyre::Context; @@ -330,6 +330,9 @@ pub trait DatabaseExt: Database { } Ok(()) } + + /// set the blockhash for the given block number + fn set_blockhash(&mut self, block_number: B256, block_hash: B256) -> Result<(), DatabaseError>; } struct _ObjectSafe(dyn DatabaseExt); @@ -780,7 +783,7 @@ impl Backend { // created account takes precedence: for example contract creation in setups if init_account.is_created() { trace!(?loaded_account, "skipping created account"); - continue + continue; } // otherwise we need to replace the account's info with the one from the fork's @@ -855,7 +858,7 @@ impl Backend { if tx.hash == tx_hash { // found the target transaction - return Ok(Some(tx)) + return Ok(Some(tx)); } trace!(tx=?tx.hash, "committing transaction"); @@ -1370,6 +1373,17 @@ impl DatabaseExt for Backend { fn has_cheatcode_access(&self, account: &Address) -> bool { self.inner.cheatcode_access_accounts.contains(account) } + + fn set_blockhash(&mut self, block_number: B256, block_hash: B256) -> Result<(), DatabaseError> { + match self.mem_db.block_hashes.insert(block_number.into(), block_hash) { + Some(_) => Ok(()), + None => Err(DatabaseError::Other(format!( + " + Cannot set blockhash {:?} for block number {:?}", + block_hash, block_number + ))), + } + } } impl DatabaseRef for Backend { From e0f19e912170807b0bb6bf32b0d4eabba841467d Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Wed, 26 Jun 2024 17:03:24 +0700 Subject: [PATCH 03/17] cargo cheats --- crates/cheatcodes/assets/cheatcodes.json | 20 ++++++++++++++++++ crates/evm/core/src/backend/cow.rs | 24 +++++++++++++++++++--- crates/evm/core/src/backend/mod.rs | 4 ++-- testdata/cheats/Vm.sol | 1 + testdata/default/cheats/SetBlockhash.t.sol | 16 +++++++++++++++ 5 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 testdata/default/cheats/SetBlockhash.t.sol diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index 85b2766da128..0c4d09f7d7de 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -7391,6 +7391,26 @@ "status": "stable", "safety": "safe" }, + { + "func": { + "id": "setBlockhash", + "description": "Set blockhash for the current block.", + "declaration": "function setBlockhash(uint256 blockNumber, bytes32 blockHash) external;", + "visibility": "external", + "mutability": "", + "signature": "setBlockhash(uint256,bytes32)", + "selector": "0x5314b54a", + "selectorBytes": [ + 83, + 20, + 181, + 74 + ] + }, + "group": "utilities", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "setEnv", diff --git a/crates/evm/core/src/backend/cow.rs b/crates/evm/core/src/backend/cow.rs index 766070e997f5..91b84107fa22 100644 --- a/crates/evm/core/src/backend/cow.rs +++ b/crates/evm/core/src/backend/cow.rs @@ -94,7 +94,7 @@ impl<'a> CowBackend<'a> { let env = EnvWithHandlerCfg::new_with_spec_id(Box::new(env.clone()), self.spec_id); backend.initialize(&env); self.is_initialized = true; - return backend + return backend; } self.backend.to_mut() } @@ -102,7 +102,7 @@ impl<'a> CowBackend<'a> { /// Returns a mutable instance of the Backend if it is initialized. fn initialized_backend_mut(&mut self) -> Option<&mut Backend> { if self.is_initialized { - return Some(self.backend.to_mut()) + return Some(self.backend.to_mut()); } None } @@ -126,7 +126,7 @@ impl<'a> DatabaseExt for CowBackend<'a> { fn delete_snapshot(&mut self, id: U256) -> bool { // delete snapshot requires a previous snapshot to be initialized if let Some(backend) = self.initialized_backend_mut() { - return backend.delete_snapshot(id) + return backend.delete_snapshot(id); } false } @@ -244,6 +244,24 @@ impl<'a> DatabaseExt for CowBackend<'a> { fn has_cheatcode_access(&self, account: &Address) -> bool { self.backend.has_cheatcode_access(account) } + + fn set_blockhash(&mut self, block_number: B256, block_hash: B256) -> Result<(), DatabaseError> { + match self + .backend + .to_mut() + .mem_db() + .to_owned() + .block_hashes + .insert(block_number.into(), block_hash) + { + Some(_) => Ok(()), + None => Err(DatabaseError::Other(format!( + " + Cannot set blockhash {:?} for block number {:?}", + block_hash, block_number + ))), + } + } } impl<'a> DatabaseRef for CowBackend<'a> { diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 6689695e4152..483489748314 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -849,8 +849,8 @@ impl Backend { for tx in txs.into_iter() { // System transactions such as on L2s don't contain any pricing info so we skip them // otherwise this would cause reverts - if is_known_system_sender(tx.from) || - tx.transaction_type == Some(SYSTEM_TRANSACTION_TYPE) + if is_known_system_sender(tx.from) + || tx.transaction_type == Some(SYSTEM_TRANSACTION_TYPE) { trace!(tx=?tx.hash, "skipping system transaction"); continue; diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index 23e1f699c89d..158e16b64a99 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -365,6 +365,7 @@ interface Vm { function serializeUintToHex(string calldata objectKey, string calldata valueKey, uint256 value) external returns (string memory json); function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) external returns (string memory json); function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) external returns (string memory json); + function setBlockhash(uint256 blockNumber, bytes32 blockHash) external; function setEnv(string calldata name, string calldata value) external; function setNonce(address account, uint64 newNonce) external; function setNonceUnsafe(address account, uint64 newNonce) external; diff --git a/testdata/default/cheats/SetBlockhash.t.sol b/testdata/default/cheats/SetBlockhash.t.sol new file mode 100644 index 000000000000..eefeed3de997 --- /dev/null +++ b/testdata/default/cheats/SetBlockhash.t.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity 0.8.18; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +contract SetBlockhash is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function testSetBlockhash() public { + bytes32 blockhash = 0x1234567890123456789012345678901234567890123456789012345678901234; + vm.setBlockhash(1, blockhash); + bytes32 expected = vm.blockhash(1); + assertEq(actual, expected); + } +} From 22d69771b645675b84f7844521d58b8da5c6a7a0 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 27 Jun 2024 02:53:34 +0700 Subject: [PATCH 04/17] remove additional ; --- crates/evm/core/src/backend/cow.rs | 2 +- crates/evm/core/src/backend/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/evm/core/src/backend/cow.rs b/crates/evm/core/src/backend/cow.rs index 91b84107fa22..a1049db6ac59 100644 --- a/crates/evm/core/src/backend/cow.rs +++ b/crates/evm/core/src/backend/cow.rs @@ -94,7 +94,7 @@ impl<'a> CowBackend<'a> { let env = EnvWithHandlerCfg::new_with_spec_id(Box::new(env.clone()), self.spec_id); backend.initialize(&env); self.is_initialized = true; - return backend; + return backend } self.backend.to_mut() } diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 483489748314..6d94f9228899 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -783,7 +783,7 @@ impl Backend { // created account takes precedence: for example contract creation in setups if init_account.is_created() { trace!(?loaded_account, "skipping created account"); - continue; + continue } // otherwise we need to replace the account's info with the one from the fork's From 683732dc2e9decba939e1afa321b5e63c710d75d Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 27 Jun 2024 02:56:49 +0700 Subject: [PATCH 05/17] update to Evm group --- crates/cheatcodes/assets/cheatcodes.json | 4 ++-- crates/cheatcodes/spec/src/vm.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index 0c4d09f7d7de..4ec4cba718dc 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -7407,9 +7407,9 @@ 74 ] }, - "group": "utilities", + "group": "evm", "status": "stable", - "safety": "safe" + "safety": "unsafe" }, { "func": { diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index 1edf06e02f87..0f4f2338a9ac 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -430,6 +430,10 @@ interface Vm { #[cheatcode(group = Evm, safety = Safe)] function getBlobBaseFee() external view returns (uint256 blobBaseFee); + /// Set blockhash for the current block. + #[cheatcode(group = Evm, safety = Unsafe)] + function setBlockhash(uint256 blockNumber, bytes32 blockHash) external; + // -------- Account State -------- /// Sets an address' balance. @@ -2155,10 +2159,6 @@ interface Vm { /// Returns a random `address`. #[cheatcode(group = Utilities)] function randomAddress() external returns (address); - - /// Set blockhash for the current block. - #[cheatcode(group = Utilities)] - function setBlockhash(uint256 blockNumber, bytes32 blockHash) external; } } From c436cef1c3b84ec7cba82622cf2c18a2c889c12a Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 27 Jun 2024 03:00:04 +0700 Subject: [PATCH 06/17] remove err handling --- crates/evm/core/src/backend/cow.rs | 15 +++------------ crates/evm/core/src/backend/mod.rs | 13 +++---------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/crates/evm/core/src/backend/cow.rs b/crates/evm/core/src/backend/cow.rs index a1049db6ac59..9aa3ce0eb304 100644 --- a/crates/evm/core/src/backend/cow.rs +++ b/crates/evm/core/src/backend/cow.rs @@ -245,22 +245,13 @@ impl<'a> DatabaseExt for CowBackend<'a> { self.backend.has_cheatcode_access(account) } - fn set_blockhash(&mut self, block_number: B256, block_hash: B256) -> Result<(), DatabaseError> { - match self - .backend + fn set_blockhash(&mut self, block_number: B256, block_hash: B256) { + self.backend .to_mut() .mem_db() .to_owned() .block_hashes - .insert(block_number.into(), block_hash) - { - Some(_) => Ok(()), - None => Err(DatabaseError::Other(format!( - " - Cannot set blockhash {:?} for block number {:?}", - block_hash, block_number - ))), - } + .insert(block_number.into(), block_hash); } } diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 6d94f9228899..00a26d2fe86f 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -332,7 +332,7 @@ pub trait DatabaseExt: Database { } /// set the blockhash for the given block number - fn set_blockhash(&mut self, block_number: B256, block_hash: B256) -> Result<(), DatabaseError>; + fn set_blockhash(&mut self, block_number: B256, block_hash: B256); } struct _ObjectSafe(dyn DatabaseExt); @@ -1374,15 +1374,8 @@ impl DatabaseExt for Backend { self.inner.cheatcode_access_accounts.contains(account) } - fn set_blockhash(&mut self, block_number: B256, block_hash: B256) -> Result<(), DatabaseError> { - match self.mem_db.block_hashes.insert(block_number.into(), block_hash) { - Some(_) => Ok(()), - None => Err(DatabaseError::Other(format!( - " - Cannot set blockhash {:?} for block number {:?}", - block_hash, block_number - ))), - } + fn set_blockhash(&mut self, block_number: B256, block_hash: B256) { + self.mem_db.block_hashes.insert(block_number.into(), block_hash); } } From 336a4a530f7b43cae9357f58806fded91cc31eda Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 27 Jun 2024 03:08:21 +0700 Subject: [PATCH 07/17] adjust signature and add implementation for cheatcode --- crates/cheatcodes/src/evm.rs | 11 ++++++++++- crates/evm/core/src/backend/cow.rs | 6 +++--- crates/evm/core/src/backend/mod.rs | 10 +++++----- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index ca8495a3a27e..5000df928f2c 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -569,7 +569,16 @@ impl Cheatcode for stopAndReturnStateDiffCall { impl Cheatcode for setBlockhashCall { fn apply_full(&self, ccx: &mut CheatsCtxt) -> Result { - todo!() + let Self { blockNumber, blockHash } = self; + let block_number: U256 = *blockNumber; + ensure!( + block_number <= ccx.ecx.env.block.number, + "block number must be less than or equal to the current block number" + ); + + ccx.ecx.db.set_blockhash(*blockNumber, *blockHash); + + Ok(Default::default()) } } diff --git a/crates/evm/core/src/backend/cow.rs b/crates/evm/core/src/backend/cow.rs index 9aa3ce0eb304..236909cfdb0a 100644 --- a/crates/evm/core/src/backend/cow.rs +++ b/crates/evm/core/src/backend/cow.rs @@ -126,7 +126,7 @@ impl<'a> DatabaseExt for CowBackend<'a> { fn delete_snapshot(&mut self, id: U256) -> bool { // delete snapshot requires a previous snapshot to be initialized if let Some(backend) = self.initialized_backend_mut() { - return backend.delete_snapshot(id); + return backend.delete_snapshot(id) } false } @@ -245,13 +245,13 @@ impl<'a> DatabaseExt for CowBackend<'a> { self.backend.has_cheatcode_access(account) } - fn set_blockhash(&mut self, block_number: B256, block_hash: B256) { + fn set_blockhash(&mut self, block_number: U256, block_hash: B256) { self.backend .to_mut() .mem_db() .to_owned() .block_hashes - .insert(block_number.into(), block_hash); + .insert(block_number, block_hash); } } diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 00a26d2fe86f..4dc11edd8f21 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -8,7 +8,7 @@ use crate::{ InspectorExt, }; use alloy_genesis::GenesisAccount; -use alloy_primitives::{keccak256, uint, Address, B256, B64, U256, U64}; +use alloy_primitives::{keccak256, uint, Address, B256, U256}; use alloy_rpc_types::{Block, BlockNumberOrTag, BlockTransactions, Transaction}; use alloy_serde::WithOtherFields; use eyre::Context; @@ -332,7 +332,7 @@ pub trait DatabaseExt: Database { } /// set the blockhash for the given block number - fn set_blockhash(&mut self, block_number: B256, block_hash: B256); + fn set_blockhash(&mut self, block_number: U256, block_hash: B256); } struct _ObjectSafe(dyn DatabaseExt); @@ -858,7 +858,7 @@ impl Backend { if tx.hash == tx_hash { // found the target transaction - return Ok(Some(tx)); + return Ok(Some(tx)) } trace!(tx=?tx.hash, "committing transaction"); @@ -1374,8 +1374,8 @@ impl DatabaseExt for Backend { self.inner.cheatcode_access_accounts.contains(account) } - fn set_blockhash(&mut self, block_number: B256, block_hash: B256) { - self.mem_db.block_hashes.insert(block_number.into(), block_hash); + fn set_blockhash(&mut self, block_number: U256, block_hash: B256) { + self.mem_db.block_hashes.insert(block_number, block_hash); } } From e354e54a22baeae29aec70f0e68f176bfe514682 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 27 Jun 2024 04:09:55 +0700 Subject: [PATCH 08/17] lint --- crates/evm/core/src/backend/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 4dc11edd8f21..70ad93230b9b 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -849,8 +849,8 @@ impl Backend { for tx in txs.into_iter() { // System transactions such as on L2s don't contain any pricing info so we skip them // otherwise this would cause reverts - if is_known_system_sender(tx.from) - || tx.transaction_type == Some(SYSTEM_TRANSACTION_TYPE) + if is_known_system_sender(tx.from) || + tx.transaction_type == Some(SYSTEM_TRANSACTION_TYPE) { trace!(tx=?tx.hash, "skipping system transaction"); continue; From 8f9845d90128f65864ce044cdb793f2071ce24c8 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 27 Jun 2024 04:11:33 +0700 Subject: [PATCH 09/17] update --- crates/cheatcodes/src/evm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index ef5b5b38b457..b005ac54ab92 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -568,7 +568,7 @@ impl Cheatcode for stopAndReturnStateDiffCall { } impl Cheatcode for setBlockhashCall { - fn apply_full(&self, ccx: &mut CheatsCtxt) -> Result { + fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { blockNumber, blockHash } = self; let block_number: U256 = *blockNumber; ensure!( From 0ece26755313cdbc4ad53885775113e74eba2f99 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 27 Jun 2024 17:28:54 +0700 Subject: [PATCH 10/17] fix test --- testdata/default/cheats/SetBlockhash.t.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testdata/default/cheats/SetBlockhash.t.sol b/testdata/default/cheats/SetBlockhash.t.sol index eefeed3de997..76ca854b671c 100644 --- a/testdata/default/cheats/SetBlockhash.t.sol +++ b/testdata/default/cheats/SetBlockhash.t.sol @@ -8,9 +8,9 @@ contract SetBlockhash is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); function testSetBlockhash() public { - bytes32 blockhash = 0x1234567890123456789012345678901234567890123456789012345678901234; - vm.setBlockhash(1, blockhash); - bytes32 expected = vm.blockhash(1); - assertEq(actual, expected); + bytes32 blockHash = 0x1234567890123456789012345678901234567890123456789012345678901234; + vm.setBlockhash(1, blockHash); + bytes32 expected = blockhash(1); + assertEq(blockHash, expected); } } From 5d3da00da5a523352ed7717a1b3e43b721ab5676 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 27 Jun 2024 17:52:56 +0700 Subject: [PATCH 11/17] fmt --- crates/evm/core/src/backend/cow.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/crates/evm/core/src/backend/cow.rs b/crates/evm/core/src/backend/cow.rs index 2f958be10579..7355d08e957b 100644 --- a/crates/evm/core/src/backend/cow.rs +++ b/crates/evm/core/src/backend/cow.rs @@ -102,7 +102,7 @@ impl<'a> CowBackend<'a> { /// Returns a mutable instance of the Backend if it is initialized. fn initialized_backend_mut(&mut self) -> Option<&mut Backend> { if self.is_initialized { - return Some(self.backend.to_mut()); + return Some(self.backend.to_mut()) } None } @@ -246,12 +246,7 @@ impl<'a> DatabaseExt for CowBackend<'a> { } fn set_blockhash(&mut self, block_number: U256, block_hash: B256) { - self.backend - .to_mut() - .mem_db() - .to_owned() - .block_hashes - .insert(block_number, block_hash); + self.backend.to_mut().mem_db().to_owned().block_hashes.insert(block_number, block_hash); } } From 719219abd7a8c7a976823a2aa6167984dd88b444 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Fri, 28 Jun 2024 23:34:19 +0700 Subject: [PATCH 12/17] refactor based on reviews --- crates/cheatcodes/src/evm.rs | 7 +++---- crates/evm/core/src/backend/cow.rs | 2 +- crates/evm/core/src/backend/mod.rs | 8 ++++++-- crates/forge/tests/it/invariant.rs | 2 +- testdata/default/cheats/SetBlockhash.t.sol | 4 ++-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index b005ac54ab92..0b42391f8b31 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -569,14 +569,13 @@ impl Cheatcode for stopAndReturnStateDiffCall { impl Cheatcode for setBlockhashCall { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { - let Self { blockNumber, blockHash } = self; - let block_number: U256 = *blockNumber; + let Self { blockNumber, blockHash } = *self; ensure!( - block_number <= ccx.ecx.env.block.number, + blockNumber <= ccx.ecx.env.block.number, "block number must be less than or equal to the current block number" ); - ccx.ecx.db.set_blockhash(*blockNumber, *blockHash); + ccx.ecx.db.set_blockhash(blockNumber, blockHash); Ok(Default::default()) } diff --git a/crates/evm/core/src/backend/cow.rs b/crates/evm/core/src/backend/cow.rs index 7355d08e957b..203ea97056ed 100644 --- a/crates/evm/core/src/backend/cow.rs +++ b/crates/evm/core/src/backend/cow.rs @@ -246,7 +246,7 @@ impl<'a> DatabaseExt for CowBackend<'a> { } fn set_blockhash(&mut self, block_number: U256, block_hash: B256) { - self.backend.to_mut().mem_db().to_owned().block_hashes.insert(block_number, block_hash); + self.backend.to_mut().set_blockhash(block_number, block_hash); } } diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index b09ced105763..e5f05415232f 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -331,7 +331,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { Ok(()) } - /// set the blockhash for the given block number + /// Set the blockhash for the given block number fn set_blockhash(&mut self, block_number: U256, block_hash: B256); } @@ -1375,7 +1375,11 @@ impl DatabaseExt for Backend { } fn set_blockhash(&mut self, block_number: U256, block_hash: B256) { - self.mem_db.block_hashes.insert(block_number, block_hash); + if let Some(db) = self.active_fork_db_mut() { + db.block_hashes.insert(block_number, block_hash); + } else { + self.mem_db.block_hashes.insert(block_number, block_hash); + } } } diff --git a/crates/forge/tests/it/invariant.rs b/crates/forge/tests/it/invariant.rs index 537569745aaf..06637f8e5616 100644 --- a/crates/forge/tests/it/invariant.rs +++ b/crates/forge/tests/it/invariant.rs @@ -391,7 +391,7 @@ async fn test_shrink_fail_on_revert() { runner.test_options.fuzz.seed = Some(U256::from(119u32)); runner.test_options.invariant.fail_on_revert = true; runner.test_options.invariant.runs = 1; - runner.test_options.invariant.depth = 100; + runner.test_options.invariant.depth = 1000; match get_counterexample!(runner, &filter) { CounterExample::Single(_) => panic!("CounterExample should be a sequence."), diff --git a/testdata/default/cheats/SetBlockhash.t.sol b/testdata/default/cheats/SetBlockhash.t.sol index 76ca854b671c..f6c2af5f668b 100644 --- a/testdata/default/cheats/SetBlockhash.t.sol +++ b/testdata/default/cheats/SetBlockhash.t.sol @@ -9,8 +9,8 @@ contract SetBlockhash is DSTest { function testSetBlockhash() public { bytes32 blockHash = 0x1234567890123456789012345678901234567890123456789012345678901234; - vm.setBlockhash(1, blockHash); - bytes32 expected = blockhash(1); + vm.setBlockhash(block.number - 1, blockHash); + bytes32 expected = blockhash(block.number - 1); assertEq(blockHash, expected); } } From 74d419145675dbc6de1b03e5fb3770dbfd2bd910 Mon Sep 17 00:00:00 2001 From: Tuan Date: Sat, 29 Jun 2024 01:00:00 +0700 Subject: [PATCH 13/17] update docs for setBlockhash --- crates/evm/core/src/backend/mod.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index e5f05415232f..422260b05b03 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -331,7 +331,20 @@ pub trait DatabaseExt: Database + DatabaseCommit { Ok(()) } - /// Set the blockhash for the given block number + /// Set the blockhash for a given block number. + /// + /// # Arguments + /// + /// * `number` - The block number to set the blockhash for + /// * `hash` - The blockhash to set + /// + /// # Note + /// + /// This function mimics the EVM limits of the `blockhash` operation: + /// - It sets the blockhash for blocks where `block.number - 256 <= number < block.number` + /// - Setting a blockhash for the current block (number == block.number) has no effect + /// - Setting a blockhash for future blocks (number > block.number) has no effect + /// - Setting a blockhash for blocks older than `block.number - 256` has no effect fn set_blockhash(&mut self, block_number: U256, block_hash: B256); } From 54b963a91efaa76ec40a0dc401e2de8df6f3c53c Mon Sep 17 00:00:00 2001 From: Tuan Date: Sat, 29 Jun 2024 20:53:15 +0700 Subject: [PATCH 14/17] empty From 7a75144cefa774b9fb93dd431c8eae772fa0aa7a Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Tue, 2 Jul 2024 18:09:24 +0700 Subject: [PATCH 15/17] Update crates/forge/tests/it/invariant.rs Co-authored-by: Matthias Seitz --- crates/forge/tests/it/invariant.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/forge/tests/it/invariant.rs b/crates/forge/tests/it/invariant.rs index 06637f8e5616..537569745aaf 100644 --- a/crates/forge/tests/it/invariant.rs +++ b/crates/forge/tests/it/invariant.rs @@ -391,7 +391,7 @@ async fn test_shrink_fail_on_revert() { runner.test_options.fuzz.seed = Some(U256::from(119u32)); runner.test_options.invariant.fail_on_revert = true; runner.test_options.invariant.runs = 1; - runner.test_options.invariant.depth = 1000; + runner.test_options.invariant.depth = 100; match get_counterexample!(runner, &filter) { CounterExample::Single(_) => panic!("CounterExample should be a sequence."), From ec6712d9926d3c881fc2ca2706f7485c6639f5fc Mon Sep 17 00:00:00 2001 From: Tuan Date: Tue, 2 Jul 2024 22:29:51 +0700 Subject: [PATCH 16/17] add docs --- crates/cheatcodes/spec/src/vm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index 5cc4a6e91664..d04313db57e0 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -431,6 +431,7 @@ interface Vm { function getBlobBaseFee() external view returns (uint256 blobBaseFee); /// Set blockhash for the current block. + /// It only sets the blockhash for blocks where `block.number - 256 <= number < block.number`. #[cheatcode(group = Evm, safety = Unsafe)] function setBlockhash(uint256 blockNumber, bytes32 blockHash) external; From 58ff804a6c687419ee8a0b142f963074d1b71d6b Mon Sep 17 00:00:00 2001 From: Tuan Date: Wed, 3 Jul 2024 10:11:07 +0700 Subject: [PATCH 17/17] cargo cheats --- crates/cheatcodes/assets/cheatcodes.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index d6663847a532..33efe36f42af 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -7434,7 +7434,7 @@ { "func": { "id": "setBlockhash", - "description": "Set blockhash for the current block.", + "description": "Set blockhash for the current block.\nIt only sets the blockhash for blocks where `block.number - 256 <= number < block.number`.", "declaration": "function setBlockhash(uint256 blockNumber, bytes32 blockHash) external;", "visibility": "external", "mutability": "",