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