anvil/eth/backend/
genesis.rs

1//! Genesis settings
2
3use crate::eth::backend::db::Db;
4use alloy_genesis::{Genesis, GenesisAccount};
5use alloy_primitives::{Address, U256};
6use foundry_evm::{
7    backend::DatabaseResult,
8    revm::primitives::{AccountInfo, Bytecode, KECCAK_EMPTY},
9};
10use tokio::sync::RwLockWriteGuard;
11
12/// Genesis settings
13#[derive(Clone, Debug, Default)]
14pub struct GenesisConfig {
15    /// The initial number for the genesis block
16    pub number: u64,
17    /// The initial timestamp for the genesis block
18    pub timestamp: u64,
19    /// Balance for genesis accounts
20    pub balance: U256,
21    /// All accounts that should be initialised at genesis
22    pub accounts: Vec<Address>,
23    /// The `genesis.json` if provided
24    pub genesis_init: Option<Genesis>,
25}
26
27impl GenesisConfig {
28    /// Returns fresh `AccountInfo`s for the configured `accounts`
29    pub fn account_infos(&self) -> impl Iterator<Item = (Address, AccountInfo)> + '_ {
30        self.accounts.iter().copied().map(|address| {
31            let info = AccountInfo {
32                balance: self.balance,
33                code_hash: KECCAK_EMPTY,
34                // we set this to empty so `Database::code_by_hash` doesn't get called
35                code: Some(Default::default()),
36                nonce: 0,
37            };
38            (address, info)
39        })
40    }
41
42    /// If an initial `genesis.json` was provided, this applies the account alloc to the db
43    pub fn apply_genesis_json_alloc(
44        &self,
45        mut db: RwLockWriteGuard<'_, Box<dyn Db>>,
46    ) -> DatabaseResult<()> {
47        if let Some(ref genesis) = self.genesis_init {
48            for (addr, mut acc) in genesis.alloc.clone() {
49                let storage = std::mem::take(&mut acc.storage);
50                // insert all accounts
51                db.insert_account(addr, self.genesis_to_account_info(&acc));
52                // insert all storage values
53                for (k, v) in &storage.unwrap_or_default() {
54                    db.set_storage_at(addr, *k, *v)?;
55                }
56            }
57        }
58        Ok(())
59    }
60
61    /// Converts a [`GenesisAccount`] to an [`AccountInfo`]
62    fn genesis_to_account_info(&self, acc: &GenesisAccount) -> AccountInfo {
63        let GenesisAccount { code, balance, nonce, .. } = acc.clone();
64        let code = code.map(Bytecode::new_raw);
65        AccountInfo {
66            balance,
67            nonce: nonce.unwrap_or_default(),
68            code_hash: code.as_ref().map(|code| code.hash_slow()).unwrap_or(KECCAK_EMPTY),
69            code,
70        }
71    }
72}