-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement state and block overrides (#1270)
* Implement state and block overrides * Update comment * apply_block_overrides func * apply_state_overrides func * Use a single func for replacing account storage * Clippy * Address feedback Use Reth's BlockOverrides with saturating_to to convert back to u64 * Test for block overrides * Test for state overrides * Comment tests * Create a fresh working set * Remove box * remove alloy-serde --------- Co-authored-by: eyusufatik <[email protected]>
- Loading branch information
1 parent
31a2b52
commit 1f5782f
Showing
9 changed files
with
422 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,120 @@ | ||
use std::collections::HashMap; | ||
|
||
pub use filter::*; | ||
pub use log_utils::*; | ||
pub use responses::*; | ||
use reth_primitives::{keccak256, Address}; | ||
use reth_rpc_eth_types::{EthApiError, EthResult}; | ||
use reth_rpc_types::state::AccountOverride; | ||
use reth_rpc_types::BlockOverrides; | ||
use revm::Database; | ||
|
||
mod filter; | ||
mod log_utils; | ||
mod responses; | ||
mod tracing_utils; | ||
|
||
pub use filter::*; | ||
pub use log_utils::*; | ||
pub use responses::*; | ||
pub(crate) use tracing_utils::*; | ||
|
||
use crate::db::EvmDb; | ||
#[cfg(feature = "native")] | ||
use crate::primitive_types::BlockEnv; | ||
|
||
#[cfg(feature = "native")] | ||
/// Applies all instances [`AccountOverride`] to the [`EvmDb`]. | ||
pub(crate) fn apply_state_overrides<C: sov_modules_api::Context>( | ||
state_overrides: HashMap<Address, AccountOverride>, | ||
db: &mut EvmDb<C>, | ||
) -> EthResult<()> { | ||
for (address, account_overrides) in state_overrides { | ||
apply_account_override(address, account_overrides, db)?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
#[cfg(feature = "native")] | ||
/// Applies a single [`AccountOverride`] to the [`EvmDb`]. | ||
pub(crate) fn apply_account_override<C: sov_modules_api::Context>( | ||
account: Address, | ||
account_override: AccountOverride, | ||
db: &mut EvmDb<C>, | ||
) -> EthResult<()> { | ||
// we need to fetch the account via the `DatabaseRef` to not update the state of the account, | ||
// which is modified via `Database::basic_ref` | ||
let mut account_info = db.basic(account)?.unwrap_or_default(); | ||
|
||
if let Some(nonce) = account_override.nonce { | ||
account_info.nonce = nonce; | ||
} | ||
if let Some(code) = account_override.code { | ||
account_info.code_hash = keccak256(code); | ||
} | ||
if let Some(balance) = account_override.balance { | ||
account_info.balance = balance; | ||
} | ||
|
||
db.override_account(&account, account_info.into()); | ||
|
||
// We ensure that not both state and state_diff are set. | ||
// If state is set, we must mark the account as "NewlyCreated", so that the old storage | ||
// isn't read from | ||
match (account_override.state, account_override.state_diff) { | ||
(Some(_), Some(_)) => return Err(EthApiError::BothStateAndStateDiffInOverride(account)), | ||
(None, None) => { | ||
// nothing to do | ||
} | ||
(Some(new_account_state), None) => { | ||
db.override_set_account_storage(&account, new_account_state); | ||
} | ||
(None, Some(account_state_diff)) => { | ||
db.override_set_account_storage(&account, account_state_diff); | ||
} | ||
}; | ||
|
||
Ok(()) | ||
} | ||
|
||
#[cfg(feature = "native")] | ||
/// Applies all instances of [`BlockOverride`] to the [`EvmDb`]. | ||
pub(crate) fn apply_block_overrides<C: sov_modules_api::Context>( | ||
block_env: &mut BlockEnv, | ||
block_overrides: &mut BlockOverrides, | ||
db: &mut EvmDb<C>, | ||
) { | ||
if let Some(block_hashes) = block_overrides.block_hash.take() { | ||
// override block hashes | ||
for (num, hash) in block_hashes { | ||
db.override_block_hash(num, hash); | ||
} | ||
} | ||
|
||
let BlockOverrides { | ||
number, | ||
time, | ||
gas_limit, | ||
coinbase, | ||
random, | ||
base_fee, | ||
block_hash: _, | ||
difficulty: _, | ||
} = *block_overrides; | ||
if let Some(number) = number { | ||
block_env.number = number.saturating_to(); | ||
} | ||
if let Some(time) = time { | ||
block_env.timestamp = time; | ||
} | ||
if let Some(gas_limit) = gas_limit { | ||
block_env.gas_limit = gas_limit; | ||
} | ||
if let Some(coinbase) = coinbase { | ||
block_env.coinbase = coinbase; | ||
} | ||
if let Some(random) = random { | ||
block_env.prevrandao = random; | ||
} | ||
if let Some(base_fee) = base_fee { | ||
block_env.basefee = base_fee.saturating_to(); | ||
} | ||
} |
Oops, something went wrong.