Skip to main content

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