diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index 147237a744ef4..208eaa35ec971 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -1744,17 +1744,17 @@ impl EthApi { /// Reset the fork to a fresh forked state, and optionally update the fork config. /// - /// If `forking` is `None` then this will disable forking entirely. + /// If `forking` is `None` then this will disable forking entirely and reset to a fresh state. /// /// Handler for RPC call: `anvil_reset` pub async fn anvil_reset(&self, forking: Option) -> Result<()> { node_info!("anvil_reset"); + self.reset_instance_id(); if let Some(forking) = forking { // if we're resetting the fork we need to reset the instance id - self.reset_instance_id(); self.backend.reset_fork(forking).await } else { - Err(BlockchainError::RpcUnimplemented) + self.backend.reset_to_non_fork().await } } diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index ce5c960c5e2dc..9cbab9ed0b1e7 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -16,11 +16,13 @@ use crate::{ storage::MinedTransactionReceipt, }, notifications::{NewBlockNotification, NewBlockNotifications}, - time::{utc_from_secs, TimeManager}, + time::{duration_since_unix_epoch, utc_from_secs, TimeManager}, validate::TransactionValidator, }, error::{BlockchainError, ErrDetail, InvalidTransactionError}, - fees::{FeeDetails, FeeManager, MIN_SUGGESTED_PRIORITY_FEE}, + fees::{ + FeeDetails, FeeManager, INITIAL_BASE_FEE, INITIAL_GAS_PRICE, MIN_SUGGESTED_PRIORITY_FEE, + }, macros::node_info, pool::transactions::PoolTransaction, util::get_precompiles_for, @@ -77,6 +79,7 @@ use anvil_rpc::error::RpcError; use chrono::Datelike; use eyre::{Context, Result}; use flate2::{read::GzDecoder, write::GzEncoder, Compression}; +use foundry_common::DEV_CHAIN_ID; use foundry_evm::{ backend::{DatabaseError, DatabaseResult, RevertStateSnapshotAction}, constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE, @@ -592,6 +595,96 @@ impl Backend { } } + /// Reset to fresh state + pub async fn reset_to_non_fork(&self) -> Result<(), BlockchainError> { + // Clear the db + let mut db = self.db.write().await; + // clear database + db.clear(); + + let genesis_init = self.genesis.genesis_init.to_owned(); + if let Some(fork) = self.get_fork() { + // Node is currently in fork mode, reintialize the env and db + // Clear the fork storage and set ClientFork to None + fork.clear_cached_storage(); + + self.fork.write().take(); + + // Reset the env and db + { + let mut env = self.env.write(); + + env.clear(); + + // Check if `genesis.json` is provided + if let Some(ref genesis) = genesis_init { + env.cfg.chain_id = genesis.config.chain_id; + env.block.timestamp = U256::from(genesis.timestamp); + if let Some(base_fee) = genesis.base_fee_per_gas { + env.block.basefee = U256::from(base_fee); + } + if let Some(number) = genesis.number { + env.block.number = U256::from(number); + } + env.block.coinbase = genesis.coinbase; + env.block.gas_limit = U256::from(genesis.gas_limit); + } else { + // Anvil defaults for non-forked node. + env.cfg.chain_id = DEV_CHAIN_ID; + env.block = BlockEnv::default(); + env.block.timestamp = U256::from(duration_since_unix_epoch().as_secs()); + env.block.basefee = U256::from(INITIAL_BASE_FEE); + env.block.gas_limit = U256::from(30_000_000); + } + + // Reset time + self.time.reset(env.block.timestamp.to::()); + } + + // genesis accounts + for (address, info) in self.genesis.account_infos() { + db.insert_account(address, info); + } + } else { + // Node is in in-mem-mode. Clear the db and reset the env + // TODO: ENV related changes. + + // genesis accounts + for (account, info) in self.genesis.account_infos() { + db.insert_account(account, info); + } + } + + let node_config = if let Some(ref genesis) = genesis_init { + self.fees.set_base_fee( + genesis.base_fee_per_gas.map(|g| g as u64).unwrap_or(INITIAL_BASE_FEE), + ); + NodeConfig::default() + .with_base_fee(Some( + genesis.base_fee_per_gas.map(|g| g as u64).unwrap_or(INITIAL_BASE_FEE), + )) + .with_gas_price(Some(INITIAL_GAS_PRICE)) + .with_genesis_balance(Unit::ETHER.wei().saturating_mul(U256::from(10000))) + .with_genesis(genesis_init) + } else { + NodeConfig::default() + .with_base_fee(Some(INITIAL_BASE_FEE)) + .with_gas_price(Some(INITIAL_GAS_PRICE)) + .with_genesis_balance(Unit::ETHER.wei().saturating_mul(U256::from(10000))) + }; + + *self.node_config.write().await = node_config; + // reset feess + self.fees.set_gas_price(INITIAL_GAS_PRICE); + // Clear the state + *self.blockchain.storage.write() = BlockchainStorage::empty(); + self.states.write().clear(); + + // Reset genensis alloc + self.genesis.apply_genesis_json_alloc(db)?; + + Ok(()) + } /// Returns the `TimeManager` responsible for timestamps pub fn time(&self) -> &TimeManager { &self.time