From bf3264b2579310840bffecfc74113c1529084bbb Mon Sep 17 00:00:00 2001 From: "Supernovahs.eth" <91280922+supernovahs@users.noreply.github.com> Date: Sat, 20 Jan 2024 15:38:32 +0530 Subject: [PATCH] feat: use alloy genesis now (#6135) Co-authored-by: Matthias Seitz --- Cargo.lock | 30 +- Cargo.toml | 5 +- bin/reth/src/init.rs | 7 +- crates/consensus/beacon/Cargo.toml | 1 + crates/consensus/beacon/src/engine/mod.rs | 5 +- crates/net/network/Cargo.toml | 1 + crates/net/network/src/transactions/mod.rs | 10 +- .../tests/it/clique/clique_middleware.rs | 4 +- crates/net/network/tests/it/clique/geth.rs | 16 +- crates/net/network/tests/it/connect.rs | 2 +- crates/net/network/tests/it/geth.rs | 13 +- crates/primitives/Cargo.toml | 2 +- crates/primitives/src/account.rs | 14 +- crates/primitives/src/genesis.rs | 1597 ++--------------- crates/primitives/src/lib.rs | 4 +- crates/trie/src/proof.rs | 7 +- 16 files changed, 257 insertions(+), 1461 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 87538a996ac9..c4b5312e8c78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,6 +170,16 @@ dependencies = [ "winnow", ] +[[package]] +name = "alloy-genesis" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy#42778ba44fbf9fdcfd44de81436f65d73e70ede2" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types", + "serde", +] + [[package]] name = "alloy-json-abi" version = "0.6.0" @@ -182,6 +192,18 @@ dependencies = [ "serde_json", ] +[[package]] +name = "alloy-node-bindings" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy#42778ba44fbf9fdcfd44de81436f65d73e70ede2" +dependencies = [ + "alloy-genesis", + "alloy-primitives", + "k256", + "serde_json", + "tempfile", +] + [[package]] name = "alloy-primitives" version = "0.6.0" @@ -234,7 +256,7 @@ dependencies = [ [[package]] name = "alloy-rpc-engine-types" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#61142b3fee367a9aee087d6cfac8e57abaaa2eb2" +source = "git+https://github.com/alloy-rs/alloy#42778ba44fbf9fdcfd44de81436f65d73e70ede2" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -249,7 +271,7 @@ dependencies = [ [[package]] name = "alloy-rpc-trace-types" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#61142b3fee367a9aee087d6cfac8e57abaaa2eb2" +source = "git+https://github.com/alloy-rs/alloy#42778ba44fbf9fdcfd44de81436f65d73e70ede2" dependencies = [ "alloy-primitives", "alloy-rpc-types", @@ -260,7 +282,7 @@ dependencies = [ [[package]] name = "alloy-rpc-types" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#61142b3fee367a9aee087d6cfac8e57abaaa2eb2" +source = "git+https://github.com/alloy-rs/alloy#42778ba44fbf9fdcfd44de81436f65d73e70ede2" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -6287,6 +6309,7 @@ dependencies = [ name = "reth-network" version = "0.1.0-alpha.15" dependencies = [ + "alloy-node-bindings", "alloy-rlp", "aquamarine", "async-trait", @@ -6453,6 +6476,7 @@ version = "0.1.0-alpha.15" dependencies = [ "ahash", "alloy-chains", + "alloy-genesis", "alloy-primitives", "alloy-rlp", "alloy-trie", diff --git a/Cargo.toml b/Cargo.toml index 09abc80c91fa..f07c19cd0784 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -169,14 +169,17 @@ alloy-primitives = "0.6" alloy-dyn-abi = "0.6" alloy-sol-types = "0.6" alloy-rlp = "0.3" +alloy-trie = "0.2" alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy" } alloy-rpc-trace-types = { git = "https://github.com/alloy-rs/alloy" } alloy-rpc-engine-types = { git = "https://github.com/alloy-rs/alloy" } -alloy-trie = "0.2" +alloy-genesis = { git = "https://github.com/alloy-rs/alloy"} +alloy-node-bindings = {git = "https://github.com/alloy-rs/alloy"} ethers-core = { version = "2.0", default-features = false } ethers-providers = { version = "2.0", default-features = false } ethers-signers = { version = "2.0", default-features = false } ethers-middleware = { version = "2.0", default-features = false } + discv5 = { git = "https://github.com/sigp/discv5", rev = "f289bbd4c57d499bb1bdb393af3c249600a1c662" } igd = { git = "https://github.com/stevefan1999-personal/rust-igd", rev = "c2d1f83eb1612a462962453cb0703bc93258b173" } diff --git a/bin/reth/src/init.rs b/bin/reth/src/init.rs index 77a7be95067b..de75bf9d5483 100644 --- a/bin/reth/src/init.rs +++ b/bin/reth/src/init.rs @@ -164,8 +164,11 @@ pub fn insert_genesis_hashes( genesis: &reth_primitives::Genesis, ) -> ProviderResult<()> { // insert and hash accounts to hashing table - let alloc_accounts = - genesis.alloc.clone().into_iter().map(|(addr, account)| (addr, Some(account.into()))); + let alloc_accounts = genesis + .alloc + .clone() + .into_iter() + .map(|(addr, account)| (addr, Some(Account::from_genesis_account(account)))); provider.insert_account_for_hashing(alloc_accounts)?; let alloc_storage = genesis.alloc.clone().into_iter().filter_map(|(addr, account)| { diff --git a/crates/consensus/beacon/Cargo.toml b/crates/consensus/beacon/Cargo.toml index ac8b903c8054..ef6242edcf36 100644 --- a/crates/consensus/beacon/Cargo.toml +++ b/crates/consensus/beacon/Cargo.toml @@ -45,6 +45,7 @@ cfg-if = "1.0.0" [dev-dependencies] # reth reth-payload-builder = { workspace = true, features = ["test-utils"] } +reth-primitives = { workspace = true, features = ["test-utils"] } reth-interfaces = { workspace = true, features = ["test-utils"] } reth-stages = { workspace = true, features = ["test-utils"] } reth-blockchain-tree = { workspace = true, features = ["test-utils"] } diff --git a/crates/consensus/beacon/src/engine/mod.rs b/crates/consensus/beacon/src/engine/mod.rs index adf00530aad8..89c39f0c1e29 100644 --- a/crates/consensus/beacon/src/engine/mod.rs +++ b/crates/consensus/beacon/src/engine/mod.rs @@ -2346,7 +2346,10 @@ mod tests { mod new_payload { use super::*; use reth_interfaces::test_utils::{generators, generators::random_block}; - use reth_primitives::{Genesis, GenesisAllocator, Hardfork, U256}; + use reth_primitives::{ + genesis::{Genesis, GenesisAllocator}, + Hardfork, U256, + }; use reth_provider::test_utils::blocks::BlockChainTestData; #[tokio::test] diff --git a/crates/net/network/Cargo.toml b/crates/net/network/Cargo.toml index 35704f58054a..f19ee43262dc 100644 --- a/crates/net/network/Cargo.toml +++ b/crates/net/network/Cargo.toml @@ -84,6 +84,7 @@ reth-provider = { workspace = true, features = ["test-utils"] } reth-tracing.workspace = true reth-transaction-pool = { workspace = true, features = ["test-utils"] } +alloy-node-bindings.workspace = true ethers-core = { workspace = true, default-features = false } ethers-providers = { workspace = true, default-features = false, features = ["ws"] } ethers-signers = { workspace = true, default-features = false } diff --git a/crates/net/network/src/transactions/mod.rs b/crates/net/network/src/transactions/mod.rs index c549584c2cbf..79fcff1eff5e 100644 --- a/crates/net/network/src/transactions/mod.rs +++ b/crates/net/network/src/transactions/mod.rs @@ -1258,23 +1258,25 @@ mod tests { use super::*; use crate::{test_utils::Testnet, NetworkConfigBuilder, NetworkManager}; use alloy_rlp::Decodable; + use fetcher::MAX_ALTERNATIVE_PEERS_PER_TX; use futures::FutureExt; use reth_interfaces::sync::{NetworkSyncUpdater, SyncState}; use reth_network_api::NetworkInfo; use reth_primitives::hex; use reth_provider::test_utils::NoopProvider; - use reth_transaction_pool::test_utils::{testing_pool, MockTransaction}; use secp256k1::SecretKey; use std::{future::poll_fn, hash}; - use fetcher::MAX_ALTERNATIVE_PEERS_PER_TX; - async fn new_tx_manager() -> TransactionsManager { let secret_key = SecretKey::new(&mut rand::thread_rng()); let client = NoopProvider::default(); - let config = NetworkConfigBuilder::new(secret_key).disable_discovery().build(client); + let config = NetworkConfigBuilder::new(secret_key) + // let OS choose port + .listener_port(0) + .disable_discovery() + .build(client); let pool = testing_pool(); diff --git a/crates/net/network/tests/it/clique/clique_middleware.rs b/crates/net/network/tests/it/clique/clique_middleware.rs index 4d3d1cad4014..7e21a20bcc0d 100644 --- a/crates/net/network/tests/it/clique/clique_middleware.rs +++ b/crates/net/network/tests/it/clique/clique_middleware.rs @@ -91,7 +91,7 @@ pub trait CliqueMiddleware: Send + Sync + Middleware { Ok(()) } - /// Returns the genesis block of the [`Geth`](ethers_core::utils::Geth) instance by calling + /// Returns the genesis block of the [`Geth`](alloy_node_bindings::Geth) instance by calling /// geth's `eth_getBlock`. async fn remote_genesis_block(&self) -> Result, CliqueMiddlewareError> { self.get_block(BlockNumber::Earliest).await?.ok_or(CliqueError::NoGenesis) @@ -109,7 +109,7 @@ pub trait CliqueMiddleware: Send + Sync + Middleware { Ok(()) } - /// Returns the [`Geth`](ethers_core::utils::Geth) instance [`PeerId`](reth_primitives::PeerId) + /// Returns the [`Geth`](alloy_node_bindings::Geth) instance [`PeerId`](reth_primitives::PeerId) /// by calling geth's `admin_nodeInfo`. async fn peer_id(&self) -> Result> { Ok(enr_to_peer_id(self.node_info().await?.enr)) diff --git a/crates/net/network/tests/it/clique/geth.rs b/crates/net/network/tests/it/clique/geth.rs index 6534fd87db7e..323cef0166ec 100644 --- a/crates/net/network/tests/it/clique/geth.rs +++ b/crates/net/network/tests/it/clique/geth.rs @@ -1,8 +1,8 @@ #![allow(unreachable_pub)] //! Helper struct for working with a clique geth instance. +use alloy_node_bindings::{Geth, GethInstance}; use enr::k256::ecdsa::SigningKey; -use ethers_core::utils::{Geth, GethInstance}; use ethers_middleware::SignerMiddleware; use ethers_providers::{Provider, Ws}; use ethers_signers::{LocalWallet, Wallet}; @@ -11,15 +11,15 @@ use std::{ net::SocketAddr, }; -/// A [`Geth`](ethers_core::utils::Geth) instance configured with Clique and a custom -/// [`Genesis`](ethers_core::utils::Genesis). +/// A [`Geth`](alloy_node_bindings::Geth) instance configured with Clique and a custom +/// [`Genesis`](reth_primitives::Genesis). /// /// This holds a [`SignerMiddleware`](ethers_middleware::SignerMiddleware) for /// enabling block production and creating transactions. /// /// # Example /// ```no_run -/// # use ethers_core::utils::Geth; +/// # use alloy_node_bindings::Geth; /// # use reth_staged_sync::test_utils::CliqueGethInstance; /// # let clique = async { /// @@ -34,7 +34,7 @@ use std::{ /// # }; /// ``` pub struct CliqueGethInstance { - /// The spawned [`GethInstance`](ethers_core::utils::GethInstance). + /// The spawned [`GethInstance`](alloy_node_bindings::GethInstance). pub instance: GethInstance, /// The provider who can talk to this instance pub provider: SignerMiddleware, Wallet>, @@ -42,7 +42,7 @@ pub struct CliqueGethInstance { impl CliqueGethInstance { /// Sets up a new [`SignerMiddleware`](ethers_middleware::SignerMiddleware) - /// for the [`Geth`](ethers_core::utils::Geth) instance and returns the + /// for the [`Geth`](alloy_node_bindings::Geth) instance and returns the /// [`CliqueGethInstance`](crate::test_utils::CliqueGethInstance). /// /// The signer is assumed to be the clique signer and the signer for any transactions sent for @@ -69,7 +69,7 @@ impl CliqueGethInstance { Self { instance, provider } } - /// Prints the logs of the [`Geth`](ethers_core::utils::Geth) instance in a new + /// Prints the logs of the [`Geth`](alloy_node_bindings::Geth) instance in a new /// [`task`](tokio::task). #[allow(dead_code)] pub async fn print_logs(&mut self) { @@ -96,7 +96,7 @@ impl CliqueGethInstance { }); } - /// Prevents the [`Geth`](ethers_core::utils::Geth) instance from blocking due to the `stderr` + /// Prevents the [`Geth`](alloy_node_bindings::Geth) instance from blocking due to the `stderr` /// filling up. pub async fn prevent_blocking(&mut self) { // take the stderr of the geth instance and print it diff --git a/crates/net/network/tests/it/connect.rs b/crates/net/network/tests/it/connect.rs index 8238235a5baa..2bab1d6709d0 100644 --- a/crates/net/network/tests/it/connect.rs +++ b/crates/net/network/tests/it/connect.rs @@ -1,6 +1,6 @@ //! Connection tests -use ethers_core::utils::Geth; +use alloy_node_bindings::Geth; use ethers_providers::{Http, Middleware, Provider}; use futures::StreamExt; use reth_discv4::Discv4Config; diff --git a/crates/net/network/tests/it/geth.rs b/crates/net/network/tests/it/geth.rs index 0a80d0327e68..7b510d88804b 100644 --- a/crates/net/network/tests/it/geth.rs +++ b/crates/net/network/tests/it/geth.rs @@ -1,7 +1,7 @@ use crate::clique::{CliqueGethInstance, CliqueMiddleware}; -use ethers_core::{ - types::{transaction::eip2718::TypedTransaction, Address, Eip1559TransactionRequest}, - utils::Geth, +use alloy_node_bindings::Geth; +use ethers_core::types::{ + transaction::eip2718::TypedTransaction, Address, Eip1559TransactionRequest, }; use ethers_providers::Middleware; use reth_network::{ @@ -9,10 +9,11 @@ use reth_network::{ NetworkConfig, NetworkEvents, NetworkManager, }; use reth_network_api::Peers; -use reth_primitives::{ChainSpec, Genesis, PeerId, SealedHeader}; +use reth_primitives::{ChainSpec, PeerId, SealedHeader}; use reth_provider::test_utils::NoopProvider; use secp256k1::SecretKey; use std::{net::SocketAddr, sync::Arc}; + #[tokio::test(flavor = "multi_thread")] #[cfg_attr(not(feature = "geth-tests"), ignore)] async fn can_peer_with_geth() { @@ -97,9 +98,9 @@ async fn init_geth() -> (CliqueGethInstance, Arc) { // === check that we have the same genesis hash === // get the chainspec from the genesis we configured for geth - let chainspec = ChainSpec::from(Genesis::from( + let chainspec = ChainSpec::from( clique.instance.genesis().clone().expect("clique should be configured with a genesis"), - )); + ); let remote_genesis = SealedHeader::from(&clique.provider.remote_genesis_block().await.unwrap()); diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index d380b71b406a..7628b85a42dc 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -26,7 +26,7 @@ alloy-rlp = { workspace = true, features = ["arrayvec"] } alloy-trie = { workspace = true, features = ["serde"] } ethers-core = { workspace = true, default-features = false, optional = true } nybbles = { version = "0.1.2", features = ["serde", "rlp"] } - +alloy-genesis.workspace = true # crypto secp256k1 = { workspace = true, features = ["global-context", "recovery"] } diff --git a/crates/primitives/src/account.rs b/crates/primitives/src/account.rs index c505ee5dfc1b..5d062693dbb0 100644 --- a/crates/primitives/src/account.rs +++ b/crates/primitives/src/account.rs @@ -1,13 +1,13 @@ use crate::{ + keccak256, revm_primitives::{Bytecode as RevmBytecode, BytecodeState, Bytes, JumpMap}, - B256, KECCAK_EMPTY, U256, + GenesisAccount, B256, KECCAK_EMPTY, U256, }; use byteorder::{BigEndian, ReadBytesExt}; use bytes::Buf; use reth_codecs::{main_codec, Compact}; use serde::{Deserialize, Serialize}; use std::ops::Deref; - /// An Ethereum account. #[main_codec] #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] @@ -37,6 +37,16 @@ impl Account { self.nonce == 0 && self.balance.is_zero() && is_bytecode_empty } + /// Converts [GenesisAccount] to [Account] type + pub fn from_genesis_account(value: GenesisAccount) -> Self { + Account { + // nonce must exist, so we default to zero when converting a genesis account + nonce: value.nonce.unwrap_or_default(), + balance: value.balance, + bytecode_hash: value.code.map(keccak256), + } + } + /// Returns an account bytecode's hash. /// In case of no bytecode, returns [`KECCAK_EMPTY`]. pub fn get_bytecode_hash(&self) -> B256 { diff --git a/crates/primitives/src/genesis.rs b/crates/primitives/src/genesis.rs index e81f24751010..df1788ebd171 100644 --- a/crates/primitives/src/genesis.rs +++ b/crates/primitives/src/genesis.rs @@ -1,1469 +1,214 @@ -use crate::{ - keccak256, public_key_to_address, - serde_helper::{ - json_u256::{deserialize_json_ttd_opt, deserialize_json_u256}, - num::{u64_hex_or_decimal, u64_hex_or_decimal_opt}, - storage::deserialize_storage_map, - }, - Account, Address, Bytes, B256, U256, -}; -use secp256k1::{ - rand::{thread_rng, RngCore}, - KeyPair, Secp256k1, -}; -use serde::{Deserialize, Serialize}; -use std::collections::{hash_map::Entry, HashMap}; - -/// The genesis block specification. -#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "camelCase", default)] -pub struct Genesis { - /// The fork configuration for this network. - #[serde(default)] - pub config: ChainConfig, - /// The genesis header nonce. - #[serde(with = "u64_hex_or_decimal")] - pub nonce: u64, - /// The genesis header timestamp. - #[serde(with = "u64_hex_or_decimal")] - pub timestamp: u64, - /// The genesis header extra data. - pub extra_data: Bytes, - /// The genesis header gas limit. - #[serde(with = "u64_hex_or_decimal")] - pub gas_limit: u64, - /// The genesis header difficulty. - #[serde(deserialize_with = "deserialize_json_u256")] - pub difficulty: U256, - /// The genesis header mix hash. - pub mix_hash: B256, - /// The genesis header coinbase address. - pub coinbase: Address, - /// The initial state of accounts in the genesis block. - pub alloc: HashMap, - // NOTE: the following fields: - // * base_fee_per_gas - // * excess_blob_gas - // * blob_gas_used - // should NOT be set in a real genesis file, but are included here for compatibility with - // consensus tests, which have genesis files with these fields populated. - /// The genesis header base fee - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub base_fee_per_gas: Option, - /// The genesis header excess blob gas - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub excess_blob_gas: Option, - /// The genesis header blob gas used - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub blob_gas_used: Option, -} - -impl Genesis { - /// Set the nonce. - pub fn with_nonce(mut self, nonce: u64) -> Self { - self.nonce = nonce; - self - } - - /// Set the timestamp. - pub fn with_timestamp(mut self, timestamp: u64) -> Self { - self.timestamp = timestamp; - self - } - - /// Set the extra data. - pub fn with_extra_data(mut self, extra_data: Bytes) -> Self { - self.extra_data = extra_data; - self - } - - /// Set the gas limit. - pub fn with_gas_limit(mut self, gas_limit: u64) -> Self { - self.gas_limit = gas_limit; - self - } - - /// Set the difficulty. - pub fn with_difficulty(mut self, difficulty: U256) -> Self { - self.difficulty = difficulty; - self - } - - /// Set the mix hash of the header. - pub fn with_mix_hash(mut self, mix_hash: B256) -> Self { - self.mix_hash = mix_hash; - self - } - - /// Set the coinbase address. - pub fn with_coinbase(mut self, address: Address) -> Self { - self.coinbase = address; - self - } - - /// Set the base fee. - pub fn with_base_fee(mut self, base_fee: Option) -> Self { - self.base_fee_per_gas = base_fee; - self - } - - /// Set the excess blob gas. - pub fn with_excess_blob_gas(mut self, excess_blob_gas: Option) -> Self { - self.excess_blob_gas = excess_blob_gas; - self - } - - /// Set the blob gas used. - pub fn with_blob_gas_used(mut self, blob_gas_used: Option) -> Self { - self.blob_gas_used = blob_gas_used; - self - } - - /// Add accounts to the genesis block. If the address is already present, - /// the account is updated. - pub fn extend_accounts( - mut self, - accounts: impl IntoIterator, - ) -> Self { - self.alloc.extend(accounts); - self - } -} - -/// An account in the state of the genesis block. -#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct GenesisAccount { - /// The nonce of the account at genesis. - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt", default)] - pub nonce: Option, - /// The balance of the account at genesis. - #[serde(deserialize_with = "deserialize_json_u256")] - pub balance: U256, - /// The account's bytecode at genesis. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub code: Option, - /// The account's storage at genesis. - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "deserialize_storage_map" - )] - pub storage: Option>, -} - -impl GenesisAccount { - /// Set the nonce. - pub fn with_nonce(mut self, nonce: Option) -> Self { - self.nonce = nonce; - self - } - - /// Set the balance. - pub fn with_balance(mut self, balance: U256) -> Self { - self.balance = balance; - self - } - - /// Set the code. - pub fn with_code(mut self, code: Option) -> Self { - self.code = code; - self - } - - /// Set the storage. - pub fn with_storage(mut self, storage: Option>) -> Self { - self.storage = storage; - self - } -} - -impl From for Account { - fn from(value: GenesisAccount) -> Self { - Account { - // nonce must exist, so we default to zero when converting a genesis account - nonce: value.nonce.unwrap_or_default(), - balance: value.balance, - bytecode_hash: value.code.map(keccak256), - } - } -} - -/// Helper trait that encapsulates [RngCore], and [Debug](std::fmt::Debug) to get around rules for -/// auto traits (Opt-in built-in traits). -trait RngDebug: RngCore + std::fmt::Debug {} -impl RngDebug for T where T: RngCore + std::fmt::Debug {} - -/// This helps create a custom genesis alloc by making it easy to add funded accounts with known -/// signers to the genesis block. -/// -/// # Example -/// ``` -/// # use reth_primitives::{GenesisAllocator, Address, U256, hex, Bytes}; -/// # use std::str::FromStr; -/// let mut allocator = GenesisAllocator::default(); -/// -/// // This will add a genesis account to the alloc builder, with the provided balance. The -/// // signer for the account will be returned. -/// let (_signer, _addr) = allocator.new_funded_account(U256::from(100_000_000_000_000_000u128)); -/// -/// // You can also provide code for the account. -/// let code = Bytes::from_str("0x1234").unwrap(); -/// let (_second_signer, _second_addr) = -/// allocator.new_funded_account_with_code(U256::from(100_000_000_000_000_000u128), code); -/// -/// // You can also add an account with a specific address. -/// // This will not return a signer, since the address is provided by the user and the signer -/// // may be unknown. -/// let addr = "0Ac1dF02185025F65202660F8167210A80dD5086".parse::
().unwrap(); -/// allocator.add_funded_account_with_address(addr, U256::from(100_000_000_000_000_000u128)); -/// -/// // Once you're done adding accounts, you can build the alloc. -/// let alloc = allocator.build(); -/// ``` -#[derive(Debug)] -pub struct GenesisAllocator<'a> { - /// The genesis alloc to be built. - alloc: HashMap, - /// The rng to use for generating key pairs. - rng: Box, -} - -impl<'a> GenesisAllocator<'a> { - /// Initialize a new alloc builder with the provided rng. - pub fn new_with_rng(rng: &'a mut R) -> Self - where - R: RngCore + std::fmt::Debug, - { - Self { alloc: HashMap::default(), rng: Box::new(rng) } - } - - /// Use the provided rng for generating key pairs. - pub fn with_rng(mut self, rng: &'a mut R) -> Self - where - R: RngCore + std::fmt::Debug, - { - self.rng = Box::new(rng); - self - } - - /// Add a funded account to the genesis alloc. - /// - /// Returns the key pair for the account and the account's address. - pub fn new_funded_account(&mut self, balance: U256) -> (KeyPair, Address) { - let secp = Secp256k1::new(); - let pair = KeyPair::new(&secp, &mut self.rng); - let address = public_key_to_address(pair.public_key()); - - self.alloc.insert(address, GenesisAccount::default().with_balance(balance)); - - (pair, address) - } - - /// Add a funded account to the genesis alloc with the provided code. - /// - /// Returns the key pair for the account and the account's address. - pub fn new_funded_account_with_code( - &mut self, - balance: U256, - code: Bytes, - ) -> (KeyPair, Address) { - let secp = Secp256k1::new(); - let pair = KeyPair::new(&secp, &mut self.rng); - let address = public_key_to_address(pair.public_key()); - - self.alloc - .insert(address, GenesisAccount::default().with_balance(balance).with_code(Some(code))); - - (pair, address) - } +//! Types for genesis configuration of a chain. + +// re-export genesis types +#[doc(inline)] +pub use alloy_genesis::*; + +#[cfg(any(test, feature = "test-utils"))] +pub use allocator::GenesisAllocator; + +#[cfg(any(test, feature = "test-utils"))] +mod allocator { + use crate::{public_key_to_address, Address, Bytes, B256, U256}; + use alloy_genesis::GenesisAccount; + use secp256k1::{ + rand::{thread_rng, RngCore}, + KeyPair, Secp256k1, + }; + use std::collections::{hash_map::Entry, HashMap}; - /// Adds a funded account to the genesis alloc with the provided storage. + /// This helps create a custom genesis alloc by making it easy to add funded accounts with known + /// signers to the genesis block. /// - /// Returns the key pair for the account and the account's address. - pub fn new_funded_account_with_storage( - &mut self, - balance: U256, - storage: HashMap, - ) -> (KeyPair, Address) { - let secp = Secp256k1::new(); - let pair = KeyPair::new(&secp, &mut self.rng); - let address = public_key_to_address(pair.public_key()); - - self.alloc.insert( - address, - GenesisAccount::default().with_balance(balance).with_storage(Some(storage)), - ); - - (pair, address) - } - - /// Adds an account with code and storage to the genesis alloc. + /// # Example + /// ``` + /// # use reth_primitives::{ genesis::GenesisAllocator, Address, U256, hex, Bytes}; + /// # use std::str::FromStr; + /// let mut allocator = GenesisAllocator::default(); /// - /// Returns the key pair for the account and the account's address. - pub fn new_account_with_code_and_storage( - &mut self, - code: Bytes, - storage: HashMap, - ) -> (KeyPair, Address) { - let secp = Secp256k1::new(); - let pair = KeyPair::new(&secp, &mut self.rng); - let address = public_key_to_address(pair.public_key()); - - self.alloc.insert( - address, - GenesisAccount::default().with_code(Some(code)).with_storage(Some(storage)), - ); - - (pair, address) - } - - /// Adds an account with code to the genesis alloc. + /// // This will add a genesis account to the alloc builder, with the provided balance. The + /// // signer for the account will be returned. + /// let (_signer, _addr) = allocator.new_funded_account(U256::from(100_000_000_000_000_000u128)); /// - /// Returns the key pair for the account and the account's address. - pub fn new_account_with_code(&mut self, code: Bytes) -> (KeyPair, Address) { - let secp = Secp256k1::new(); - let pair = KeyPair::new(&secp, &mut self.rng); - let address = public_key_to_address(pair.public_key()); - - self.alloc.insert(address, GenesisAccount::default().with_code(Some(code))); - - (pair, address) - } - - /// Add a funded account to the genesis alloc with the provided address. + /// // You can also provide code for the account. + /// let code = Bytes::from_str("0x1234").unwrap(); + /// let (_second_signer, _second_addr) = + /// allocator.new_funded_account_with_code(U256::from(100_000_000_000_000_000u128), code); /// - /// Neither the key pair nor the account will be returned, since the address is provided by the - /// user and the signer may be unknown. - pub fn add_funded_account_with_address(&mut self, address: Address, balance: U256) { - self.alloc.insert(address, GenesisAccount::default().with_balance(balance)); - } - - /// Adds the given [GenesisAccount] to the genesis alloc. + /// // You can also add an account with a specific address. + /// // This will not return a signer, since the address is provided by the user and the signer + /// // may be unknown. + /// let addr = "0Ac1dF02185025F65202660F8167210A80dD5086".parse::
().unwrap(); + /// allocator.add_funded_account_with_address(addr, U256::from(100_000_000_000_000_000u128)); /// - /// Returns the key pair for the account and the account's address. - pub fn add_account(&mut self, account: GenesisAccount) -> Address { - let secp = Secp256k1::new(); - let pair = KeyPair::new(&secp, &mut self.rng); - let address = public_key_to_address(pair.public_key()); - - self.alloc.insert(address, account); - - address - } - - /// Gets the account for the provided address. - /// - /// If it does not exist, this returns `None`. - pub fn get_account(&self, address: &Address) -> Option<&GenesisAccount> { - self.alloc.get(address) - } - - /// Gets a mutable version of the account for the provided address, if it exists. - pub fn get_account_mut(&mut self, address: &Address) -> Option<&mut GenesisAccount> { - self.alloc.get_mut(address) - } - - /// Gets an [Entry] for the provided address. - pub fn account_entry(&mut self, address: Address) -> Entry<'_, Address, GenesisAccount> { - self.alloc.entry(address) - } - - /// Build the genesis alloc. - pub fn build(self) -> HashMap { - self.alloc - } -} - -impl Default for GenesisAllocator<'_> { - fn default() -> Self { - Self { alloc: HashMap::default(), rng: Box::new(thread_rng()) } - } -} - -/// Defines core blockchain settings per block. -/// -/// Tailors unique settings for each network based on its genesis block. -/// -/// Governs crucial blockchain behavior and adaptability. -/// -/// Encapsulates parameters shaping network evolution and behavior. -/// -/// See [geth's `ChainConfig` -/// struct](https://github.com/ethereum/go-ethereum/blob/64dccf7aa411c5c7cd36090c3d9b9892945ae813/params/config.go#L349) -/// for the source of each field. -#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Eq)] -#[serde(default, rename_all = "camelCase")] -pub struct ChainConfig { - /// The network's chain ID. - #[serde(default = "mainnet_id")] - pub chain_id: u64, - - /// The homestead switch block (None = no fork, 0 = already homestead). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub homestead_block: Option, - - /// The DAO fork switch block (None = no fork). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub dao_fork_block: Option, - - /// Whether or not the node supports the DAO hard-fork. - pub dao_fork_support: bool, - - /// The [EIP-150](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md) hard fork block (None = no fork). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub eip150_block: Option, - - /// The [EIP-150](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md) hard fork hash. - #[serde(skip_serializing_if = "Option::is_none")] - pub eip150_hash: Option, - - /// The [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) hard fork block. - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub eip155_block: Option, - - /// The [EIP-158](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-158.md) hard fork block. - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub eip158_block: Option, - - /// The Byzantium hard fork block (None = no fork, 0 = already on byzantium). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub byzantium_block: Option, - - /// The Constantinople hard fork block (None = no fork, 0 = already on constantinople). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub constantinople_block: Option, - - /// The Petersburg hard fork block (None = no fork, 0 = already on petersburg). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub petersburg_block: Option, - - /// The Istanbul hard fork block (None = no fork, 0 = already on istanbul). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub istanbul_block: Option, - - /// The Muir Glacier hard fork block (None = no fork, 0 = already on muir glacier). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub muir_glacier_block: Option, - - /// The Berlin hard fork block (None = no fork, 0 = already on berlin). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub berlin_block: Option, - - /// The London hard fork block (None = no fork, 0 = already on london). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub london_block: Option, - - /// The Arrow Glacier hard fork block (None = no fork, 0 = already on arrow glacier). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub arrow_glacier_block: Option, - - /// The Gray Glacier hard fork block (None = no fork, 0 = already on gray glacier). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub gray_glacier_block: Option, - - /// Virtual fork after the merge to use as a network splitter. - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub merge_netsplit_block: Option, - - /// Shanghai switch time (None = no fork, 0 = already on shanghai). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub shanghai_time: Option, - - /// Cancun switch time (None = no fork, 0 = already on cancun). - #[serde(skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub cancun_time: Option, - - /// Total difficulty reached that triggers the merge consensus upgrade. - #[serde( - skip_serializing_if = "Option::is_none", - deserialize_with = "deserialize_json_ttd_opt" - )] - pub terminal_total_difficulty: Option, - - /// A flag specifying that the network already passed the terminal total difficulty. Its - /// purpose is to disable legacy sync without having seen the TTD locally. - pub terminal_total_difficulty_passed: bool, - - /// Ethash parameters. - #[serde(skip_serializing_if = "Option::is_none")] - pub ethash: Option, - - /// Clique parameters. - #[serde(skip_serializing_if = "Option::is_none")] - pub clique: Option, -} - -impl ChainConfig { - /// Checks if the blockchain is active at or after the Homestead fork block. - pub fn is_homestead_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.homestead_block, block) - } - - /// Checks if the blockchain is active at or after the EIP150 fork block. - pub fn is_eip150_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.eip150_block, block) - } - - /// Checks if the blockchain is active at or after the EIP155 fork block. - pub fn is_eip155_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.eip155_block, block) - } - - /// Checks if the blockchain is active at or after the EIP158 fork block. - pub fn is_eip158_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.eip158_block, block) - } - - /// Checks if the blockchain is active at or after the Byzantium fork block. - pub fn is_byzantium_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.byzantium_block, block) - } - - /// Checks if the blockchain is active at or after the Constantinople fork block. - pub fn is_constantinople_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.constantinople_block, block) - } - - /// Checks if the blockchain is active at or after the Muir Glacier (EIP-2384) fork block. - pub fn is_muir_glacier_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.muir_glacier_block, block) - } - - /// Checks if the blockchain is active at or after the Petersburg fork block. - pub fn is_petersburg_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.petersburg_block, block) - } - - /// Checks if the blockchain is active at or after the Istanbul fork block. - pub fn is_istanbul_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.istanbul_block, block) - } - - /// Checks if the blockchain is active at or after the Berlin fork block. - pub fn is_berlin_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.berlin_block, block) - } - - /// Checks if the blockchain is active at or after the London fork block. - pub fn is_london_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.london_block, block) - } - - /// Checks if the blockchain is active at or after the Arrow Glacier (EIP-4345) fork block. - pub fn is_arrow_glacier_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.arrow_glacier_block, block) - } - - /// Checks if the blockchain is active at or after the Gray Glacier (EIP-5133) fork block. - pub fn is_gray_glacier_active_at_block(&self, block: u64) -> bool { - self.is_active_at_block(self.gray_glacier_block, block) - } - - /// Checks if the blockchain is active at or after the Shanghai fork block and the specified - /// timestamp. - pub fn is_shanghai_active_at_block_and_timestamp(&self, block: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block) && - self.is_active_at_timestamp(self.shanghai_time, timestamp) - } - - /// Checks if the blockchain is active at or after the Cancun fork block and the specified - /// timestamp. - pub fn is_cancun_active_at_block_and_timestamp(&self, block: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block) && - self.is_active_at_timestamp(self.cancun_time, timestamp) - } - - // Private function handling the comparison logic for block numbers - fn is_active_at_block(&self, config_block: Option, block: u64) -> bool { - config_block.map_or(false, |cb| cb <= block) - } - - // Private function handling the comparison logic for timestamps - fn is_active_at_timestamp(&self, config_timestamp: Option, timestamp: u64) -> bool { - config_timestamp.map_or(false, |cb| cb <= timestamp) - } -} - -// used only for serde -#[inline] -const fn mainnet_id() -> u64 { - 1 -} - -/// Empty consensus configuration for proof-of-work networks. -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] -pub struct EthashConfig {} - -/// Consensus configuration for Clique. -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] -pub struct CliqueConfig { - /// Number of seconds between blocks to enforce. - #[serde(default, skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub period: Option, - - /// Epoch length to reset votes and checkpoints. - #[serde(default, skip_serializing_if = "Option::is_none", with = "u64_hex_or_decimal_opt")] - pub epoch: Option, -} - -#[cfg(feature = "test-utils")] -mod ethers_compat { - use super::*; - use ethers_core::utils::{ - ChainConfig as EthersChainConfig, CliqueConfig as EthersCliqueConfig, - EthashConfig as EthersEthashConfig, GenesisAccount as EthersGenesisAccount, - }; + /// // Once you're done adding accounts, you can build the alloc. + /// let alloc = allocator.build(); + /// ``` + #[derive(Debug)] + pub struct GenesisAllocator<'a> { + /// The genesis alloc to be built. + alloc: HashMap, + /// The rng to use for generating key pairs. + rng: Box, + } + + impl<'a> GenesisAllocator<'a> { + /// Initialize a new alloc builder with the provided rng. + pub fn new_with_rng(rng: &'a mut R) -> Self + where + R: RngCore + std::fmt::Debug, + { + Self { alloc: HashMap::default(), rng: Box::new(rng) } + } - /// Converts an `ethers_core::utils::Genesis` into a `Genesis`. - impl From for Genesis { - /// This conversion function extracts and maps specific fields from the input `genesis` to - /// create a new `Genesis` instance - fn from(genesis: ethers_core::utils::Genesis) -> Genesis { - Genesis { - config: genesis.config.into(), - nonce: genesis.nonce.as_u64(), - timestamp: genesis.timestamp.as_u64(), - gas_limit: genesis.gas_limit.as_u64(), - difficulty: U256::from_limbs(genesis.difficulty.0), - mix_hash: genesis.mix_hash.0.into(), - coinbase: genesis.coinbase.0.into(), - extra_data: genesis.extra_data.0.into(), - base_fee_per_gas: genesis.base_fee_per_gas.map(|fee| fee.as_u64()), - // TODO: if/when ethers has cancun fields they should be added here - excess_blob_gas: None, - blob_gas_used: None, - alloc: genesis - .alloc - .iter() - .map(|(addr, account)| (addr.0.into(), account.clone().into())) - .collect(), - } + /// Use the provided rng for generating key pairs. + pub fn with_rng(mut self, rng: &'a mut R) -> Self + where + R: RngCore + std::fmt::Debug, + { + self.rng = Box::new(rng); + self } - } - /// Converts an `EthersGenesisAccount` into a `GenesisAccount`. - impl From for GenesisAccount { - /// Converts fields from `EthersGenesisAccount` to construct a `GenesisAccount`. + /// Add a funded account to the genesis alloc. /// - /// - Maps the `balance` from limbs. - /// - Sets the `nonce`. - /// - Handles the `code` field, converting it if present. - /// - Processes the `storage` field into key-value pairs. - fn from(genesis_account: EthersGenesisAccount) -> Self { - Self { - balance: U256::from_limbs(genesis_account.balance.0), - nonce: genesis_account.nonce, - code: genesis_account.code.as_ref().map(|code| code.0.clone().into()), - storage: genesis_account.storage.as_ref().map(|storage| { - storage.clone().into_iter().map(|(k, v)| (k.0.into(), v.0.into())).collect() - }), - } - } - } + /// Returns the key pair for the account and the account's address. + pub fn new_funded_account(&mut self, balance: U256) -> (KeyPair, Address) { + let secp = Secp256k1::new(); + let pair = KeyPair::new(&secp, &mut self.rng); + let address = public_key_to_address(pair.public_key()); - /// Converts an `EthersChainConfig` into a `ChainConfig`. - impl From for ChainConfig { - fn from(chain_config: EthersChainConfig) -> Self { - let EthersChainConfig { - chain_id, - homestead_block, - dao_fork_block, - dao_fork_support, - eip150_block, - eip150_hash, - eip155_block, - eip158_block, - byzantium_block, - constantinople_block, - petersburg_block, - istanbul_block, - muir_glacier_block, - berlin_block, - london_block, - arrow_glacier_block, - gray_glacier_block, - merge_netsplit_block, - shanghai_time, - cancun_time, - terminal_total_difficulty, - terminal_total_difficulty_passed, - ethash, - clique, - } = chain_config; + self.alloc.insert(address, GenesisAccount::default().with_balance(balance)); - Self { - chain_id, - homestead_block, - dao_fork_block, - dao_fork_support, - eip150_block, - eip150_hash: eip150_hash.map(|x| x.0.into()), - eip155_block, - eip158_block, - byzantium_block, - constantinople_block, - petersburg_block, - istanbul_block, - muir_glacier_block, - berlin_block, - london_block, - arrow_glacier_block, - gray_glacier_block, - merge_netsplit_block, - shanghai_time, - cancun_time, - terminal_total_difficulty: terminal_total_difficulty.map(|x| U256::from_limbs(x.0)), - terminal_total_difficulty_passed, - ethash: ethash.map(Into::into), - clique: clique.map(Into::into), - } + (pair, address) } - } - /// Converts an `EthersEthashConfig` into an `EthashConfig`. - impl From for EthashConfig { - fn from(_: EthersEthashConfig) -> Self { - EthashConfig {} + /// Add a funded account to the genesis alloc with the provided code. + /// + /// Returns the key pair for the account and the account's address. + pub fn new_funded_account_with_code( + &mut self, + balance: U256, + code: Bytes, + ) -> (KeyPair, Address) { + let secp = Secp256k1::new(); + let pair = KeyPair::new(&secp, &mut self.rng); + let address = public_key_to_address(pair.public_key()); + + self.alloc.insert( + address, + GenesisAccount::default().with_balance(balance).with_code(Some(code)), + ); + + (pair, address) } - } - /// Converts an `EthersCliqueConfig` into a `CliqueConfig`. - impl From for CliqueConfig { - fn from(clique_config: EthersCliqueConfig) -> Self { - let EthersCliqueConfig { period, epoch } = clique_config; - Self { period, epoch } + /// Adds a funded account to the genesis alloc with the provided storage. + /// + /// Returns the key pair for the account and the account's address. + pub fn new_funded_account_with_storage( + &mut self, + balance: U256, + storage: HashMap, + ) -> (KeyPair, Address) { + let secp = Secp256k1::new(); + let pair = KeyPair::new(&secp, &mut self.rng); + let address = public_key_to_address(pair.public_key()); + + self.alloc.insert( + address, + GenesisAccount::default().with_balance(balance).with_storage(Some(storage)), + ); + + (pair, address) } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{hex_literal::hex, Address, Bytes, U256}; - use std::{collections::HashMap, str::FromStr}; - - #[test] - fn test_genesis() { - let default_genesis = Genesis::default(); - - let nonce = 999; - let timestamp = 12345; - let extra_data = Bytes::from(b"extra-data"); - let gas_limit = 333333; - let difficulty = U256::from(9000); - let mix_hash = - hex!("74385b512f1e0e47100907efe2b00ac78df26acba6dd16b0772923068a5801a8").into(); - let coinbase = hex!("265873b6faf3258b3ab0827805386a2a20ed040e").into(); - // create dummy account - let first_address: Address = hex!("7618a8c597b89e01c66a1f662078992c52a30c9a").into(); - let mut account = HashMap::default(); - account.insert(first_address, GenesisAccount::default()); - - // check values updated - let custom_genesis = Genesis::default() - .with_nonce(nonce) - .with_timestamp(timestamp) - .with_extra_data(extra_data.clone()) - .with_gas_limit(gas_limit) - .with_difficulty(difficulty) - .with_mix_hash(mix_hash) - .with_coinbase(coinbase) - .extend_accounts(account.clone()); - - assert_ne!(custom_genesis, default_genesis); - // check every field - assert_eq!(custom_genesis.nonce, nonce); - assert_eq!(custom_genesis.timestamp, timestamp); - assert_eq!(custom_genesis.extra_data, extra_data); - assert_eq!(custom_genesis.gas_limit, gas_limit); - assert_eq!(custom_genesis.difficulty, difficulty); - assert_eq!(custom_genesis.mix_hash, mix_hash); - assert_eq!(custom_genesis.coinbase, coinbase); - assert_eq!(custom_genesis.alloc, account.clone()); - - // update existing account - assert_eq!(custom_genesis.alloc.len(), 1); - let same_address = first_address; - let new_alloc_account = GenesisAccount { - nonce: Some(1), - balance: U256::from(1), - code: Some(Bytes::from(b"code")), - storage: Some(HashMap::default()), - }; - let mut updated_account = HashMap::default(); - updated_account.insert(same_address, new_alloc_account); - let custom_genesis = custom_genesis.extend_accounts(updated_account.clone()); - assert_ne!(account, updated_account); - assert_eq!(custom_genesis.alloc.len(), 1); - - // add second account - let different_address = hex!("94e0681e3073dd71cec54b53afe988f39078fd1a").into(); - let more_accounts = HashMap::from([(different_address, GenesisAccount::default())]); - let custom_genesis = custom_genesis.extend_accounts(more_accounts); - assert_eq!(custom_genesis.alloc.len(), 2); - - // ensure accounts are different - let first_account = custom_genesis.alloc.get(&first_address); - let second_account = custom_genesis.alloc.get(&different_address); - assert!(first_account.is_some()); - assert!(second_account.is_some()); - assert_ne!(first_account, second_account); - } - - #[test] - fn test_genesis_account() { - let default_account = GenesisAccount::default(); - let nonce = Some(1); - let balance = U256::from(33); - let code = Some(Bytes::from(b"code")); - let root = hex!("9474ddfcea39c5a690d2744103e39d1ff1b03d18db10fc147d970ad24699395a").into(); - let value = hex!("58eb8294d9bb16832a9dabfcb270fff99ab8ee1d8764e4f3d9fdf59ec1dee469").into(); - let mut map = HashMap::default(); - map.insert(root, value); - let storage = Some(map); - - let genesis_account = GenesisAccount::default() - .with_nonce(nonce) - .with_balance(balance) - .with_code(code.clone()) - .with_storage(storage.clone()); - - assert_ne!(default_account, genesis_account); - // check every field - assert_eq!(genesis_account.nonce, nonce); - assert_eq!(genesis_account.balance, balance); - assert_eq!(genesis_account.code, code); - assert_eq!(genesis_account.storage, storage); - } - - #[test] - fn parse_hive_genesis() { - let geth_genesis = r#" - { - "difficulty": "0x20000", - "gasLimit": "0x1", - "alloc": {}, - "config": { - "ethash": {}, - "chainId": 1 + /// Adds an account with code and storage to the genesis alloc. + /// + /// Returns the key pair for the account and the account's address. + pub fn new_account_with_code_and_storage( + &mut self, + code: Bytes, + storage: HashMap, + ) -> (KeyPair, Address) { + let secp = Secp256k1::new(); + let pair = KeyPair::new(&secp, &mut self.rng); + let address = public_key_to_address(pair.public_key()); + + self.alloc.insert( + address, + GenesisAccount::default().with_code(Some(code)).with_storage(Some(storage)), + ); + + (pair, address) } - } - "#; - let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap(); - } - - #[test] - fn parse_hive_clique_smoke_genesis() { - let geth_genesis = r#" - { - "difficulty": "0x1", - "gasLimit": "0x400000", - "extraData": - "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - , "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0", - "timestamp": "0x5c51a607", - "alloc": {} - } - "#; + /// Adds an account with code to the genesis alloc. + /// + /// Returns the key pair for the account and the account's address. + pub fn new_account_with_code(&mut self, code: Bytes) -> (KeyPair, Address) { + let secp = Secp256k1::new(); + let pair = KeyPair::new(&secp, &mut self.rng); + let address = public_key_to_address(pair.public_key()); - let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap(); - } + self.alloc.insert(address, GenesisAccount::default().with_code(Some(code))); - #[test] - fn parse_non_hex_prefixed_balance() { - // tests that we can parse balance / difficulty fields that are either hex or decimal - let example_balance_json = r#" - { - "nonce": "0x0000000000000042", - "difficulty": "34747478", - "mixHash": "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234", - "coinbase": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "timestamp": "0x123456", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0xfafbfcfd", - "gasLimit": "0x2fefd8", - "alloc": { - "0x3E951C9f69a06Bc3AD71fF7358DbC56bEd94b9F2": { - "balance": "1000000000000000000000000000" - }, - "0xe228C30d4e5245f967ac21726d5412dA27aD071C": { - "balance": "1000000000000000000000000000" - }, - "0xD59Ce7Ccc6454a2D2C2e06bbcf71D0Beb33480eD": { - "balance": "1000000000000000000000000000" - }, - "0x1CF4D54414eF51b41f9B2238c57102ab2e61D1F2": { - "balance": "1000000000000000000000000000" - }, - "0x249bE3fDEd872338C733cF3975af9736bdCb9D4D": { - "balance": "1000000000000000000000000000" - }, - "0x3fCd1bff94513712f8cD63d1eD66776A67D5F78e": { - "balance": "1000000000000000000000000000" - } - }, - "config": { - "ethash": {}, - "chainId": 10, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0 + (pair, address) } - } - "#; - - let genesis: Genesis = serde_json::from_str(example_balance_json).unwrap(); - // check difficulty against hex ground truth - let expected_difficulty = U256::from_str("0x2123456").unwrap(); - assert_eq!(expected_difficulty, genesis.difficulty); - - // check all alloc balances - let dec_balance = U256::from_str("1000000000000000000000000000").unwrap(); - for alloc in &genesis.alloc { - assert_eq!(alloc.1.balance, dec_balance); + /// Add a funded account to the genesis alloc with the provided address. + /// + /// Neither the key pair nor the account will be returned, since the address is provided by + /// the user and the signer may be unknown. + pub fn add_funded_account_with_address(&mut self, address: Address, balance: U256) { + self.alloc.insert(address, GenesisAccount::default().with_balance(balance)); } - } - #[test] - fn parse_hive_rpc_genesis() { - let geth_genesis = r#" - { - "config": { - "chainId": 7, - "homesteadBlock": 0, - "eip150Block": 0, - "eip150Hash": "0x5de1ee4135274003348e80b788e5afa4b18b18d320a5622218d5c493fedf5689", - "eip155Block": 0, - "eip158Block": 0 - }, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x20000", - "extraData": - "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - , "gasLimit": "0x2fefd8", - "nonce": "0x0000000000000000", - "timestamp": "0x1234", - "alloc": { - "cf49fda3be353c69b41ed96333cd24302da4556f": { - "balance": "0x123450000000000000000" - }, - "0161e041aad467a890839d5b08b138c1e6373072": { - "balance": "0x123450000000000000000" - }, - "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": { - "balance": "0x123450000000000000000" - }, - "b97de4b8c857e4f6bc354f226dc3249aaee49209": { - "balance": "0x123450000000000000000" - }, - "c5065c9eeebe6df2c2284d046bfc906501846c51": { - "balance": "0x123450000000000000000" - }, - "0000000000000000000000000000000000000314": { - "balance": "0x0", - "code": - "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029" - , "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234", - "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01" - } - }, - "0000000000000000000000000000000000000315": { - "balance": "0x9999999999999999999999999999999", - "code": - "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029" - } - } - } - "#; + /// Adds the given [GenesisAccount] to the genesis alloc. + /// + /// Returns the key pair for the account and the account's address. + pub fn add_account(&mut self, account: GenesisAccount) -> Address { + let secp = Secp256k1::new(); + let pair = KeyPair::new(&secp, &mut self.rng); + let address = public_key_to_address(pair.public_key()); - let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap(); - } + self.alloc.insert(address, account); - #[test] - fn parse_hive_graphql_genesis() { - let geth_genesis = r#" - { - "config" : {}, - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "0x020000", - "extraData" : "0x42", - "gasLimit" : "0x2fefd8", - "mixHash" : "0x2c85bcbce56429100b2108254bb56906257582aeafcbd682bc9af67a9f5aee46", - "nonce" : "0x78cc16f7b4f65485", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp" : "0x54c98c81", - "alloc" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance" : "0x09184e72a000" - } + address } - } - "#; - - let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap(); - } - #[test] - fn parse_hive_engine_genesis() { - let geth_genesis = r#" - { - "config": { - "chainId": 7, - "homesteadBlock": 0, - "eip150Block": 0, - "eip150Hash": "0x5de1ee4135274003348e80b788e5afa4b18b18d320a5622218d5c493fedf5689", - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "berlinBlock": 0, - "yolov2Block": 0, - "yolov3Block": 0, - "londonBlock": 0 - }, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x30000", - "extraData": - "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - , "gasLimit": "0x2fefd8", - "nonce": "0x0000000000000000", - "timestamp": "0x1234", - "alloc": { - "cf49fda3be353c69b41ed96333cd24302da4556f": { - "balance": "0x123450000000000000000" - }, - "0161e041aad467a890839d5b08b138c1e6373072": { - "balance": "0x123450000000000000000" - }, - "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": { - "balance": "0x123450000000000000000" - }, - "b97de4b8c857e4f6bc354f226dc3249aaee49209": { - "balance": "0x123450000000000000000" - }, - "c5065c9eeebe6df2c2284d046bfc906501846c51": { - "balance": "0x123450000000000000000" - }, - "0000000000000000000000000000000000000314": { - "balance": "0x0", - "code": - "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029" - , "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234", - "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01" - } - }, - "0000000000000000000000000000000000000315": { - "balance": "0x9999999999999999999999999999999", - "code": - "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029" - }, - "0000000000000000000000000000000000000316": { - "balance": "0x0", - "code": "0x444355" - }, - "0000000000000000000000000000000000000317": { - "balance": "0x0", - "code": "0x600160003555" + /// Gets the account for the provided address. + /// + /// If it does not exist, this returns `None`. + pub fn get_account(&self, address: &Address) -> Option<&GenesisAccount> { + self.alloc.get(address) } - } - } - "#; - - let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap(); - } - - #[test] - fn parse_hive_devp2p_genesis() { - let geth_genesis = r#" - { - "config": { - "chainId": 19763, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "ethash": {} - }, - "nonce": "0xdeadbeefdeadbeef", - "timestamp": "0x0", - "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", - "gasLimit": "0x80000000", - "difficulty": "0x20000", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "coinbase": "0x0000000000000000000000000000000000000000", - "alloc": { - "71562b71999873db5b286df957af199ec94617f7": { - "balance": "0xffffffffffffffffffffffffff" - } - }, - "number": "0x0", - "gasUsed": "0x0", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" - } - "#; - let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap(); - } - - #[test] - fn parse_execution_apis_genesis() { - let geth_genesis = r#" - { - "config": { - "chainId": 1337, - "homesteadBlock": 0, - "eip150Block": 0, - "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "arrowGlacierBlock": 0, - "grayGlacierBlock": 0, - "shanghaiTime": 0, - "terminalTotalDifficulty": 0, - "terminalTotalDifficultyPassed": true, - "ethash": {} - }, - "nonce": "0x0", - "timestamp": "0x0", - "extraData": "0x", - "gasLimit": "0x4c4b40", - "difficulty": "0x1", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "coinbase": "0x0000000000000000000000000000000000000000", - "alloc": { - "658bdf435d810c91414ec09147daa6db62406379": { - "balance": "0x487a9a304539440000" - }, - "aa00000000000000000000000000000000000000": { - "code": "0x6042", - "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0100000000000000000000000000000000000000000000000000000000000000": - "0x0100000000000000000000000000000000000000000000000000000000000000", - "0x0200000000000000000000000000000000000000000000000000000000000000": - "0x0200000000000000000000000000000000000000000000000000000000000000", - "0x0300000000000000000000000000000000000000000000000000000000000000": - "0x0000000000000000000000000000000000000000000000000000000000000303" }, - "balance": "0x1", - "nonce": "0x1" - }, - "bb00000000000000000000000000000000000000": { - "code": "0x600154600354", - "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0100000000000000000000000000000000000000000000000000000000000000": - "0x0100000000000000000000000000000000000000000000000000000000000000", - "0x0200000000000000000000000000000000000000000000000000000000000000": - "0x0200000000000000000000000000000000000000000000000000000000000000", - "0x0300000000000000000000000000000000000000000000000000000000000000": - "0x0000000000000000000000000000000000000000000000000000000000000303" }, - "balance": "0x2", - "nonce": "0x1" + /// Gets a mutable version of the account for the provided address, if it exists. + pub fn get_account_mut(&mut self, address: &Address) -> Option<&mut GenesisAccount> { + self.alloc.get_mut(address) } - } - } - "#; - let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap(); - } - - #[test] - fn parse_hive_rpc_genesis_full() { - let geth_genesis = r#" - { - "config": { - "clique": { - "period": 1 - }, - "chainId": 7, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0 - }, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x020000", - "extraData": - "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - , "gasLimit": "0x2fefd8", - "nonce": "0x0000000000000000", - "timestamp": "0x1234", - "alloc": { - "cf49fda3be353c69b41ed96333cd24302da4556f": { - "balance": "0x123450000000000000000" - }, - "0161e041aad467a890839d5b08b138c1e6373072": { - "balance": "0x123450000000000000000" - }, - "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": { - "balance": "0x123450000000000000000" - }, - "b97de4b8c857e4f6bc354f226dc3249aaee49209": { - "balance": "0x123450000000000000000" - }, - "c5065c9eeebe6df2c2284d046bfc906501846c51": { - "balance": "0x123450000000000000000" - }, - "0000000000000000000000000000000000000314": { - "balance": "0x0", - "code": - "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029" - , "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234", - "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01" - } - }, - "0000000000000000000000000000000000000315": { - "balance": "0x9999999999999999999999999999999", - "code": - "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029" + /// Gets an [Entry] for the provided address. + pub fn account_entry(&mut self, address: Address) -> Entry<'_, Address, GenesisAccount> { + self.alloc.entry(address) } - }, - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" - } - "#; - - let genesis: Genesis = serde_json::from_str(geth_genesis).unwrap(); - let alloc_entry = genesis - .alloc - .get(&Address::from_str("0000000000000000000000000000000000000314").unwrap()) - .expect("missing account for parsed genesis"); - let storage = alloc_entry.storage.as_ref().expect("missing storage for parsed genesis"); - let expected_storage = HashMap::from_iter(vec![ - ( - B256::from_str( - "0x0000000000000000000000000000000000000000000000000000000000000000", - ) - .unwrap(), - B256::from_str( - "0x0000000000000000000000000000000000000000000000000000000000001234", - ) - .unwrap(), - ), - ( - B256::from_str( - "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9", - ) - .unwrap(), - B256::from_str( - "0x0000000000000000000000000000000000000000000000000000000000000001", - ) - .unwrap(), - ), - ]); - assert_eq!(storage, &expected_storage); - let expected_code = - Bytes::from_str("0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029" - ).unwrap(); - let code = alloc_entry.code.as_ref().expect( - "missing code for parsed - genesis", - ); - assert_eq!(code, &expected_code); + /// Build the genesis alloc. + pub fn build(self) -> HashMap { + self.alloc + } } - #[test] - fn test_hive_smoke_alloc_deserialize() { - let hive_genesis = r#" - { - "nonce": "0x0000000000000042", - "difficulty": "0x2123456", - "mixHash": "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234", - "coinbase": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "timestamp": "0x123456", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0xfafbfcfd", - "gasLimit": "0x2fefd8", - "alloc": { - "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { - "balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - }, - "e6716f9544a56c530d868e4bfbacb172315bdead": { - "balance": "0x11", - "code": "0x12" - }, - "b9c015918bdaba24b4ff057a92a3873d6eb201be": { - "balance": "0x21", - "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000001": "0x22" - } - }, - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { - "balance": "0x31", - "nonce": "0x32" - }, - "0000000000000000000000000000000000000001": { - "balance": "0x41" - }, - "0000000000000000000000000000000000000002": { - "balance": "0x51" - }, - "0000000000000000000000000000000000000003": { - "balance": "0x61" - }, - "0000000000000000000000000000000000000004": { - "balance": "0x71" - } - }, - "config": { - "ethash": {}, - "chainId": 10, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0 + impl Default for GenesisAllocator<'_> { + fn default() -> Self { + Self { alloc: HashMap::default(), rng: Box::new(thread_rng()) } } } - "#; - - let expected_genesis = - Genesis { - nonce: 0x0000000000000042, - difficulty: U256::from(0x2123456), - mix_hash: B256::from_str( - "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234", - ) - .unwrap(), - coinbase: Address::from_str("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap(), - timestamp: 0x123456, - extra_data: Bytes::from_str("0xfafbfcfd").unwrap(), - gas_limit: 0x2fefd8, - base_fee_per_gas: None, - excess_blob_gas: None, - blob_gas_used: None, - alloc: HashMap::from_iter(vec![ - ( - Address::from_str("0xdbdbdb2cbd23b783741e8d7fcf51e459b497e4a6").unwrap(), - GenesisAccount { - balance: - U256::from_str("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"). - unwrap(), nonce: None, - code: None, - storage: None, - }, - ), - ( - Address::from_str("0xe6716f9544a56c530d868e4bfbacb172315bdead").unwrap(), - GenesisAccount { - balance: U256::from_str("0x11").unwrap(), - nonce: None, - code: Some(Bytes::from_str("0x12").unwrap()), - storage: None, - }, - ), - ( - Address::from_str("0xb9c015918bdaba24b4ff057a92a3873d6eb201be").unwrap(), - GenesisAccount { - balance: U256::from_str("0x21").unwrap(), - nonce: None, - code: None, - storage: Some(HashMap::from_iter(vec![ - ( - B256::from_str("0x0000000000000000000000000000000000000000000000000000000000000001"). - unwrap(), - B256::from_str("0x0000000000000000000000000000000000000000000000000000000000000022"). - unwrap(), ), - ])), - }, - ), - ( - Address::from_str("0x1a26338f0d905e295fccb71fa9ea849ffa12aaf4").unwrap(), - GenesisAccount { - balance: U256::from_str("0x31").unwrap(), - nonce: Some(0x32u64), - code: None, - storage: None, - }, - ), - ( - Address::from_str("0x0000000000000000000000000000000000000001").unwrap(), - GenesisAccount { - balance: U256::from_str("0x41").unwrap(), - nonce: None, - code: None, - storage: None, - }, - ), - ( - Address::from_str("0x0000000000000000000000000000000000000002").unwrap(), - GenesisAccount { - balance: U256::from_str("0x51").unwrap(), - nonce: None, - code: None, - storage: None, - }, - ), - ( - Address::from_str("0x0000000000000000000000000000000000000003").unwrap(), - GenesisAccount { - balance: U256::from_str("0x61").unwrap(), - nonce: None, - code: None, - storage: None, - }, - ), - ( - Address::from_str("0x0000000000000000000000000000000000000004").unwrap(), - GenesisAccount { - balance: U256::from_str("0x71").unwrap(), - nonce: None, - code: None, - storage: None, - }, - ), - ]), - config: ChainConfig { - ethash: Some(EthashConfig {}), - chain_id: 10, - homestead_block: Some(0), - eip150_block: Some(0), - eip155_block: Some(0), - eip158_block: Some(0), - byzantium_block: Some(0), - constantinople_block: Some(0), - petersburg_block: Some(0), - istanbul_block: Some(0), - ..Default::default() - }, - }; + /// Helper trait that encapsulates [RngCore], and [Debug](std::fmt::Debug) to get around rules + /// for auto traits (Opt-in built-in traits). + trait RngDebug: RngCore + std::fmt::Debug {} - let deserialized_genesis: Genesis = serde_json::from_str(hive_genesis).unwrap(); - assert_eq!( - deserialized_genesis, expected_genesis, - "deserialized genesis - {deserialized_genesis:#?} does not match expected {expected_genesis:#?}" - ); - } + impl RngDebug for T where T: RngCore + std::fmt::Debug {} } diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 291d7122de54..f63f1d79241b 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -23,7 +23,7 @@ pub mod constants; pub mod eip4844; mod error; pub mod fs; -mod genesis; +pub mod genesis; mod header; mod integer_list; mod log; @@ -59,7 +59,7 @@ pub use constants::{ KECCAK_EMPTY, MAINNET_GENESIS_HASH, SEPOLIA_GENESIS_HASH, }; pub use error::{GotExpected, GotExpectedBoxed}; -pub use genesis::{ChainConfig, Genesis, GenesisAccount, GenesisAllocator}; +pub use genesis::{ChainConfig, Genesis, GenesisAccount}; pub use header::{Header, HeadersDirection, SealedHeader}; pub use integer_list::IntegerList; pub use log::{logs_bloom, Log}; diff --git a/crates/trie/src/proof.rs b/crates/trie/src/proof.rs index ce73bcaf022d..726bed46779d 100644 --- a/crates/trie/src/proof.rs +++ b/crates/trie/src/proof.rs @@ -206,8 +206,11 @@ mod tests { // Hash accounts and insert them into hashing table. let genesis = chain_spec.genesis(); - let alloc_accounts = - genesis.alloc.clone().into_iter().map(|(addr, account)| (addr, Some(account.into()))); + let alloc_accounts = genesis + .alloc + .clone() + .into_iter() + .map(|(addr, account)| (addr, Some(Account::from_genesis_account(account)))); provider.insert_account_for_hashing(alloc_accounts).unwrap(); let alloc_storage = genesis.alloc.clone().into_iter().filter_map(|(addr, account)| {