Skip to content

Commit

Permalink
chore: remove allocator type (alloy-rs#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattsse authored Jan 18, 2024
1 parent 8b47b5d commit 37ca7a8
Show file tree
Hide file tree
Showing 4 changed files with 1 addition and 219 deletions.
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 64,6 @@ jobs:
--exclude alloy-signer-aws \
--exclude alloy-signer-ledger \
--exclude alloy-signer-trezor \
--exclude alloy-genesis \
--exclude alloy-node-bindings \
--exclude alloy-transport-ipc
Expand Down
5 changes: 0 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 45,6 @@ elliptic-curve = { version = "0.13", default-features = false, features = ["std"
k256 = { version = "0.13", default-features = false, features = ["ecdsa", "std"] }
sha2 = { version = "0.10", default-features = false, features = ["std"] }
spki = { version = "0.7", default-features = false, features = ["std"] }
secp256k1 = { version = "0.27.0", default-features = false, features = [
"global-context",
"rand-std",
"recovery",
] }
# async
async-trait = "0.1.74"
futures = "0.3.29"
Expand Down
3 changes: 0 additions & 3 deletions crates/genesis/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 14,9 @@ exclude.workspace = true
[dependencies]
alloy-primitives.workspace = true
alloy-rpc-types.workspace = true
secp256k1.workspace = true
alloy-signer.workspace = true

# serde
serde.workspace = true
k256.workspace = true

[dev-dependencies]
serde_json.workspace = true
Expand Down
211 changes: 1 addition & 210 deletions crates/genesis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 23,8 @@ use alloy_rpc_types::serde_helpers::{
num::{u64_hex_or_decimal, u64_hex_or_decimal_opt},
storage::deserialize_storage_map,
};
use alloy_signer::utils::{public_key_to_address, raw_public_key_to_address};
use k256::ecdsa::VerifyingKey;
use secp256k1::{
rand::{thread_rng, RngCore},
KeyPair, Secp256k1,
};
use serde::{Deserialize, Serialize};
use std::collections::{hash_map::Entry, HashMap};
use std::collections::HashMap;

/// The genesis block specification.
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
Expand Down Expand Up @@ -196,209 190,6 @@ impl GenesisAccount {
}
}

/// 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<T> 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 alloy_primitives::{Address, U256, hex, Bytes};
/// use alloy_genesis::GenesisAllocator;
/// # 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::<Address>().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<Address, GenesisAccount>,
/// The rng to use for generating key pairs.
rng: Box<dyn RngDebug 'a>,
}

impl<'a> GenesisAllocator<'a> {
/// Initialize a new alloc builder with the provided rng.
pub fn new_with_rng<R>(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<R>(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 = self.keypair_to_address(pair);

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 = self.keypair_to_address(pair);
self.alloc
.insert(address, GenesisAccount::default().with_balance(balance).with_code(Some(code)));
(pair, address)
}

/// 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<B256, B256>,
) -> (KeyPair, Address) {
let secp = Secp256k1::new();
let pair = KeyPair::new(&secp, &mut self.rng);
let address = self.keypair_to_address(pair);
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.
///
/// 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<B256, B256>,
) -> (KeyPair, Address) {
let secp = Secp256k1::new();
let pair = KeyPair::new(&secp, &mut self.rng);
let address = self.keypair_to_address(pair);

self.alloc.insert(
address,
GenesisAccount::default().with_code(Some(code)).with_storage(Some(storage)),
);

(pair, address)
}

/// Returns the address from the keypair
pub fn keypair_to_address(&mut self, pair: KeyPair) -> Address {
let public_key = pair.public_key();
let uncompressed_pub_key = public_key.serialize_uncompressed();
// Skip the first byte (0x04) and use the next 64 bytes
let raw_public_key = &uncompressed_pub_key[1..];
raw_public_key_to_address(raw_public_key)
}

/// 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 verifying_key = VerifyingKey::from_sec1_bytes(pair.public_key().to_string().as_bytes())
.expect("Failed to parse verifying key to bytes");
let address = public_key_to_address(&verifying_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.
///
/// 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.
///
/// 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 verifying_key = VerifyingKey::from_sec1_bytes(pair.public_key().to_string().as_bytes())
.expect("Failed to parse verifying key to bytes");
let address = public_key_to_address(&verifying_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<Address, GenesisAccount> {
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.
Expand Down

0 comments on commit 37ca7a8

Please sign in to comment.