Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(anvil): migrate in-house Genesis to alloy-genesis #6970

Merged
merged 6 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/anvil/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ alloy-rpc-trace-types.workspace = true
alloy-providers.workspace = true
alloy-transport.workspace = true
alloy-chains.workspace = true
alloy-genesis.workspace = true

# axum related
axum.workspace = true
Expand Down
9 changes: 7 additions & 2 deletions crates/anvil/src/cmd.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{
config::DEFAULT_MNEMONIC,
eth::{backend::db::SerializableState, pool::transactions::TransactionOrder, EthApi},
genesis::Genesis,
AccountGenerator, Hardfork, NodeConfig, CHAIN_ID,
};
use alloy_genesis::Genesis;
use alloy_primitives::{utils::Unit, U256};
use alloy_signer::coins_bip39::{English, Mnemonic};
use anvil_server::ServerConfig;
Expand Down Expand Up @@ -110,7 +110,7 @@ pub struct NodeArgs {
pub order: TransactionOrder,

/// Initialize the genesis block with the given `genesis.json` file.
#[clap(long, value_name = "PATH", value_parser = Genesis::parse)]
#[clap(long, value_name = "PATH", value_parser= read_genesis_file)]
pub init: Option<Genesis>,

/// This is an alias for both --load-state and --dump-state.
Expand Down Expand Up @@ -672,6 +672,11 @@ impl FromStr for ForkUrl {
}
}

/// Clap's value parser for genesis. Loads a genesis.json file.
fn read_genesis_file(path: &str) -> Result<Genesis, String> {
foundry_common::fs::read_json_file(path.as_ref()).map_err(|err| err.to_string())
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
16 changes: 11 additions & 5 deletions crates/anvil/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use crate::{
fees::{INITIAL_BASE_FEE, INITIAL_GAS_PRICE},
pool::transactions::TransactionOrder,
},
genesis::Genesis,
mem,
mem::in_memory_db::MemDb,
FeeManager, Hardfork,
};
use alloy_genesis::Genesis;
use alloy_primitives::{hex, utils::Unit, U256};
use alloy_providers::provider::TempProvider;
use alloy_rpc_types::BlockNumberOrTag;
Expand Down Expand Up @@ -412,7 +412,7 @@ impl NodeConfig {
/// Returns the base fee to use
pub fn get_base_fee(&self) -> U256 {
self.base_fee
.or_else(|| self.genesis.as_ref().and_then(|g| g.base_fee_per_gas))
.or_else(|| self.genesis.as_ref().and_then(|g| g.base_fee_per_gas.map(U256::from)))
.unwrap_or_else(|| U256::from(INITIAL_BASE_FEE))
}

Expand Down Expand Up @@ -457,7 +457,7 @@ impl NodeConfig {
/// Returns the chain ID to use
pub fn get_chain_id(&self) -> u64 {
self.chain_id
.or_else(|| self.genesis.as_ref().and_then(|g| g.chain_id()))
.or_else(|| self.genesis.as_ref().map(|g| g.config.chain_id))
.unwrap_or(CHAIN_ID)
}

Expand Down Expand Up @@ -532,7 +532,7 @@ impl NodeConfig {
/// Returns the genesis timestamp to use
pub fn get_genesis_timestamp(&self) -> u64 {
self.genesis_timestamp
.or_else(|| self.genesis.as_ref().and_then(|g| g.timestamp))
.or_else(|| self.genesis.as_ref().map(|g| g.timestamp))
.unwrap_or_else(|| duration_since_unix_epoch().as_secs())
}

Expand Down Expand Up @@ -834,7 +834,13 @@ impl NodeConfig {

// if provided use all settings of `genesis.json`
if let Some(ref genesis) = self.genesis {
genesis.apply(&mut env);
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);
}
env.block.number = U256::from(genesis.nonce);
Evalir marked this conversation as resolved.
Show resolved Hide resolved
env.block.coinbase = genesis.coinbase;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this applied these fields conditionally before (see genesis.apply())—but they're not conditional on alloy-genesis. Should check for any default values or just apply them like this?

}

let genesis = GenesisConfig {
Expand Down
35 changes: 23 additions & 12 deletions crates/anvil/src/eth/backend/genesis.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
//! Genesis settings

use crate::{
eth::backend::db::{Db, MaybeHashDatabase},
genesis::Genesis,
};
use crate::eth::backend::db::{Db, MaybeHashDatabase};
use alloy_genesis::{Genesis, GenesisAccount};
use alloy_primitives::{Address, B256, U256};
use foundry_evm::{
backend::{DatabaseError, DatabaseResult, StateSnapshot},
Expand Down Expand Up @@ -57,19 +55,31 @@ impl GenesisConfig {
mut db: RwLockWriteGuard<'_, Box<dyn Db>>,
) -> DatabaseResult<()> {
if let Some(ref genesis) = self.genesis_init {
for (addr, mut acc) in genesis.alloc.accounts.clone() {
for (addr, mut acc) in genesis.alloc.clone() {
let storage = std::mem::take(&mut acc.storage);
// insert all accounts
db.insert_account(addr, acc.into());
db.insert_account(addr, self.genesis_to_account_info(&acc));
// insert all storage values
for (k, v) in storage.iter() {
for (k, v) in storage.unwrap_or_default().iter() {
db.set_storage_at(addr, U256::from_be_bytes(k.0), U256::from_be_bytes(v.0))?;
}
}
}
Ok(())
}

/// Converts a [`GenesisAccount`] to an [`AccountInfo`]
fn genesis_to_account_info(&self, acc: &GenesisAccount) -> AccountInfo {
let GenesisAccount { code, balance, nonce, .. } = acc.clone();
let code = code.map(|code| Bytecode::new_raw(code.to_vec().into()));
AccountInfo {
balance,
nonce: nonce.unwrap_or_default(),
code_hash: code.as_ref().map(|code| code.hash_slow()).unwrap_or(KECCAK_EMPTY),
code,
}
}

/// Returns a database wrapper that points to the genesis and is aware of all provided
/// [AccountInfo]
pub(crate) fn state_db_at_genesis<'a>(
Expand Down Expand Up @@ -113,11 +123,12 @@ impl<'a> DatabaseRef for AtGenesisStateDb<'a> {
}

fn storage_ref(&self, address: Address, index: U256) -> DatabaseResult<U256> {
if let Some(acc) =
self.genesis.as_ref().and_then(|genesis| genesis.alloc.accounts.get(&(address)))
{
let value = acc.storage.get(&B256::from(index)).copied().unwrap_or_default();
return Ok(U256::from_be_bytes(value.0))
if let Some(acc) = self.genesis.as_ref().and_then(|genesis| genesis.alloc.get(&(address))) {
if let Some(storage) = acc.storage.as_ref() {
return Ok(U256::from_be_bytes(
storage.get(&B256::from(index)).copied().unwrap_or_default().0,
))
}
}
self.db.storage_ref(address, index)
}
Expand Down
Loading
Loading