diff --git a/.github/workflows/book.yml b/.github/workflows/book.yml index 3f3d90367a..6ed8042224 100644 --- a/.github/workflows/book.yml +++ b/.github/workflows/book.yml @@ -1,4 +1,9 @@ name: book + +concurrency: + cancel-in-progress: true + group: ${{github.workflow}}-${{github.ref}} + on: push: branches: [main] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02d613b233..be5e3a5d98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,9 @@ name: Tests +concurrency: + cancel-in-progress: true + group: ${{github.workflow}}-${{github.ref}} + on: push: branches: [main, "release/**"] diff --git a/.github/workflows/ethereum-tests.yml b/.github/workflows/ethereum-tests.yml index 02a0863282..032a632346 100644 --- a/.github/workflows/ethereum-tests.yml +++ b/.github/workflows/ethereum-tests.yml @@ -1,10 +1,15 @@ +name: Ethereum Tests + +concurrency: + cancel-in-progress: true + group: ${{github.workflow}}-${{github.ref}} + on: push: branches: [main, "release/**"] pull_request: branches: [main, "release/**"] -name: Ethereum Tests jobs: tests-stable: diff --git a/crates/interpreter/src/gas/calc.rs b/crates/interpreter/src/gas/calc.rs index 1258b82365..2208c0b7c2 100644 --- a/crates/interpreter/src/gas/calc.rs +++ b/crates/interpreter/src/gas/calc.rs @@ -290,7 +290,7 @@ pub fn call_cost( } #[inline] -pub fn hot_cold_cost(is_cold: bool, regular_value: u64) -> u64 { +pub fn warm_cold_cost(is_cold: bool, regular_value: u64) -> u64 { if SPEC::enabled(BERLIN) { if is_cold { COLD_ACCOUNT_ACCESS_COST diff --git a/crates/interpreter/src/host/dummy.rs b/crates/interpreter/src/host/dummy.rs index c2df6b2f65..394bd26fe2 100644 --- a/crates/interpreter/src/host/dummy.rs +++ b/crates/interpreter/src/host/dummy.rs @@ -110,7 +110,7 @@ impl Host for DummyHost { fn tload(&mut self, _address: B160, index: U256) -> U256 { self.transient_storage .get(&index) - .cloned() + .copied() .unwrap_or_default() } diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs index aaf7aff98d..3a659264b3 100644 --- a/crates/primitives/src/env.rs +++ b/crates/primitives/src/env.rs @@ -604,7 +604,10 @@ impl Env { /// Validate transaction against state. #[inline] - pub fn validate_tx_against_state(&self, account: &Account) -> Result<(), InvalidTransaction> { + pub fn validate_tx_against_state( + &self, + account: &mut Account, + ) -> Result<(), InvalidTransaction> { // EIP-3607: Reject transactions from senders with deployed code // This EIP is introduced after london but there was no collision in past // so we can leave it enabled always @@ -647,11 +650,16 @@ impl Env { // Check if account has enough balance for gas_limit*gas_price and value transfer. // Transfer will be done inside `*_inner` functions. - if !self.cfg.is_balance_check_disabled() && balance_check > account.info.balance { - return Err(InvalidTransaction::LackOfFundForMaxFee { - fee: self.tx.gas_limit, - balance: account.info.balance, - }); + if balance_check > account.info.balance { + if self.cfg.is_balance_check_disabled() { + // Add transaction cost to balance to ensure execution doesn't fail. + account.info.balance = balance_check; + } else { + return Err(InvalidTransaction::LackOfFundForMaxFee { + fee: self.tx.gas_limit, + balance: account.info.balance, + }); + } } Ok(()) diff --git a/crates/primitives/src/state.rs b/crates/primitives/src/state.rs index c562cfb5a0..3e9b0aa604 100644 --- a/crates/primitives/src/state.rs +++ b/crates/primitives/src/state.rs @@ -5,11 +5,11 @@ use hashbrown::HashMap; #[derive(Debug, Clone, Eq, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Account { - /// Balance of the account. + /// Balance, nonce, and code. pub info: AccountInfo, - /// storage cache + /// Storage cache pub storage: HashMap, - // Account status flags. + /// Account status flags. pub status: AccountStatus, } @@ -173,7 +173,7 @@ pub struct AccountInfo { /// code hash, pub code_hash: B256, /// code: if None, `code_by_hash` will be used to fetch it if code needs to be loaded from - /// inside of revm. + /// inside of `revm`. pub code: Option, } diff --git a/crates/revm/src/db/states/account_status.rs b/crates/revm/src/db/states/account_status.rs index 25d8d2c396..f75ae3a61e 100644 --- a/crates/revm/src/db/states/account_status.rs +++ b/crates/revm/src/db/states/account_status.rs @@ -15,8 +15,7 @@ pub enum AccountStatus { } impl AccountStatus { - /// Transition to other state while preserving - /// invariance of this state. + /// Transition to other state while preserving invariance of this state. /// /// It this account was Destroyed and other account is not: /// we should mark extended account as destroyed too. @@ -26,7 +25,7 @@ impl AccountStatus { /// If both account are not destroyed and if this account is in memory: /// this means that extended account is in memory too. /// - /// otherwise if both are destroyed or other is destroyed: + /// Otherwise, if both are destroyed or other is destroyed: /// set other status to extended account. pub fn transition(&mut self, other: Self) { *self = match (self.was_destroyed(), other.was_destroyed()) { @@ -69,7 +68,7 @@ impl AccountStatus { } /// Account is modified but not destroyed. - /// This means that some of storage values can be found in both + /// This means that some storage values can be found in both /// memory and database. pub fn modified_but_not_destroyed(&self) -> bool { matches!(self, AccountStatus::Changed | AccountStatus::InMemoryChange) diff --git a/crates/revm/src/db/states/bundle_account.rs b/crates/revm/src/db/states/bundle_account.rs index d81226a693..38c0831c76 100644 --- a/crates/revm/src/db/states/bundle_account.rs +++ b/crates/revm/src/db/states/bundle_account.rs @@ -50,9 +50,9 @@ impl BundleAccount { 1 + self.storage.len() } - /// Return storage slot if it exist. + /// Return storage slot if it exists. /// - /// In case we know that account is destroyed return `Some(U256::ZERO)` + /// In case we know that account is newly created or destroyed, return `Some(U256::ZERO)` pub fn storage_slot(&self, slot: U256) -> Option { let slot = self.storage.get(&slot).map(|s| s.present_value); if slot.is_some() { diff --git a/crates/revm/src/db/states/bundle_state.rs b/crates/revm/src/db/states/bundle_state.rs index f2965a51a0..baa5e570a0 100644 --- a/crates/revm/src/db/states/bundle_state.rs +++ b/crates/revm/src/db/states/bundle_state.rs @@ -869,7 +869,7 @@ mod tests { } #[test] - fn extend_on_destoyed_values() { + fn extend_on_destroyed_values() { let base_bundle1 = test_bundle1(); let base_bundle2 = test_bundle2(); diff --git a/crates/revm/src/db/states/cache_account.rs b/crates/revm/src/db/states/cache_account.rs index 29d7b81a2a..f6b85436c6 100644 --- a/crates/revm/src/db/states/cache_account.rs +++ b/crates/revm/src/db/states/cache_account.rs @@ -155,9 +155,9 @@ impl CacheAccount { }) } - /// Touche empty account, related to EIP-161 state clear. + /// Touch empty account, related to EIP-161 state clear. /// - /// This account returns Transition that is used to create the BundleState. + /// This account returns the Transition that is used to create the BundleState. pub fn touch_empty_eip161(&mut self) -> Option { let previous_status = self.status; @@ -169,7 +169,7 @@ impl CacheAccount { AccountStatus::InMemoryChange | AccountStatus::Destroyed | AccountStatus::LoadedEmptyEIP161 => { - // account can be created empty them touched. + // account can be created empty then touched. AccountStatus::Destroyed } AccountStatus::LoadedNotExisting => { @@ -344,7 +344,7 @@ impl CacheAccount { ) } - /// Drain balance from account and return transition and drained amount + /// Drain balance from account and return drained amount and transition. /// /// Used for DAO hardfork transition. pub fn drain_balance(&mut self) -> (u128, TransitionAccount) { diff --git a/crates/revm/src/db/states/state.rs b/crates/revm/src/db/states/state.rs index 140145c7c5..7fba19fa20 100644 --- a/crates/revm/src/db/states/state.rs +++ b/crates/revm/src/db/states/state.rs @@ -269,7 +269,7 @@ impl Database for State { } fn block_hash(&mut self, number: U256) -> Result { - // block number is never biger then u64::MAX. + // block number is never bigger then u64::MAX. let u64num: u64 = number.to(); match self.block_hashes.entry(u64num) { btree_map::Entry::Occupied(entry) => Ok(*entry.get()), diff --git a/crates/revm/src/db/states/transition_account.rs b/crates/revm/src/db/states/transition_account.rs index fc9e4eed80..c8fea5eb1f 100644 --- a/crates/revm/src/db/states/transition_account.rs +++ b/crates/revm/src/db/states/transition_account.rs @@ -3,7 +3,7 @@ use crate::db::AccountStatus; use revm_interpreter::primitives::{hash_map, AccountInfo, Bytecode, B256}; /// Account Created when EVM state is merged to cache state. -/// And it is send to Block state. +/// And it is sent to Block state. /// /// It is used when block state gets merged to bundle state to /// create needed Reverts. @@ -53,8 +53,8 @@ impl TransitionAccount { None } - /// Update new values of transition. Don't override old values - /// both account info and old storages need to be left intact. + /// Update new values of transition. Don't override old values. + /// Both account info and old storages need to be left intact. pub fn update(&mut self, other: Self) { self.info = other.info.clone(); self.status = other.status; diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 5d674716c3..ba7291603b 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -83,7 +83,7 @@ pub trait Transact { impl<'a, DB: Database> EVMData<'a, DB> { /// Load access list for berlin hardfork. /// - /// Loading of accounts/storages is needed to make them hot. + /// Loading of accounts/storages is needed to make them warm. #[inline] fn load_access_list(&mut self) -> Result<(), EVMError> { for (address, slots) in self.env.tx.access_list.iter() { @@ -472,7 +472,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB, CreateScheme::Create2 { salt } => create2_address(inputs.caller, code_hash, salt), }; - // Load account so it needs to be marked as hot for access list. + // Load account so it needs to be marked as warm for access list. if self .data .journaled_state @@ -891,7 +891,7 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host } fn sload(&mut self, address: B160, index: U256) -> Option<(U256, bool)> { - // account is always hot. reference on that statement https://eips.ethereum.org/EIPS/eip-2929 see `Note 2:` + // account is always warm. reference on that statement https://eips.ethereum.org/EIPS/eip-2929 see `Note 2:` self.data .journaled_state .sload(address, index, self.data.db) diff --git a/crates/revm/src/inspector/customprinter.rs b/crates/revm/src/inspector/customprinter.rs index c9ccf6ec03..44881be409 100644 --- a/crates/revm/src/inspector/customprinter.rs +++ b/crates/revm/src/inspector/customprinter.rs @@ -141,7 +141,7 @@ mod test { balance: "0x100c5d668240db8e00".parse().unwrap(), code_hash: crate::primitives::keccak256(&code), code: Some(crate::primitives::Bytecode::new_raw(code.clone())), - nonce: "1".parse().unwrap(), + nonce: 1, }; let callee = hex_literal::hex!("5fdcca53617f4d2b9134b29090c87d01058e27e9"); database.insert_account_info(crate::primitives::B160(callee), acc_info); diff --git a/crates/revm/src/journaled_state.rs b/crates/revm/src/journaled_state.rs index c866f38ac1..8e8c9c1d77 100644 --- a/crates/revm/src/journaled_state.rs +++ b/crates/revm/src/journaled_state.rs @@ -32,7 +32,7 @@ pub struct JournaledState { #[derive(Debug, Clone, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum JournalEntry { - /// Used to mark account that is hot inside EVM in regards to EIP-2929 AccessList. + /// Used to mark account that is warm inside EVM in regards to EIP-2929 AccessList. /// Action: We will add Account to state. /// Revert: we will remove account from state. AccountLoaded { address: B160 }, @@ -64,9 +64,9 @@ pub enum JournalEntry { /// Actions: Mark account as created /// Revert: Unmart account as created and reset nonce to zero. AccountCreated { address: B160 }, - /// It is used to track both storage change and hot load of storage slot. For hot load in regard + /// It is used to track both storage change and warm load of storage slot. For warm load in regard /// to EIP-2929 AccessList had_value will be None - /// Action: Storage change or hot load + /// Action: Storage change or warm load /// Revert: Revert to previous value or remove slot from storage StorageChange { address: B160, @@ -153,8 +153,8 @@ impl JournaledState { self.depth as u64 } - /// use it only if you know that acc is hot - /// Assume account is hot + /// use it only if you know that acc is warm + /// Assume account is warm pub fn set_code(&mut self, address: B160, code: Bytecode) { let account = self.state.get_mut(&address).unwrap(); Self::touch_account(self.journal.last_mut().unwrap(), &address, account); @@ -231,7 +231,7 @@ impl JournaledState { /// Create account or return false if collision is detected. /// /// There are few steps done: - /// 1. Make created account hot loaded (AccessList) and this should + /// 1. Make created account warm loaded (AccessList) and this should /// be done before subroutine checkpoint is created. /// 2. Check if there is collision of newly created account with existing one. /// 3. Mark created account as created. @@ -356,7 +356,7 @@ impl JournaledState { had_balance, } => { let account = state.get_mut(&address).unwrap(); - // set previous ste of selfdestructed flag. as there could be multiple + // set previous state of selfdestructed flag, as there could be multiple // selfdestructs in one transaction. if was_destroyed { // flag is still selfdestructed @@ -373,7 +373,7 @@ impl JournaledState { } } JournalEntry::BalanceTransfer { from, to, balance } => { - // we don't need to check overflow and underflow when adding sub subtracting the balance. + // we don't need to check overflow and underflow when adding and subtracting the balance. let from = state.get_mut(&from).unwrap(); from.info.balance += balance; let to = state.get_mut(&to).unwrap(); @@ -574,7 +574,7 @@ impl JournaledState { Ok(account) } - /// load account into memory. return if it is cold or hot accessed + /// load account into memory. return if it is cold or warm accessed pub fn load_account( &mut self, address: B160, @@ -595,7 +595,7 @@ impl JournaledState { .unwrap() .push(JournalEntry::AccountLoaded { address }); - // precompiles are hot loaded so we need to take that into account + // precompiles are warm loaded so we need to take that into account let is_cold = !is_precompile(address, self.num_of_precompiles); (vac.insert(account), is_cold) @@ -647,7 +647,7 @@ impl JournaledState { key: U256, db: &mut DB, ) -> Result<(U256, bool), DB::Error> { - let account = self.state.get_mut(&address).unwrap(); // assume acc is hot + let account = self.state.get_mut(&address).unwrap(); // assume acc is warm // only if account is created in this tx we can assume that storage is empty. let is_newly_created = account.is_created(); let load = match account.storage.entry(key) { @@ -717,7 +717,7 @@ impl JournaledState { pub fn tload(&mut self, address: B160, key: U256) -> U256 { self.transient_storage .get(&(address, key)) - .cloned() + .copied() .unwrap_or_default() } diff --git a/documentation/src/crates/interpreter.md b/documentation/src/crates/interpreter.md index 10fcca0f6c..6c91bf1cce 100644 --- a/documentation/src/crates/interpreter.md +++ b/documentation/src/crates/interpreter.md @@ -10,7 +10,6 @@ Modules: - [instruction_result](./interpreter/instruction_result.md): This module contains definitions related to the result of instruction execution. - [instructions](./interpreter/instructions.md): This module includes the definitions of the EVM opcodes (instructions). - External Crates: - [alloc](https://doc.rust-lang.org/alloc/): The alloc crate is used to provide the ability to allocate memory on the heap. It's a part of Rust's standard library that can be used in environments without a full host OS. diff --git a/documentation/src/crates/primitives/environment.md b/documentation/src/crates/primitives/environment.md index 8c5469bd3c..8e33181527 100644 --- a/documentation/src/crates/primitives/environment.md +++ b/documentation/src/crates/primitives/environment.md @@ -1,5 +1,5 @@ # Environment -A significant module that manages the execution environment of the EVM. The module containts objects and methods associated with processing transactions and blocks within such a blockchain environment. It defines several structures: `Env`, `BlockEnv`, `TxEnv`, `CfgEnv`, `TransactTo`, and `CreateScheme`. These structures contain various fields representing the block data, transaction data, environmental configurations, transaction recipient details, and the method of contract creation respectively. +A significant module that manages the execution environment of the EVM. The module contains objects and methods associated with processing transactions and blocks within such a blockchain environment. It defines several structures: `Env`, `BlockEnv`, `TxEnv`, `CfgEnv`, `TransactTo`, and `CreateScheme`. These structures contain various fields representing the block data, transaction data, environmental configurations, transaction recipient details, and the method of contract creation respectively. The `Env` structure, which encapsulates the environment of the EVM, contains methods for calculating effective gas prices and for validating block and transaction data. It also checks transactions against the current state of the associated account, which is necessary to validate the transaction's nonce and the account balance. Various Ethereum Improvement Proposals (EIPs) are also considered in these validations, such as [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) for the base fee, [EIP-3607](https://eips.ethereum.org/EIPS/eip-3607) for rejecting transactions from senders with deployed code, and [EIP-3298](https://eips.ethereum.org/EIPS/eip-3298) for disabling gas refunds. The code is structured to include optional features and to allow for changes in the EVM specifications. diff --git a/documentation/src/crates/revm/host_trait.md b/documentation/src/crates/revm/host_trait.md index 697a2b8126..ba4c7be726 100644 --- a/documentation/src/crates/revm/host_trait.md +++ b/documentation/src/crates/revm/host_trait.md @@ -24,11 +24,11 @@ The [`EVMImpl`](./evm_impl.md) struct implements this `Host` trait. This method retrieves the balance of an Ethereum account given its address. It returns a tuple containing the balance and a boolean indicating whether the account was "cold" (accessed for the first time in the current transaction). -- `code` +- `code` This method retrieves the bytecode of a given address. It returns a tuple containing the bytecode and a boolean indicating whether the account was "cold". -- `code_hash` +- `code_hash` This method retrieves the code_hash at a given address. It returns a tuple containing the hash and a boolean indicating whether the account was "cold". @@ -44,7 +44,7 @@ The [`EVMImpl`](./evm_impl.md) struct implements this `Host` trait. This method is used to create log entries, which are a way for contracts to produce output that external observers (like dapps or the frontend of a blockchain explorer) can listen for and react to. -- `selfdestruct` +- `selfdestruct` The selfdestruct method attempts to terminate the specified address, transferring its remaining balance to a given target address. If the INSPECT constant is true, the self-destruction event is observed or logged via an inspector. The method returns an Option, encapsulating the outcome of the operation: Some(SelfDestructResult) on success and None if an error occurs, with the error being stored internally for later reference. diff --git a/documentation/src/crates/revm/journaled_state.md b/documentation/src/crates/revm/journaled_state.md index 853f43d5d1..a553b67836 100644 --- a/documentation/src/crates/revm/journaled_state.md +++ b/documentation/src/crates/revm/journaled_state.md @@ -45,12 +45,12 @@ This module is built around the `JournaledState` structure, which encapsulates t - `load_account` This method loads an account's information into memory and returns whether the account was - cold or hot accessed. + cold or warm accessed. - `load_account_exist` This method checks whether an account exists or not. It returns whether the account was - cold or hot accessed and whether it exists. + cold or warm accessed and whether it exists. - `load_code` @@ -85,7 +85,7 @@ The [EIP-161](https://eips.ethereum.org/EIPS/eip-161) aims to optimize Ethereum' - Account Creation: During the creation of an account (whether by transactions or the `CREATE` operation), the nonce of the new account is incremented by one before the execution of the initialization code. For most networks, the starting value is 1, but this may vary for test networks with non-zero default starting nonces. -- Call and Suicide Charges: Prior to [EIP-161](https://eips.ethereum.org/EIPS/eip-161), a gas charge of 25,000 was levied for `CALL` and `SUICIDE` operations if the destination account did not exist. With [EIP-161](https://eips.ethereum.org/EIPS/eip-161), this charge is only applied if the operation transfers more than zero value and the destination account is dead (non-existent or empty). +- CALL and SELFDESTRUCT Charges: Prior to [EIP-161](https://eips.ethereum.org/EIPS/eip-161), a gas charge of 25,000 was levied for `CALL` and `SELFDESTRUCT` operations if the destination account did not exist. With [EIP-161](https://eips.ethereum.org/EIPS/eip-161), this charge is only applied if the operation transfers more than zero value and the destination account is dead (non-existent or empty). - Existence of Empty Accounts: An account cannot change its state from non-existent to existent-but-empty. If an operation would result in this, the account remains non-existent. @@ -99,7 +99,7 @@ These rules have an impact on how state is managed within the [EIP-161](https:// The rationale behind [EIP-161](https://eips.ethereum.org/EIPS/eip-161) is to optimize the Ethereum state management by getting rid of unnecessary data. Prior to this change, it was possible for the state trie to become bloated with empty accounts. This bloating resulted in increased storage requirements and slower processing times for Ethereum nodes. -By removing these empty accounts, the size of the state trie can be reduced, leading to improvements in the performance of Ethereum nodes. Additionally, the changes regarding the gas costs for `CALL` and `SUICIDE` operations add a new level of nuance to the Ethereum gas model, further optimizing transaction processing. +By removing these empty accounts, the size of the state trie can be reduced, leading to improvements in the performance of Ethereum nodes. Additionally, the changes regarding the gas costs for `CALL` and `SELFDESTRUCT` operations add a new level of nuance to the Ethereum gas model, further optimizing transaction processing. [EIP-161](https://eips.ethereum.org/EIPS/eip-161) has a significant impact on the state management of Ethereum, and thus is highly relevant to the JournaledState module of the revm crate. The operations defined in this module, such as loading accounts, self-destructing accounts, and changing storage, must all conform to the rules defined in [EIP-161](https://eips.ethereum.org/EIPS/eip-161).