From d4724111f5cb03b30a468b760f1d06f262c43793 Mon Sep 17 00:00:00 2001 From: morph <82043364+morph-dev@users.noreply.github.com> Date: Thu, 25 Jul 2024 13:22:43 +0300 Subject: [PATCH] feat: implement VerkleTrie --- portal-verkle-primitives/src/ec/crs.rs | 15 +- portal-verkle-primitives/src/lib.rs | 2 +- portal-verkle-primitives/src/verkle/error.rs | 11 + .../src/verkle/genesis_config.rs | 98 ++ portal-verkle-primitives/src/verkle/mod.rs | 37 + .../src/verkle/nodes/branch.rs | 118 +++ .../src/verkle/nodes/commitment.rs | 60 ++ .../src/verkle/nodes/leaf.rs | 96 ++ .../src/verkle/nodes/mod.rs | 36 + .../src/{ => verkle}/storage.rs | 0 portal-verkle-primitives/src/verkle/trie.rs | 163 ++++ .../src/verkle/trie_printer.rs | 142 +++ testdata/genesis.json | 901 ++++++++++++++++++ 13 files changed, 1672 insertions(+), 7 deletions(-) create mode 100644 portal-verkle-primitives/src/verkle/error.rs create mode 100644 portal-verkle-primitives/src/verkle/genesis_config.rs create mode 100644 portal-verkle-primitives/src/verkle/mod.rs create mode 100644 portal-verkle-primitives/src/verkle/nodes/branch.rs create mode 100644 portal-verkle-primitives/src/verkle/nodes/commitment.rs create mode 100644 portal-verkle-primitives/src/verkle/nodes/leaf.rs create mode 100644 portal-verkle-primitives/src/verkle/nodes/mod.rs rename portal-verkle-primitives/src/{ => verkle}/storage.rs (100%) create mode 100644 portal-verkle-primitives/src/verkle/trie.rs create mode 100644 portal-verkle-primitives/src/verkle/trie_printer.rs create mode 100644 testdata/genesis.json diff --git a/portal-verkle-primitives/src/ec/crs.rs b/portal-verkle-primitives/src/ec/crs.rs index 7e6194e..091ee90 100644 --- a/portal-verkle-primitives/src/ec/crs.rs +++ b/portal-verkle-primitives/src/ec/crs.rs @@ -74,7 +74,11 @@ impl CRS { /// Single scalar multiplication. pub fn commit_single(index: usize, scalar: ScalarField) -> Point { - Point::new(INSTANCE.wnaf_precomp.mul_index(scalar.inner(), index)) + if scalar.is_zero() { + Point::zero() + } else { + Point::new(INSTANCE.wnaf_precomp.mul_index(scalar.inner(), index)) + } } /// Commit to sparse set of scalars. @@ -88,11 +92,10 @@ impl CRS { } Self::commit(&dense) } else { - let mut result = Point::zero(); - for (index, value) in scalars { - result += Self::commit_single(*index, value.clone()) - } - result + scalars + .iter() + .map(|(index, value)| Self::commit_single(*index, value.clone())) + .sum() } } } diff --git a/portal-verkle-primitives/src/lib.rs b/portal-verkle-primitives/src/lib.rs index 5eafd4a..59d6d5d 100644 --- a/portal-verkle-primitives/src/lib.rs +++ b/portal-verkle-primitives/src/lib.rs @@ -9,6 +9,6 @@ pub mod portal; pub mod proof; pub mod ssz; mod stem; -pub mod storage; mod trie_key; mod trie_value; +pub mod verkle; diff --git a/portal-verkle-primitives/src/verkle/error.rs b/portal-verkle-primitives/src/verkle/error.rs new file mode 100644 index 0000000..f2b41d8 --- /dev/null +++ b/portal-verkle-primitives/src/verkle/error.rs @@ -0,0 +1,11 @@ +use thiserror::Error; + +use crate::Stem; + +#[derive(Debug, Error)] +pub enum VerkleTrieError { + #[error("Expected stem {expected}, but received {actual}")] + UnexpectedStem { expected: Stem, actual: Stem }, + #[error("Node not found at depth {depth} for stem {stem} during the trie traversal")] + NodeNotFound { stem: Stem, depth: usize }, +} diff --git a/portal-verkle-primitives/src/verkle/genesis_config.rs b/portal-verkle-primitives/src/verkle/genesis_config.rs new file mode 100644 index 0000000..d95d751 --- /dev/null +++ b/portal-verkle-primitives/src/verkle/genesis_config.rs @@ -0,0 +1,98 @@ +use std::collections::{BTreeMap, HashMap}; + +use alloy_primitives::{b256, keccak256, Address, Bytes, B256, U256}; +use serde::{Deserialize, Serialize}; + +use crate::{Stem, TrieKey, TrieValue}; + +use super::{storage::AccountStorageLayout, StateWrites, StemStateWrite}; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct AccountAlloc { + pub balance: U256, + pub nonce: Option, + pub code: Option, + pub storage: Option>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct GenesisConfig { + pub alloc: HashMap, +} + +impl GenesisConfig { + pub const DEVNET6_BLOCK_HASH: B256 = + b256!("3fe165c03e7a77d1e3759362ebeeb16fd964cb411ce11fbe35c7032fab5b9a8a"); + pub const DEVNET6_STATE_ROOT: B256 = + b256!("1fbf85345a3cbba9a6d44f991b721e55620a22397c2a93ee8d5011136ac300ee"); + + pub fn into_state_writes(self) -> StateWrites { + let mut state_writes = BTreeMap::::new(); + let mut insert_state_write = |key: TrieKey, value: TrieValue| { + let stem = key.stem(); + state_writes + .entry(stem) + .or_insert_with(|| StemStateWrite { + stem, + writes: HashMap::new(), + }) + .writes + .insert(key.suffix(), value); + }; + + for (address, account_alloc) in self.alloc { + let storage_layout = AccountStorageLayout::new(address); + insert_state_write(storage_layout.version_key(), U256::ZERO.into()); + insert_state_write(storage_layout.balance_key(), account_alloc.balance.into()); + insert_state_write( + storage_layout.nonce_key(), + account_alloc.nonce.unwrap_or(U256::ZERO).into(), + ); + + match &account_alloc.code { + None => insert_state_write(storage_layout.code_hash_key(), keccak256([]).into()), + Some(code) => { + insert_state_write(storage_layout.code_hash_key(), keccak256(code).into()); + insert_state_write( + storage_layout.code_size_key(), + U256::from(code.len()).into(), + ); + for (key, value) in storage_layout.chunkify_code(code) { + insert_state_write(key, value); + } + } + } + + if let Some(storage) = account_alloc.storage { + for (storage_key, value) in storage { + insert_state_write(storage_layout.storage_slot_key(storage_key), value); + } + } + } + + StateWrites::new(state_writes.into_values().collect()) + } +} + +impl From for StateWrites { + fn from(genesis_config: GenesisConfig) -> Self { + genesis_config.into_state_writes() + } +} + +#[cfg(test)] +mod tests { + use std::{fs::File, io::BufReader}; + + use super::*; + + #[test] + fn parse_genesis() -> anyhow::Result<()> { + let reader = BufReader::new(File::open("../testdata/genesis.json")?); + let genesis_config: GenesisConfig = serde_json::from_reader(reader)?; + let alloc = genesis_config.alloc; + assert_eq!(alloc.len(), 278); + Ok(()) + } +} diff --git a/portal-verkle-primitives/src/verkle/mod.rs b/portal-verkle-primitives/src/verkle/mod.rs new file mode 100644 index 0000000..2e55a1f --- /dev/null +++ b/portal-verkle-primitives/src/verkle/mod.rs @@ -0,0 +1,37 @@ +use std::collections::{HashMap, HashSet}; + +use derive_more::{Constructor, Deref, Index}; + +use crate::{ssz::TriePath, Stem, TrieValue}; + +use nodes::{branch::BranchNode, leaf::LeafNode}; +pub use trie::VerkleTrie; + +pub mod error; +pub mod genesis_config; +pub mod nodes; +pub mod storage; +mod trie; +pub mod trie_printer; + +#[derive(Debug, Clone, PartialEq, Eq, Constructor, Deref, Index)] +pub struct StateWrites(Vec); + +#[derive(Debug, Clone, PartialEq, Eq, Constructor)] +pub struct StemStateWrite { + pub stem: Stem, + pub writes: HashMap, +} + +pub type NewBranchNode = Option; + +#[derive(Clone)] +pub struct AuxiliaryTrieModifications { + pub new_branch_nodes: HashSet, +} + +#[derive(Clone)] +pub struct PathToLeaf<'a> { + pub branches: Vec<&'a BranchNode>, + pub leaf: &'a LeafNode, +} diff --git a/portal-verkle-primitives/src/verkle/nodes/branch.rs b/portal-verkle-primitives/src/verkle/nodes/branch.rs new file mode 100644 index 0000000..49bce55 --- /dev/null +++ b/portal-verkle-primitives/src/verkle/nodes/branch.rs @@ -0,0 +1,118 @@ +use std::{array, mem}; + +use crate::{ + constants::VERKLE_NODE_WIDTH, + ssz::TriePath, + verkle::{NewBranchNode, StemStateWrite}, + Point, ScalarField, Stem, TrieKey, TrieValue, +}; + +use super::{commitment::Commitment, leaf::LeafNode, Node}; + +pub struct BranchNode { + depth: usize, + commitment: Commitment, + children: [Node; VERKLE_NODE_WIDTH], +} + +impl BranchNode { + pub fn new(depth: usize) -> Self { + if depth >= Stem::len_bytes() { + panic!("Invalid branch depth!") + } + Self { + depth, + commitment: Commitment::zero(), + children: array::from_fn(|_| Node::Empty), + } + } + + pub fn commitment(&self) -> &Point { + self.commitment.commitment() + } + + pub fn commitment_hash(&mut self) -> ScalarField { + self.commitment.commitment_hash() + } + + pub fn get(&self, key: &TrieKey) -> Option<&TrieValue> { + let index = key[self.depth] as usize; + match &self.children[index] { + Node::Empty => None, + Node::Branch(branch_node) => branch_node.get(key), + Node::Leaf(leaf_node) => { + if key.starts_with_stem(leaf_node.stem()) { + leaf_node.get(key.suffix() as usize) + } else { + None + } + } + } + } + + pub(crate) fn get_child(&self, index: usize) -> &Node { + &self.children[index] + } + + fn set_child(&mut self, index: usize, mut child: Node) { + self.commitment.update_single( + index, + child.commitment_hash() - self.children[index].commitment_hash(), + ); + self.children[index] = child; + } + + /// Returns by how much the commitmant hash has changed and the path to the new branch node if + /// one was created. + pub fn update(&mut self, state_write: &StemStateWrite) -> (ScalarField, NewBranchNode) { + let index = state_write.stem[self.depth] as usize; + let child = &mut self.children[index]; + match child { + Node::Empty => { + let mut leaf_node = Box::new(LeafNode::new(state_write.stem)); + leaf_node.update(&state_write.writes); + *child = Node::Leaf(leaf_node); + ( + self.commitment + .update_single(index, child.commitment_hash()), + None, + ) + } + Node::Branch(branch_node) => { + let (commitment_hash_diff, new_branch_node) = branch_node.update(state_write); + ( + self.commitment.update_single(index, commitment_hash_diff), + new_branch_node, + ) + } + Node::Leaf(leaf_node) => { + if leaf_node.stem() == &state_write.stem { + let commitment_hash_diff = leaf_node.update(&state_write.writes); + ( + self.commitment.update_single(index, commitment_hash_diff), + None, + ) + } else { + let old_commitment_hash = leaf_node.commitment_hash(); + + let old_child_index_in_new_branch = leaf_node.stem()[self.depth + 1] as usize; + let old_child = mem::replace(child, Node::Empty); + + let mut branch_node = Box::new(Self::new(self.depth + 1)); + branch_node.set_child(old_child_index_in_new_branch, old_child); + branch_node.update(state_write); + + let new_branch_node = Some(TriePath::from( + state_write.stem[..branch_node.depth].to_vec(), + )); + *child = Node::Branch(branch_node); + ( + self.commitment + .update_single(index, child.commitment_hash() - old_commitment_hash), + new_branch_node, + ) + } + } + } + } +} diff --git a/portal-verkle-primitives/src/verkle/nodes/commitment.rs b/portal-verkle-primitives/src/verkle/nodes/commitment.rs new file mode 100644 index 0000000..859316c --- /dev/null +++ b/portal-verkle-primitives/src/verkle/nodes/commitment.rs @@ -0,0 +1,60 @@ +use std::ops::AddAssign; + +use crate::{Point, ScalarField, CRS}; + +pub struct Commitment { + commitment: Point, + commitment_hash: Option, +} + +impl Commitment { + pub fn new(commitment: Point) -> Self { + Self { + commitment, + commitment_hash: None, + } + } + + pub fn commitment(&self) -> &Point { + &self.commitment + } + + pub fn commitment_hash(&mut self) -> ScalarField { + self.commitment_hash + .get_or_insert_with(|| self.commitment.map_to_scalar_field()) + .clone() + } + + /// Updates this commitment and returns by how much the commitment hash changed. + /// + /// @param diff By how much scalar changed. + pub fn update_single(&mut self, index: usize, diff: ScalarField) -> ScalarField { + let old_commitment_hash = self.commitment_hash(); + *self += CRS::commit_single(index, diff); + self.commitment_hash() - old_commitment_hash + } + + /// Updates this commitment and returns by how much the commitment hash changed. + /// + /// @param diff By how much each inner scalar changed. + pub fn update(&mut self, diff: &[(usize, ScalarField)]) -> ScalarField { + let old_commitment_hash = self.commitment_hash(); + *self += CRS::commit_sparse(diff); + self.commitment_hash() - old_commitment_hash + } + + pub fn zero() -> Self { + Self::new(Point::zero()) + } + + pub fn is_zero(&self) -> bool { + self.commitment.is_zero() + } +} + +impl AddAssign for Commitment { + fn add_assign(&mut self, rhs: Point) { + self.commitment += rhs; + self.commitment_hash = None; + } +} diff --git a/portal-verkle-primitives/src/verkle/nodes/leaf.rs b/portal-verkle-primitives/src/verkle/nodes/leaf.rs new file mode 100644 index 0000000..79aec59 --- /dev/null +++ b/portal-verkle-primitives/src/verkle/nodes/leaf.rs @@ -0,0 +1,96 @@ +use std::collections::HashMap; + +use crate::{ + constants::{ + LEAF_C1_INDEX, LEAF_C2_INDEX, LEAF_MARKER_INDEX, LEAF_STEM_INDEX, VERKLE_NODE_WIDTH, + }, + ssz::SparseVector, + Point, ScalarField, Stem, TrieValue, TrieValueSplit, CRS, +}; + +use super::commitment::Commitment; + +pub struct LeafNode { + marker: u64, + stem: Stem, + commitment: Commitment, + c1: Commitment, + c2: Commitment, + values: SparseVector, +} + +impl LeafNode { + pub fn new(stem: Stem) -> Self { + let marker = 1; + + let commitment = CRS::commit_sparse(&[ + (LEAF_MARKER_INDEX, ScalarField::from(marker)), + (LEAF_STEM_INDEX, ScalarField::from(&stem)), + ]); + + Self { + marker, + stem, + commitment: Commitment::new(commitment), + c1: Commitment::zero(), + c2: Commitment::zero(), + values: SparseVector::default(), + } + } + + pub fn marker(&self) -> u64 { + self.marker + } + + pub fn stem(&self) -> &Stem { + &self.stem + } + + pub fn commitment(&self) -> &Point { + self.commitment.commitment() + } + + pub fn commitment_hash(&mut self) -> ScalarField { + self.commitment.commitment_hash() + } + + pub fn c1(&self) -> &Point { + self.c1.commitment() + } + + pub fn c2(&self) -> &Point { + self.c2.commitment() + } + + pub fn get(&self, index: usize) -> Option<&TrieValue> { + self.values[index].as_ref() + } + + /// Sets trie values and returns by how much the commitment hash changed. + pub fn update(&mut self, writes: &HashMap) -> ScalarField { + // Contains the changes of c1 and c2 + let mut c1_diff = vec![]; + let mut c2_diff = vec![]; + + for (index, new_value) in writes.iter() { + let index = *index as usize; + let suffix_index = index % (VERKLE_NODE_WIDTH / 2); + let suffix_commitment_diff = if index < VERKLE_NODE_WIDTH / 2 { + &mut c1_diff + } else { + &mut c2_diff + }; + + let (new_low_value, new_high_value) = new_value.split(); + let old_value = self.values[index].replace(*new_value); + let (old_low_value, old_high_value) = old_value.split(); + + suffix_commitment_diff.push((2 * suffix_index, new_low_value - old_low_value)); + suffix_commitment_diff.push((2 * suffix_index + 1, new_high_value - old_high_value)); + } + self.commitment.update(&[ + (LEAF_C1_INDEX, self.c1.update(&c1_diff)), + (LEAF_C2_INDEX, self.c2.update(&c2_diff)), + ]) + } +} diff --git a/portal-verkle-primitives/src/verkle/nodes/mod.rs b/portal-verkle-primitives/src/verkle/nodes/mod.rs new file mode 100644 index 0000000..b2acb8b --- /dev/null +++ b/portal-verkle-primitives/src/verkle/nodes/mod.rs @@ -0,0 +1,36 @@ +use branch::BranchNode; +use leaf::LeafNode; + +use crate::{Point, ScalarField}; + +pub mod branch; +pub mod commitment; +pub mod leaf; + +pub enum Node { + Empty, + Branch(Box), + Leaf(Box), +} + +impl Node { + pub fn commitment(&self) -> Point { + match self { + Node::Empty => Point::zero(), + Node::Branch(branch_node) => branch_node.commitment().clone(), + Node::Leaf(leaf_node) => leaf_node.commitment().clone(), + } + } + + pub fn commitment_hash(&mut self) -> ScalarField { + match self { + Node::Empty => ScalarField::zero(), + Node::Branch(branch_node) => branch_node.commitment_hash(), + Node::Leaf(leaf_node) => leaf_node.commitment_hash(), + } + } + + pub fn is_empty(&self) -> bool { + matches!(self, Node::Empty) + } +} diff --git a/portal-verkle-primitives/src/storage.rs b/portal-verkle-primitives/src/verkle/storage.rs similarity index 100% rename from portal-verkle-primitives/src/storage.rs rename to portal-verkle-primitives/src/verkle/storage.rs diff --git a/portal-verkle-primitives/src/verkle/trie.rs b/portal-verkle-primitives/src/verkle/trie.rs new file mode 100644 index 0000000..23a9b36 --- /dev/null +++ b/portal-verkle-primitives/src/verkle/trie.rs @@ -0,0 +1,163 @@ +use std::collections::{HashMap, HashSet}; + +use alloy_primitives::B256; + +use super::{ + nodes::{branch::BranchNode, Node}, + PathToLeaf, StemStateWrite, +}; +use crate::{ + ssz::TriePath, + verkle::{error::VerkleTrieError, StateWrites}, + Point, Stem, TrieKey, TrieValue, +}; + +/// Fully in-memory implementation of the Verkle Trie. +pub struct VerkleTrie { + root_node: BranchNode, +} + +impl VerkleTrie { + pub fn new() -> Self { + Self { + root_node: BranchNode::new(/* depth= */ 0), + } + } + + pub(super) fn root_node(&self) -> &BranchNode { + &self.root_node + } + + pub fn root_commitment(&self) -> &Point { + self.root_node.commitment() + } + + pub fn root(&self) -> B256 { + self.root_node.commitment().into() + } + + pub fn get(&self, key: &TrieKey) -> Option<&TrieValue> { + self.root_node.get(key) + } + + pub fn insert(&mut self, key: &TrieKey, value: TrieValue) { + let stem_state_write = StemStateWrite { + stem: key.stem(), + writes: HashMap::from([(key.suffix(), value)]), + }; + self.root_node.update(&stem_state_write); + } + + pub fn update(&mut self, state_writes: &StateWrites) -> HashSet { + let mut created_branches = HashSet::new(); + for stem_state_write in state_writes.iter() { + if let Some(created_branch) = self.root_node.update(stem_state_write).1 { + created_branches.insert(created_branch); + } + } + created_branches + } + + pub fn traverse_to_leaf<'me>( + &'me self, + stem: &Stem, + ) -> Result, VerkleTrieError> { + let mut branches = vec![]; + + let mut node = &self.root_node; + let mut depth = 0; + + loop { + branches.push(node); + node = match node.get_child(stem[depth] as usize) { + Node::Empty => return Err(VerkleTrieError::NodeNotFound { stem: *stem, depth }), + Node::Branch(next_node) => next_node, + Node::Leaf(leaf) => { + if leaf.stem() == stem { + return Ok(PathToLeaf { branches, leaf }); + } else { + return Err(VerkleTrieError::UnexpectedStem { + expected: *stem, + actual: *leaf.stem(), + }); + } + } + }; + depth += 1; + } + } +} + +impl Default for VerkleTrie { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + use std::{fs::File, io::BufReader, str::FromStr}; + + use alloy_primitives::{address, b256, keccak256}; + + use crate::{ + constants::{ + BALANCE_LEAF_KEY, CODE_KECCAK_LEAF_KEY, HEADER_STORAGE_OFFSET, NONCE_LEAF_KEY, + VERSION_LEAF_KEY, + }, + verkle::{genesis_config::GenesisConfig, storage::AccountStorageLayout}, + }; + + use super::*; + + fn read_genesis() -> GenesisConfig { + let reader = BufReader::new(File::open("../testdata/genesis.json").unwrap()); + serde_json::from_reader(reader).unwrap() + } + + #[test] + fn devnet6_genesis() { + let genesis_config = read_genesis(); + + let mut trie = VerkleTrie::new(); + trie.update(&genesis_config.into_state_writes()); + + assert_eq!(trie.root(), GenesisConfig::DEVNET6_STATE_ROOT) + } + + #[test] + fn devnet6_block1() { + let genesis_config = read_genesis(); + let block1_state_root = + b256!("5a65582e323fb83ed40438a0c33fa6ebfbc7f45e4c29d112b0142cfeb63f82af"); + + let mut trie = VerkleTrie::new(); + trie.update(&genesis_config.into_state_writes()); + + let storage_layout = + AccountStorageLayout::new(address!("fffffffffffffffffffffffffffffffffffffffe")); + let stem_state_write = StemStateWrite { + stem: *storage_layout.account_storage_stem(), + writes: HashMap::from([ + (VERSION_LEAF_KEY, TrieValue::ZERO), + (BALANCE_LEAF_KEY, TrieValue::ZERO), + (NONCE_LEAF_KEY, TrieValue::ZERO), + (CODE_KECCAK_LEAF_KEY, TrieValue::from(keccak256([]))), + ( + HEADER_STORAGE_OFFSET.byte(0), + TrieValue::from_str( + "0x3fe165c03e7a77d1e3759362ebeeb16fd964cb411ce11fbe35c7032fab5b9a8a", + ) + .unwrap(), + ), + ]), + }; + + let new_branch_nodes = trie.update(&StateWrites(vec![stem_state_write])); + assert_eq!( + new_branch_nodes, + [TriePath::new(vec![0x5b]).unwrap()].into() + ); + assert_eq!(trie.root(), block1_state_root); + } +} diff --git a/portal-verkle-primitives/src/verkle/trie_printer.rs b/portal-verkle-primitives/src/verkle/trie_printer.rs new file mode 100644 index 0000000..cb1e16e --- /dev/null +++ b/portal-verkle-primitives/src/verkle/trie_printer.rs @@ -0,0 +1,142 @@ +use std::io::{self, Write}; + +use alloy_primitives::hex::{encode, encode_prefixed}; + +use super::{ + nodes::{branch::BranchNode, leaf::LeafNode, Node}, + VerkleTrie, +}; +use crate::constants::VERKLE_NODE_WIDTH; + +pub trait TriePrinter { + /// Prints all Trie key-value pairs. + fn print_state(&self, writer: &mut W) -> io::Result<()>; + + /// Prints entire trie structure, with all intermediate commitments. + fn print_trie_with_identation( + &self, + writer: &mut W, + identation: usize, + ) -> io::Result<()>; +} + +impl TriePrinter for VerkleTrie { + fn print_state(&self, writer: &mut W) -> io::Result<()> { + self.root_node().print_state(writer)?; + writer.flush() + } + + fn print_trie_with_identation( + &self, + writer: &mut W, + identation: usize, + ) -> io::Result<()> { + writeln!(writer, "{:identation$}root - {}", "", self.root())?; + self.root_node() + .print_trie_with_identation(writer, identation + 2) + } +} + +impl TriePrinter for Node { + fn print_state(&self, writer: &mut W) -> io::Result<()> { + match self { + Node::Empty => Ok(()), + Node::Branch(branch_node) => branch_node.print_state(writer), + Node::Leaf(leaf_node) => leaf_node.print_state(writer), + } + } + + fn print_trie_with_identation( + &self, + writer: &mut W, + identation: usize, + ) -> io::Result<()> { + match self { + Node::Empty => Ok(()), + Node::Branch(branch_node) => branch_node.print_trie_with_identation(writer, identation), + Node::Leaf(leaf_node) => leaf_node.print_trie_with_identation(writer, identation), + } + } +} + +impl TriePrinter for BranchNode { + fn print_state(&self, writer: &mut W) -> io::Result<()> { + for index in 0..VERKLE_NODE_WIDTH { + self.get_child(index).print_state(writer)?; + } + Ok(()) + } + + fn print_trie_with_identation( + &self, + writer: &mut W, + identation: usize, + ) -> io::Result<()> { + for index in 0..VERKLE_NODE_WIDTH { + let child = self.get_child(index); + if child.is_empty() { + continue; + } + writeln!( + writer, + "{:identation$}{index:02x} - {:?}", + "", + child.commitment() + )?; + child.print_trie_with_identation(writer, identation + 2)?; + } + Ok(()) + } +} + +impl TriePrinter for LeafNode { + fn print_state(&self, writer: &mut W) -> io::Result<()> { + for index in 0..VERKLE_NODE_WIDTH { + if let Some(value) = self.get(index) { + writeln!( + writer, + "{}{index:02x}: {}", + encode(self.stem()), + encode(value.as_slice()), + )?; + } + } + Ok(()) + } + + fn print_trie_with_identation( + &self, + writer: &mut W, + identation: usize, + ) -> io::Result<()> { + writeln!(writer, "{:identation$}stem - {}", "", self.stem())?; + + writeln!(writer, "{:identation$}C1 - {:?}", "", self.c1())?; + for index in 0..(VERKLE_NODE_WIDTH / 2) { + if let Some(value) = self.get(index) { + writeln!( + writer, + " {:identation$}{index:02x} - {}", + "", + encode_prefixed(value.as_slice()), + identation = identation + 2, + )?; + } + } + + writeln!(writer, "{:identation$}C2 - {:?}", "", self.c2())?; + for index in (VERKLE_NODE_WIDTH / 2)..VERKLE_NODE_WIDTH { + if let Some(value) = self.get(index) { + writeln!( + writer, + " {:identation$}{index:02x} - {}", + "", + encode_prefixed(value.as_slice()), + identation = identation + 2, + )?; + } + } + + Ok(()) + } +} diff --git a/testdata/genesis.json b/testdata/genesis.json new file mode 100644 index 0000000..2e229e7 --- /dev/null +++ b/testdata/genesis.json @@ -0,0 +1,901 @@ +{ + "config": { + "chainId": 69420, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "mergeNetsplitBlock": 0, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true, + "shanghaiTime": 0, + "pragueTime": 1712918460, + "proofInBlocks": true + }, + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000001": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000002": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000003": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000004": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000005": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000006": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000007": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000008": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000009": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000010": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000011": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000012": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000013": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000014": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000015": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000016": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000017": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000018": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000019": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000020": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000021": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000022": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000023": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000024": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000025": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000026": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000027": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000028": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000029": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000030": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000031": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000032": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000033": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000034": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000035": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000036": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000037": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000038": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000039": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000040": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000041": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000042": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000043": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000044": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000045": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000046": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000047": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000048": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000049": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000050": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000051": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000052": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000053": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000054": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000055": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000056": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000057": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000058": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000059": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000060": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000061": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000062": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000063": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000064": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000065": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000066": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000067": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000068": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000069": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000070": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000071": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000072": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000073": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000074": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000075": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000076": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000077": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000078": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000079": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000080": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000081": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000082": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000083": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000084": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000085": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000086": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000087": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000088": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000089": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000090": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000091": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000092": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000093": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000094": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000095": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000096": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000097": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000098": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000099": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009f": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000aa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ab": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ac": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ad": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ae": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000af": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ba": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000be": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ca": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ce": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000da": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000db": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000de": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000df": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ea": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000eb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ec": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ed": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ee": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ef": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fe": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ff": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000b": { + "balance": "0", + "nonce": "1", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b42620180004206555f3562018000420662018000015500" + }, + "0x6f22fFbC56eFF051aECF839396DD1eD9aD6BBA9D": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + }, + "0x454b0EA7d8aD3C56D0CF2e44Ed97b2Feab4D7AF2": { + "balance": "1000000000000000000000000000" + }, + "0xd3248BA3E5492D767F8e427Cb9C7B9D5C3972D7B": { + "balance": "1000000000000000000000000000" + }, + "0xAD01b55d7c3448B8899862eb335FBb17075d8DE2": { + "balance": "1000000000000000000000000000" + }, + "0x7e454a14B8e7528465eeF86f0DC1da4f235d9D79": { + "balance": "1000000000000000000000000000" + }, + "0x7a40026A3b9A41754a95EeC8c92C6B99886f440C": { + "balance": "1000000000000000000000000000" + }, + "0x8c4D8CDD1f474510Dd70D66F2785a3a38a29AC1A": { + "balance": "1000000000000000000000000000" + }, + "0xfC7360b3b28cf4204268A8354dbEc60720d155D2": { + "balance": "1000000000000000000000000000" + }, + "0x2F7626bBDb8c0f9071bC98046Ef6fDed2167F97F": { + "balance": "1000000000000000000000000000" + }, + "0x752CE31Dec0dde7D1563CdF6438d892De2D4FBee": { + "balance": "1000000000000000000000000000" + }, + "0x455f42d91096c4Aa708D7Cbcb2DC499dE89C402c": { + "balance": "1000000000000000000000000000" + }, + "0x85154341488732D57a97F54AB9706Bc4B71B8636": { + "balance": "1000000000000000000000000000" + }, + "0x6a9CcA73d4Ff3a249fa778C7651f4Df8B9fFa0Df": { + "balance": "1000000000000000000000000000" + }, + "0xee2d0567AAe8080CA269b7908F4aF8BBb59A6804": { + "balance": "1000000000000000000000000000" + }, + "0xDd8D4027078a471816e4Ef7F69aFc0A5d2947dDc": { + "balance": "1000000000000000000000000000" + }, + "0x20466E9A67f299F6056bE52A50ea324FA6Bd05D5": { + "balance": "1000000000000000000000000000" + }, + "0x03F24BB0C9cfb30217Ff992A36ae9230F2A1697f": { + "balance": "1000000000000000000000000000" + }, + "0x032d8372C519c3927b87BDe4479E846a81EF2d10": { + "balance": "1000000000000000000000000000" + }, + "0xF863DF14954df73804b3150F3754a8F98CBB1D0d": { + "balance": "1000000000000000000000000000" + }, + "0xbe918A6aef1920F3706E23d153146aA6C5982620": { + "balance": "1000000000000000000000000000" + }, + "0xA0c7edA3CE474BC670A11EA9537cBEfd36331123": { + "balance": "1000000000000000000000000000" + }, + "0xF03b43BeB861044492Eb43E247bEE2AC6C80c651": { + "balance": "1000000000000000000000000000" + } + }, + "coinbase": "0x0000000000000000000000000000000000000000", + "difficulty": "0x01", + "extraData": "", + "gasLimit": "0x17D7840", + "nonce": "0x1234", + "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "1712918460" +}