feat(op): init genesis alloc (#7748)

This commit is contained in:
Emilia Hane
2024-04-20 12:55:36 +02:00
committed by GitHub
parent 6728a5518a
commit e35abf8423
4 changed files with 37 additions and 35 deletions

View File

@ -133,7 +133,8 @@ impl Command {
StageId::Execution.to_string(), StageId::Execution.to_string(),
Default::default(), Default::default(),
)?; )?;
insert_genesis_state::<DatabaseEnv>(tx, self.chain.genesis())?; let alloc = &self.chain.genesis().alloc;
insert_genesis_state::<DatabaseEnv>(tx, alloc.len(), alloc.iter())?;
} }
StageEnum::AccountHashing => { StageEnum::AccountHashing => {
tx.clear::<tables::HashedAccounts>()?; tx.clear::<tables::HashedAccounts>()?;
@ -191,7 +192,7 @@ impl Command {
StageId::IndexStorageHistory.to_string(), StageId::IndexStorageHistory.to_string(),
Default::default(), Default::default(),
)?; )?;
insert_genesis_history(&provider_rw, &self.chain.genesis)?; insert_genesis_history(&provider_rw, self.chain.genesis.alloc.iter())?;
} }
StageEnum::TxLookup => { StageEnum::TxLookup => {
tx.clear::<tables::TransactionHashNumbers>()?; tx.clear::<tables::TransactionHashNumbers>()?;

View File

@ -7,8 +7,8 @@ use reth_db::{
}; };
use reth_interfaces::{db::DatabaseError, provider::ProviderResult}; use reth_interfaces::{db::DatabaseError, provider::ProviderResult};
use reth_primitives::{ use reth_primitives::{
stage::StageId, Account, Bytecode, ChainSpec, Receipts, StaticFileSegment, StorageEntry, B256, stage::StageId, Account, Address, Bytecode, ChainSpec, GenesisAccount, Receipts,
U256, StaticFileSegment, StorageEntry, B256, U256,
}; };
use reth_provider::{ use reth_provider::{
bundle_state::{BundleStateInit, RevertsInit}, bundle_state::{BundleStateInit, RevertsInit},
@ -72,17 +72,19 @@ pub fn init_genesis<DB: Database>(factory: ProviderFactory<DB>) -> Result<B256,
debug!("Writing genesis block."); debug!("Writing genesis block.");
let alloc = &genesis.alloc;
// use transaction to insert genesis header // use transaction to insert genesis header
let provider_rw = factory.provider_rw()?; let provider_rw = factory.provider_rw()?;
insert_genesis_hashes(&provider_rw, genesis)?; insert_genesis_hashes(&provider_rw, alloc.iter())?;
insert_genesis_history(&provider_rw, genesis)?; insert_genesis_history(&provider_rw, alloc.iter())?;
// Insert header // Insert header
let tx = provider_rw.into_tx(); let tx = provider_rw.into_tx();
let static_file_provider = factory.static_file_provider(); let static_file_provider = factory.static_file_provider();
insert_genesis_header::<DB>(&tx, &static_file_provider, chain.clone())?; insert_genesis_header::<DB>(&tx, &static_file_provider, chain.clone())?;
insert_genesis_state::<DB>(&tx, genesis)?; insert_genesis_state::<DB>(&tx, alloc.len(), alloc.iter())?;
// insert sync stage // insert sync stage
for stage in StageId::ALL.iter() { for stage in StageId::ALL.iter() {
@ -96,16 +98,16 @@ pub fn init_genesis<DB: Database>(factory: ProviderFactory<DB>) -> Result<B256,
} }
/// Inserts the genesis state into the database. /// Inserts the genesis state into the database.
pub fn insert_genesis_state<DB: Database>( pub fn insert_genesis_state<'a, 'b, DB: Database>(
tx: &<DB as Database>::TXMut, tx: &<DB as Database>::TXMut,
genesis: &reth_primitives::Genesis, capacity: usize,
alloc: impl Iterator<Item = (&'a Address, &'b GenesisAccount)>,
) -> ProviderResult<()> { ) -> ProviderResult<()> {
let capacity = genesis.alloc.len();
let mut state_init: BundleStateInit = HashMap::with_capacity(capacity); let mut state_init: BundleStateInit = HashMap::with_capacity(capacity);
let mut reverts_init = HashMap::with_capacity(capacity); let mut reverts_init = HashMap::with_capacity(capacity);
let mut contracts: HashMap<B256, Bytecode> = HashMap::with_capacity(capacity); let mut contracts: HashMap<B256, Bytecode> = HashMap::with_capacity(capacity);
for (address, account) in &genesis.alloc { for (address, account) in alloc {
let bytecode_hash = if let Some(code) = &account.code { let bytecode_hash = if let Some(code) = &account.code {
let bytecode = Bytecode::new_raw(code.clone()); let bytecode = Bytecode::new_raw(code.clone());
let hash = bytecode.hash_slow(); let hash = bytecode.hash_slow();
@ -163,24 +165,24 @@ pub fn insert_genesis_state<DB: Database>(
} }
/// Inserts hashes for the genesis state. /// Inserts hashes for the genesis state.
pub fn insert_genesis_hashes<DB: Database>( pub fn insert_genesis_hashes<'a, 'b, DB: Database>(
provider: &DatabaseProviderRW<DB>, provider: &DatabaseProviderRW<DB>,
genesis: &reth_primitives::Genesis, alloc: impl Iterator<Item = (&'a Address, &'b GenesisAccount)> + Clone,
) -> ProviderResult<()> { ) -> ProviderResult<()> {
// insert and hash accounts to hashing table // insert and hash accounts to hashing table
let alloc_accounts = genesis let alloc_accounts =
.alloc alloc.clone().map(|(addr, account)| (*addr, Some(Account::from_genesis_account(account))));
.clone()
.into_iter()
.map(|(addr, account)| (addr, Some(Account::from_genesis_account(account))));
provider.insert_account_for_hashing(alloc_accounts)?; provider.insert_account_for_hashing(alloc_accounts)?;
let alloc_storage = genesis.alloc.clone().into_iter().filter_map(|(addr, account)| { let alloc_storage = alloc.filter_map(|(addr, account)| {
// only return Some if there is storage // only return Some if there is storage
account.storage.map(|storage| { account.storage.as_ref().map(|storage| {
( (
addr, *addr,
storage.into_iter().map(|(key, value)| StorageEntry { key, value: value.into() }), storage
.clone()
.into_iter()
.map(|(key, value)| StorageEntry { key, value: value.into() }),
) )
}) })
}); });
@ -190,17 +192,15 @@ pub fn insert_genesis_hashes<DB: Database>(
} }
/// Inserts history indices for genesis accounts and storage. /// Inserts history indices for genesis accounts and storage.
pub fn insert_genesis_history<DB: Database>( pub fn insert_genesis_history<'a, 'b, DB: Database>(
provider: &DatabaseProviderRW<DB>, provider: &DatabaseProviderRW<DB>,
genesis: &reth_primitives::Genesis, alloc: impl Iterator<Item = (&'a Address, &'b GenesisAccount)> + Clone,
) -> ProviderResult<()> { ) -> ProviderResult<()> {
let account_transitions = let account_transitions =
genesis.alloc.keys().map(|addr| (*addr, vec![0])).collect::<BTreeMap<_, _>>(); alloc.clone().map(|(addr, _)| (*addr, vec![0])).collect::<BTreeMap<_, _>>();
provider.insert_account_history_index(account_transitions)?; provider.insert_account_history_index(account_transitions)?;
let storage_transitions = genesis let storage_transitions = alloc
.alloc
.iter()
.filter_map(|(addr, account)| account.storage.as_ref().map(|storage| (addr, storage))) .filter_map(|(addr, account)| account.storage.as_ref().map(|storage| (addr, storage)))
.flat_map(|(addr, storage)| storage.iter().map(|(key, _)| ((*addr, *key), vec![0]))) .flat_map(|(addr, storage)| storage.iter().map(|(key, _)| ((*addr, *key), vec![0])))
.collect::<BTreeMap<_, _>>(); .collect::<BTreeMap<_, _>>();
@ -235,6 +235,8 @@ pub fn insert_genesis_header<DB: Database>(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::sync::Arc;
use super::*; use super::*;
use reth_db::{ use reth_db::{
@ -244,7 +246,7 @@ mod tests {
DatabaseEnv, DatabaseEnv,
}; };
use reth_primitives::{ use reth_primitives::{
Address, Chain, ForkTimestamps, Genesis, GenesisAccount, IntegerList, GOERLI, Address, Chain, ChainSpec, ForkTimestamps, Genesis, GenesisAccount, IntegerList, GOERLI,
GOERLI_GENESIS_HASH, MAINNET, MAINNET_GENESIS_HASH, SEPOLIA, SEPOLIA_GENESIS_HASH, GOERLI_GENESIS_HASH, MAINNET, MAINNET_GENESIS_HASH, SEPOLIA, SEPOLIA_GENESIS_HASH,
}; };
use reth_provider::test_utils::create_test_provider_factory_with_chain_spec; use reth_provider::test_utils::create_test_provider_factory_with_chain_spec;

View File

@ -35,13 +35,13 @@ impl Account {
self.bytecode_hash.map_or(true, |hash| hash == KECCAK_EMPTY) self.bytecode_hash.map_or(true, |hash| hash == KECCAK_EMPTY)
} }
/// Converts [GenesisAccount] to [Account] type /// Makes an [Account] from [GenesisAccount] type
pub fn from_genesis_account(value: GenesisAccount) -> Self { pub fn from_genesis_account(value: &GenesisAccount) -> Self {
Account { Account {
// nonce must exist, so we default to zero when converting a genesis account // nonce must exist, so we default to zero when converting a genesis account
nonce: value.nonce.unwrap_or_default(), nonce: value.nonce.unwrap_or_default(),
balance: value.balance, balance: value.balance,
bytecode_hash: value.code.map(keccak256), bytecode_hash: value.code.as_ref().map(keccak256),
} }
} }

View File

@ -207,9 +207,8 @@ mod tests {
let genesis = chain_spec.genesis(); let genesis = chain_spec.genesis();
let alloc_accounts = genesis let alloc_accounts = genesis
.alloc .alloc
.clone() .iter()
.into_iter() .map(|(addr, account)| (*addr, Some(Account::from_genesis_account(account))));
.map(|(addr, account)| (addr, Some(Account::from_genesis_account(account))));
provider.insert_account_for_hashing(alloc_accounts).unwrap(); provider.insert_account_for_hashing(alloc_accounts).unwrap();
let alloc_storage = genesis.alloc.clone().into_iter().filter_map(|(addr, account)| { let alloc_storage = genesis.alloc.clone().into_iter().filter_map(|(addr, account)| {