From 4ef831bd310fd7ec162aa4408f2af3ae7ec20a4b Mon Sep 17 00:00:00 2001 From: Robin Salen <30937548+Nashtare@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:05:09 -0400 Subject: [PATCH] feat: add consolidated block hashes across checkpoints (#551) --- Cargo.lock | 1 + .../benches/fibonacci_25m_gas.rs | 5 +- .../src/cpu/kernel/interpreter.rs | 4 +- .../src/cpu/kernel/tests/add11.rs | 6 +- .../src/cpu/kernel/tests/init_exc_stop.rs | 5 +- .../src/fixed_recursive_verifier.rs | 63 +- evm_arithmetization/src/generation/mod.rs | 29 +- .../src/generation/segments.rs | 4 +- evm_arithmetization/src/generation/state.rs | 9 +- evm_arithmetization/src/get_challenges.rs | 6 +- evm_arithmetization/src/lib.rs | 2 +- evm_arithmetization/src/proof.rs | 245 ++++-- evm_arithmetization/src/prover.rs | 12 +- evm_arithmetization/src/recursive_verifier.rs | 54 +- evm_arithmetization/src/verifier.rs | 6 +- evm_arithmetization/src/witness/util.rs | 9 +- evm_arithmetization/tests/add11_yml.rs | 7 +- evm_arithmetization/tests/erc20.rs | 5 +- evm_arithmetization/tests/erc721.rs | 5 +- evm_arithmetization/tests/global_exit_root.rs | 5 +- evm_arithmetization/tests/log_opcode.rs | 5 +- evm_arithmetization/tests/selfdestruct.rs | 5 +- evm_arithmetization/tests/simple_transfer.rs | 5 +- evm_arithmetization/tests/two_to_one_block.rs | 15 +- evm_arithmetization/tests/withdrawals.rs | 5 +- proof_gen/src/proof_gen.rs | 2 +- proof_gen/src/proof_types.rs | 12 +- proof_gen/src/types.rs | 1 + trace_decoder/src/core.rs | 10 +- trace_decoder/src/decoding.rs | 713 +++++++++++++++++ trace_decoder/src/interface.rs | 5 + trace_decoder/src/lib.rs | 5 + trace_decoder/tests/cases/b19807080_main.json | 8 +- trace_decoder/tests/cases/b19840104_main.json | 730 +++++++++--------- trace_decoder/tests/cases/b20240052_main.json | 10 +- trace_decoder/tests/cases/b20240058_main.json | 10 +- trace_decoder/tests/cases/b20472570_main.json | 8 +- trace_decoder/tests/cases/b28_dev.json | 8 +- trace_decoder/tests/cases/b4_dev.json | 8 +- zero_bin/common/src/prover_state/mod.rs | 7 +- zero_bin/leader/src/client.rs | 13 +- zero_bin/ops/src/lib.rs | 14 +- zero_bin/rpc/Cargo.toml | 3 + zero_bin/rpc/src/jerigon.rs | 9 +- zero_bin/rpc/src/lib.rs | 31 +- zero_bin/rpc/src/main.rs | 14 +- zero_bin/rpc/src/native/mod.rs | 5 +- .../tools/artifacts/witness_b19807080.json | 10 +- zero_bin/tools/artifacts/witness_b3_b6.json | 34 +- 49 files changed, 1607 insertions(+), 580 deletions(-) create mode 100644 trace_decoder/src/decoding.rs diff --git a/Cargo.lock b/Cargo.lock index 4eaf1f7ce..b947424d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4175,6 +4175,7 @@ dependencies = [ "itertools 0.13.0", "mpt_trie", "primitive-types 0.12.2", + "proof_gen", "prover", "serde", "serde_json", diff --git a/evm_arithmetization/benches/fibonacci_25m_gas.rs b/evm_arithmetization/benches/fibonacci_25m_gas.rs index 28c9a2333..f6d5fc39f 100644 --- a/evm_arithmetization/benches/fibonacci_25m_gas.rs +++ b/evm_arithmetization/benches/fibonacci_25m_gas.rs @@ -26,6 +26,8 @@ use keccak_hash::keccak; use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; type F = GoldilocksField; @@ -50,7 +52,7 @@ fn criterion_benchmark(c: &mut Criterion) { simulate_execution::(inputs).unwrap(); } -fn prepare_setup() -> anyhow::Result { +fn prepare_setup() -> anyhow::Result> { let sender = hex!("8943545177806ED17B9F23F0a21ee5948eCaa776"); let to = hex!("159271B89fea49aF29DFaf8b4eCE7D042D5d6f07"); @@ -181,6 +183,7 @@ fn prepare_setup() -> anyhow::Result { checkpoint_state_trie_root: H256(hex!( "fe07ff6d1ab215df17884b89112ccf2373597285a56c5902150313ad1a53ee57" )), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], ger_data: None, block_metadata, txn_number_before: 0.into(), diff --git a/evm_arithmetization/src/cpu/kernel/interpreter.rs b/evm_arithmetization/src/cpu/kernel/interpreter.rs index ec54b308d..8a1f6471c 100644 --- a/evm_arithmetization/src/cpu/kernel/interpreter.rs +++ b/evm_arithmetization/src/cpu/kernel/interpreter.rs @@ -154,7 +154,7 @@ impl Interpreter { pub(crate) fn new_with_generation_inputs( initial_offset: usize, initial_stack: Vec, - inputs: &GenerationInputs, + inputs: &GenerationInputs, max_cpu_len_log: Option, ) -> Self { debug_inputs(inputs); @@ -216,7 +216,7 @@ impl Interpreter { } /// Initializes the interpreter state given `GenerationInputs`. - pub(crate) fn initialize_interpreter_state(&mut self, inputs: &GenerationInputs) { + pub(crate) fn initialize_interpreter_state(&mut self, inputs: &GenerationInputs) { // Initialize registers. let registers_before = RegistersState::new(); self.generation_state.registers = RegistersState { diff --git a/evm_arithmetization/src/cpu/kernel/tests/add11.rs b/evm_arithmetization/src/cpu/kernel/tests/add11.rs index 9e44c8bfa..fe36b40e3 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/add11.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/add11.rs @@ -9,6 +9,8 @@ use keccak_hash::keccak; use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, Node, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField as F; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -174,7 +176,7 @@ fn test_add11_yml() { receipts_root: receipts_trie.hash(), }; - let inputs = GenerationInputs { + let inputs = GenerationInputs:: { signed_txns: vec![txn.to_vec()], burn_addr: None, withdrawals: vec![], @@ -184,6 +186,7 @@ fn test_add11_yml() { contract_code: contract_code.clone(), block_metadata, checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], txn_number_before: 0.into(), gas_used_before: 0.into(), gas_used_after: gas_used, @@ -360,6 +363,7 @@ fn test_add11_yml_with_exception() { contract_code: contract_code.clone(), block_metadata, checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], txn_number_before: 0.into(), gas_used_before: 0.into(), gas_used_after: txn_gas_limit.into(), diff --git a/evm_arithmetization/src/cpu/kernel/tests/init_exc_stop.rs b/evm_arithmetization/src/cpu/kernel/tests/init_exc_stop.rs index 57ad232cb..be88021de 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/init_exc_stop.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/init_exc_stop.rs @@ -4,6 +4,8 @@ use ethereum_types::U256; use keccak_hash::{keccak, H256}; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField as F; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; use crate::cpu::kernel::{aggregator::KERNEL, interpreter::Interpreter}; use crate::generation::{ @@ -76,7 +78,7 @@ fn test_init_exc_stop() { receipts_root: receipts_trie.hash(), }; - let inputs = GenerationInputs { + let inputs = GenerationInputs:: { signed_txns: vec![], burn_addr: None, withdrawals: vec![], @@ -89,6 +91,7 @@ fn test_init_exc_stop() { trie_roots_after, contract_code, checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index be9a3daeb..459e33c93 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -69,7 +69,7 @@ where { pub is_dummy: bool, pub proof_with_pis: ProofWithPublicInputs, - pub public_values: PublicValues, + pub public_values: PublicValues, } /// Contains all recursive circuits used in the system. For each STARK and each @@ -1347,9 +1347,6 @@ where let parent_block_proof = builder.add_virtual_proof_with_pis(&expected_common_data); let agg_root_proof = builder.add_virtual_proof_with_pis(&agg.circuit.common); - // Connect block hashes - Self::connect_block_hashes(&mut builder, &parent_block_proof, &agg_root_proof); - let parent_pv = PublicValuesTarget::from_public_inputs(&parent_block_proof.public_inputs); let agg_pv = PublicValuesTarget::from_public_inputs(&agg_root_proof.public_inputs); @@ -1555,7 +1552,7 @@ where // This also enforces that the initial state trie root that will be stored in // these `FinalPublicValues` actually matches the known checkpoint state trie // root. - final_pv.connect_parent(&mut builder, &parent_pv); + final_pv.connect_parent::(&mut builder, &parent_pv); let block_verifier_data = builder.constant_verifier_data(&block.circuit.verifier_only); @@ -1672,13 +1669,11 @@ where /// Connect the 256 block hashes between two blocks fn connect_block_hashes( builder: &mut CircuitBuilder, - lhs: &ProofWithPublicInputsTarget, - rhs: &ProofWithPublicInputsTarget, + lhs_public_values: &PublicValuesTarget, + rhs_public_values: &PublicValuesTarget, ) { - let lhs_public_values = PublicValuesTarget::from_public_inputs(&lhs.public_inputs); - let rhs_public_values = PublicValuesTarget::from_public_inputs(&rhs.public_inputs); for i in 0..255 { - for j in 0..8 { + for j in 0..TARGET_HASH_SIZE { builder.connect( lhs_public_values.block_hashes.prev_hashes[8 * (i + 1) + j], rhs_public_values.block_hashes.prev_hashes[8 * i + j], @@ -1687,7 +1682,7 @@ where } let expected_hash = lhs_public_values.block_hashes.cur_hash; let prev_block_hash = &rhs_public_values.block_hashes.prev_hashes[255 * 8..256 * 8]; - for i in 0..expected_hash.len() { + for i in 0..TARGET_HASH_SIZE { builder.connect(expected_hash[i], prev_block_hash[i]); } } @@ -1736,6 +1731,9 @@ where // Check that the checkpoint block has the predetermined state trie root in // `ExtraBlockData`. Self::connect_checkpoint_block(builder, rhs, has_not_parent_block); + + // Connect block hashes + Self::connect_block_hashes(builder, lhs, rhs); } fn connect_checkpoint_block( @@ -1755,6 +1753,18 @@ where constr = builder.mul(has_not_parent_block, constr); builder.assert_zero(constr); } + + let consolidated_hash = builder + .hash_n_to_hash_no_pad::(x.block_hashes.prev_hashes.to_vec()) + .elements; + + for i in 0..NUM_HASH_OUT_ELTS { + builder.conditional_assert_eq( + has_not_parent_block, + x.extra_block_data.checkpoint_consolidated_hash[i], + consolidated_hash[i], + ) + } } fn connect_final_block_values_to_intermediary( @@ -1818,7 +1828,7 @@ where &self, all_stark: &AllStark, config: &StarkConfig, - generation_inputs: TrimmedGenerationInputs, + generation_inputs: TrimmedGenerationInputs, segment_data: &mut GenerationSegmentData, timing: &mut TimingTree, abort_signal: Option>, @@ -1893,7 +1903,7 @@ where &self, all_stark: &AllStark, config: &StarkConfig, - generation_inputs: GenerationInputs, + generation_inputs: GenerationInputs, max_cpu_len_log: usize, timing: &mut TimingTree, abort_signal: Option>, @@ -1985,7 +1995,7 @@ where all_proof: AllProof, table_circuits: &[(RecursiveCircuitsForTableSize, u8); NUM_TABLES], abort_signal: Option>, - ) -> anyhow::Result<(ProofWithPublicInputs, PublicValues)> { + ) -> anyhow::Result<(ProofWithPublicInputs, PublicValues)> { let mut root_inputs = PartialWitness::new(); for table in 0..NUM_TABLES { @@ -2106,6 +2116,9 @@ where checkpoint_state_trie_root: lhs_public_values .extra_block_data .checkpoint_state_trie_root, + checkpoint_consolidated_hash: lhs_public_values + .extra_block_data + .checkpoint_consolidated_hash, txn_number_before: lhs_public_values.extra_block_data.txn_number_before, txn_number_after: real_public_values.extra_block_data.txn_number_after, gas_used_before: lhs_public_values.extra_block_data.gas_used_before, @@ -2175,11 +2188,11 @@ where &self, lhs_is_agg: bool, lhs_proof: &ProofWithPublicInputs, - lhs_public_values: PublicValues, + lhs_public_values: PublicValues, rhs_is_agg: bool, rhs_proof: &ProofWithPublicInputs, - rhs_public_values: PublicValues, - ) -> anyhow::Result<(ProofWithPublicInputs, PublicValues)> { + rhs_public_values: PublicValues, + ) -> anyhow::Result<(ProofWithPublicInputs, PublicValues)> { let mut txn_inputs = PartialWitness::new(); Self::set_dummy_if_necessary( @@ -2290,8 +2303,8 @@ where &self, opt_parent_block_proof: Option<&ProofWithPublicInputs>, agg_root_proof: &ProofWithPublicInputs, - public_values: PublicValues, - ) -> anyhow::Result<(ProofWithPublicInputs, PublicValues)> { + public_values: PublicValues, + ) -> anyhow::Result<(ProofWithPublicInputs, PublicValues)> { let mut block_inputs = PartialWitness::new(); block_inputs.set_bool_target( @@ -2387,14 +2400,14 @@ where + TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE + BlockHashesTarget::SIZE - - 8; - + - 16; for i in 0..public_values.block_hashes.prev_hashes.len() - 1 { let targets = h256_limbs::(public_values.block_hashes.prev_hashes[i]); for j in 0..8 { nonzero_pis.insert(block_hashes_keys.start + 8 * (i + 1) + j, targets[j]); } } + let block_hashes_current_start = burn_addr_offset + TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE @@ -2474,11 +2487,15 @@ where /// This method outputs a tuple of [`ProofWithPublicInputs`] and /// associated [`FinalPublicValues`]. Only the proof with public inputs is /// necessary for a verifier to assert correctness of the computation. + #[allow(clippy::type_complexity)] pub fn prove_block_wrapper( &self, block_proof: &ProofWithPublicInputs, - public_values: PublicValues, - ) -> anyhow::Result<(ProofWithPublicInputs, FinalPublicValues)> { + public_values: PublicValues, + ) -> anyhow::Result<( + ProofWithPublicInputs, + FinalPublicValues, + )> { let mut block_wrapper_inputs = PartialWitness::new(); block_wrapper_inputs diff --git a/evm_arithmetization/src/generation/mod.rs b/evm_arithmetization/src/generation/mod.rs index f30e1e5de..89e697865 100644 --- a/evm_arithmetization/src/generation/mod.rs +++ b/evm_arithmetization/src/generation/mod.rs @@ -8,7 +8,7 @@ use log::log_enabled; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::extension::Extendable; use plonky2::field::polynomial::PolynomialValues; -use plonky2::hash::hash_types::RichField; +use plonky2::hash::hash_types::{RichField, NUM_HASH_OUT_ELTS}; use plonky2::timed; use plonky2::util::timing::TimingTree; use segments::GenerationSegmentData; @@ -54,7 +54,8 @@ pub type MemBeforeValues = Vec<(MemoryAddress, U256)>; /// Inputs needed for trace generation. #[derive(Clone, Debug, Deserialize, Serialize, Default)] -pub struct GenerationInputs { +#[serde(bound = "")] +pub struct GenerationInputs { /// The index of the transaction being proven within its block. pub txn_number_before: U256, /// The cumulative gas used through the execution of all transactions prior @@ -87,6 +88,9 @@ pub struct GenerationInputs { /// without requiring proofs for blocks past this checkpoint. pub checkpoint_state_trie_root: H256, + /// Consolidated previous block hashes, at the checkpoint block. + pub checkpoint_consolidated_hash: [F; NUM_HASH_OUT_ELTS], + /// Mapping between smart contract code hashes and the contract byte code. /// All account smart contracts that are invoked will have an entry present. pub contract_code: HashMap>, @@ -108,7 +112,8 @@ pub struct GenerationInputs { /// A lighter version of [`GenerationInputs`], which have been trimmed /// post pre-initialization processing. #[derive(Clone, Debug, Deserialize, Serialize, Default)] -pub struct TrimmedGenerationInputs { +#[serde(bound = "")] +pub struct TrimmedGenerationInputs { pub trimmed_tries: TrimmedTrieInputs, /// The index of the first transaction in this payload being proven within /// its block. @@ -135,6 +140,9 @@ pub struct TrimmedGenerationInputs { /// without requiring proofs for blocks past this checkpoint. pub checkpoint_state_trie_root: H256, + /// Consolidated previous block hashes, at the checkpoint block. + pub checkpoint_consolidated_hash: [F; NUM_HASH_OUT_ELTS], + /// Mapping between smart contract code hashes and the contract byte code. /// All account smart contracts that are invoked will have an entry present. pub contract_code: HashMap>, @@ -194,11 +202,11 @@ impl TrieInputs { } } } -impl GenerationInputs { +impl GenerationInputs { /// Outputs a trimmed version of the `GenerationInputs`, that do not contain /// the fields that have already been processed during pre-initialization, /// namely: the input tries, the signed transaction, and the withdrawals. - pub(crate) fn trim(&self) -> TrimmedGenerationInputs { + pub(crate) fn trim(&self) -> TrimmedGenerationInputs { let txn_hashes = self .signed_txns .iter() @@ -218,6 +226,7 @@ impl GenerationInputs { }, trie_roots_after: self.trie_roots_after.clone(), checkpoint_state_trie_root: self.checkpoint_state_trie_root, + checkpoint_consolidated_hash: self.checkpoint_consolidated_hash, contract_code: self.contract_code.clone(), burn_addr: self.burn_addr, block_metadata: self.block_metadata.clone(), @@ -228,7 +237,7 @@ impl GenerationInputs { fn apply_metadata_and_tries_memops, const D: usize>( state: &mut GenerationState, - inputs: &TrimmedGenerationInputs, + inputs: &TrimmedGenerationInputs, registers_before: &RegistersData, registers_after: &RegistersData, ) { @@ -390,7 +399,7 @@ fn apply_metadata_and_tries_memops, const D: usize> state.traces.memory_ops.extend(ops); } -pub(crate) fn debug_inputs(inputs: &GenerationInputs) { +pub(crate) fn debug_inputs(inputs: &GenerationInputs) { log::debug!("Input signed_txns: {:?}", &inputs.signed_txns); log::debug!("Input state_trie: {:?}", &inputs.tries.state_trie); log::debug!( @@ -445,10 +454,11 @@ fn get_all_memory_address_and_values(memory_before: &MemoryState) -> Vec<(Memory res } -type TablesWithPVsAndFinalMem = ([Vec>; NUM_TABLES], PublicValues); +type TablesWithPVsAndFinalMem = ([Vec>; NUM_TABLES], PublicValues); + pub fn generate_traces, const D: usize>( all_stark: &AllStark, - inputs: &TrimmedGenerationInputs, + inputs: &TrimmedGenerationInputs, config: &StarkConfig, segment_data: &mut GenerationSegmentData, timing: &mut TimingTree, @@ -507,6 +517,7 @@ pub fn generate_traces, const D: usize>( let extra_block_data = ExtraBlockData { checkpoint_state_trie_root: inputs.checkpoint_state_trie_root, + checkpoint_consolidated_hash: inputs.checkpoint_consolidated_hash, txn_number_before: inputs.txn_number_before, txn_number_after, gas_used_before: inputs.gas_used_before, diff --git a/evm_arithmetization/src/generation/segments.rs b/evm_arithmetization/src/generation/segments.rs index cc90154dc..f25f2e8bc 100644 --- a/evm_arithmetization/src/generation/segments.rs +++ b/evm_arithmetization/src/generation/segments.rs @@ -90,7 +90,7 @@ pub type SegmentRunResult = Option SegmentDataIterator { - pub fn new(inputs: &GenerationInputs, max_cpu_len_log: Option) -> Self { + pub fn new(inputs: &GenerationInputs, max_cpu_len_log: Option) -> Self { debug_inputs(inputs); let interpreter = Interpreter::::new_with_generation_inputs( @@ -168,7 +168,7 @@ impl SegmentDataIterator { } impl Iterator for SegmentDataIterator { - type Item = AllData; + type Item = AllData; fn next(&mut self) -> Option { let run = self.generate_next_segment(self.partial_next_data.clone()); diff --git a/evm_arithmetization/src/generation/state.rs b/evm_arithmetization/src/generation/state.rs index 9eef07f65..2630ba544 100644 --- a/evm_arithmetization/src/generation/state.rs +++ b/evm_arithmetization/src/generation/state.rs @@ -334,7 +334,7 @@ pub(crate) trait State { #[derive(Debug, Default)] pub struct GenerationState { - pub(crate) inputs: TrimmedGenerationInputs, + pub(crate) inputs: TrimmedGenerationInputs, pub(crate) registers: RegistersState, pub(crate) memory: MemoryState, pub(crate) traces: Traces, @@ -404,7 +404,10 @@ impl GenerationState { trie_roots_ptrs } - pub(crate) fn new(inputs: &GenerationInputs, kernel_code: &[u8]) -> Result { + pub(crate) fn new( + inputs: &GenerationInputs, + kernel_code: &[u8], + ) -> Result { let rlp_prover_inputs = all_rlp_prover_inputs_reversed(&inputs.signed_txns); let withdrawal_prover_inputs = all_withdrawals_prover_inputs_reversed(&inputs.withdrawals); let ger_prover_inputs = all_ger_prover_inputs(inputs.ger_data); @@ -437,7 +440,7 @@ impl GenerationState { } pub(crate) fn new_with_segment_data( - trimmed_inputs: &TrimmedGenerationInputs, + trimmed_inputs: &TrimmedGenerationInputs, segment_data: &GenerationSegmentData, ) -> Result { let mut state = Self { diff --git a/evm_arithmetization/src/get_challenges.rs b/evm_arithmetization/src/get_challenges.rs index 7a8e25f58..5f0df7cfa 100644 --- a/evm_arithmetization/src/get_challenges.rs +++ b/evm_arithmetization/src/get_challenges.rs @@ -116,9 +116,10 @@ fn observe_extra_block_data< const D: usize, >( challenger: &mut Challenger, - extra_data: &ExtraBlockData, + extra_data: &ExtraBlockData, ) -> Result<(), ProgramError> { challenger.observe_elements(&h256_limbs(extra_data.checkpoint_state_trie_root)); + challenger.observe_elements(&extra_data.checkpoint_consolidated_hash); challenger.observe_element(u256_to_u32(extra_data.txn_number_before)?); challenger.observe_element(u256_to_u32(extra_data.txn_number_after)?); challenger.observe_element(u256_to_u32(extra_data.gas_used_before)?); @@ -138,6 +139,7 @@ fn observe_extra_block_data_target< C::Hasher: AlgebraicHasher, { challenger.observe_elements(&extra_data.checkpoint_state_trie_root); + challenger.observe_elements(&extra_data.checkpoint_consolidated_hash); challenger.observe_element(extra_data.txn_number_before); challenger.observe_element(extra_data.txn_number_after); challenger.observe_element(extra_data.gas_used_before); @@ -205,7 +207,7 @@ pub(crate) fn observe_public_values< const D: usize, >( challenger: &mut Challenger, - public_values: &PublicValues, + public_values: &PublicValues, ) -> Result<(), ProgramError> { observe_trie_roots::(challenger, &public_values.trie_roots_before); observe_trie_roots::(challenger, &public_values.trie_roots_after); diff --git a/evm_arithmetization/src/lib.rs b/evm_arithmetization/src/lib.rs index bdabc1c79..3587293d5 100644 --- a/evm_arithmetization/src/lib.rs +++ b/evm_arithmetization/src/lib.rs @@ -243,4 +243,4 @@ pub use starky::config::StarkConfig; /// Returned type from a `SegmentDataIterator`, needed to prove all segments in /// a transaction batch. -pub type AllData = Result<(TrimmedGenerationInputs, GenerationSegmentData), SegmentError>; +pub type AllData = Result<(TrimmedGenerationInputs, GenerationSegmentData), SegmentError>; diff --git a/evm_arithmetization/src/proof.rs b/evm_arithmetization/src/proof.rs index 8c4742a07..d4a04deff 100644 --- a/evm_arithmetization/src/proof.rs +++ b/evm_arithmetization/src/proof.rs @@ -1,9 +1,12 @@ +use std::marker::PhantomData; + use ethereum_types::{Address, H256, U256}; +use itertools::Itertools; use plonky2::field::extension::Extendable; use plonky2::hash::hash_types::{HashOutTarget, MerkleCapTarget, RichField, NUM_HASH_OUT_ELTS}; use plonky2::iop::target::{BoolTarget, Target}; use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::config::GenericConfig; +use plonky2::plonk::config::{GenericConfig, GenericHashOut, Hasher}; use plonky2::util::serialization::{Buffer, IoResult, Read, Write}; use serde::{Deserialize, Serialize}; use starky::config::StarkConfig; @@ -11,7 +14,7 @@ use starky::lookup::GrandProductChallengeSet; use starky::proof::{MultiProof, StarkProofChallenges}; use crate::all_stark::NUM_TABLES; -use crate::util::{get_h160, get_h256, get_u256, h2u}; +use crate::util::{get_h160, get_h256, get_u256, h256_limbs, h2u}; use crate::witness::state::RegistersState; /// The default cap height used for our zkEVM STARK proofs. @@ -27,7 +30,7 @@ pub struct AllProof, C: GenericConfig, co /// their cross-table lookup challenges. pub multi_proof: MultiProof, /// Public memory values used for the recursive proofs. - pub public_values: PublicValues, + pub public_values: PublicValues, } impl, C: GenericConfig, const D: usize> AllProof { @@ -47,7 +50,8 @@ pub(crate) struct AllProofChallenges, const D: usiz /// Memory values which are public. #[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)] -pub struct PublicValues { +#[serde(bound = "")] +pub struct PublicValues { /// Trie hashes before the execution of the local state transition pub trie_roots_before: TrieRoots, /// Trie hashes after the execution of the local state transition. @@ -60,7 +64,7 @@ pub struct PublicValues { /// 256 previous block hashes and current block's hash. pub block_hashes: BlockHashes, /// Extra block data that is specific to the current proof. - pub extra_block_data: ExtraBlockData, + pub extra_block_data: ExtraBlockData, /// Registers to initialize the current proof. pub registers_before: RegistersData, /// Registers at the end of the current proof. @@ -70,12 +74,12 @@ pub struct PublicValues { pub mem_after: MemCap, } -impl PublicValues { +impl PublicValues { /// Extracts public values from the given public inputs of a proof. /// Public values are always the first public inputs added to the circuit, /// so we can start extracting at index 0. /// `len_mem_cap` is the length of the `MemBefore` and `MemAfter` caps. - pub fn from_public_inputs(pis: &[F]) -> Self { + pub fn from_public_inputs(pis: &[F]) -> Self { assert!(pis.len() >= PublicValuesTarget::SIZE); let mut offset = 0; @@ -130,37 +134,64 @@ impl PublicValues { /// Memory values which are public once a final block proof is generated. #[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)] -pub struct FinalPublicValues { +#[serde(bound = "")] +pub struct FinalPublicValues> { + /// The chain id of this chian. + pub chain_id: U256, /// State trie root before the execution of this global state transition. - pub state_trie_root_before: H256, + pub checkpoint_state_trie_root: H256, /// State trie root after the execution of this global state transition. - pub state_trie_root_after: H256, + pub new_state_trie_root: H256, + /// A compact view of the block hashes before the previous checkpoint. + pub checkpoint_consolidated_hash: [F; NUM_HASH_OUT_ELTS], + /// A compact view of the previous block hashes, for connection past + /// checkpoints. + pub new_consolidated_hash: [F; NUM_HASH_OUT_ELTS], + + _phantom: PhantomData, } -impl FinalPublicValues { +impl> FinalPublicValues { /// Extracts final public values from the given public inputs of a proof. /// Public values are always the first public inputs added to the circuit, /// so we can start extracting at index 0. - pub fn from_public_inputs(pis: &[F]) -> Self { + pub fn from_public_inputs(pis: &[F]) -> Self { assert!(FinalPublicValuesTarget::SIZE <= pis.len()); - let mut offset = 0; - let state_trie_root_before = get_h256(&pis[offset..offset + TARGET_HASH_SIZE]); + let chain_id = pis[0].to_noncanonical_u64().into(); + let mut offset = 1; + let checkpoint_state_trie_root = get_h256(&pis[offset..offset + TARGET_HASH_SIZE]); offset += TARGET_HASH_SIZE; - let state_trie_root_after = get_h256(&pis[offset..offset + TARGET_HASH_SIZE]); + let new_state_trie_root = get_h256(&pis[offset..offset + TARGET_HASH_SIZE]); + offset += TARGET_HASH_SIZE; + let checkpoint_consolidated_hash = + pis[offset..offset + NUM_HASH_OUT_ELTS].try_into().unwrap(); + offset += NUM_HASH_OUT_ELTS; + let new_consolidated_hash = pis[offset..offset + NUM_HASH_OUT_ELTS].try_into().unwrap(); Self { - state_trie_root_before, - state_trie_root_after, + chain_id, + checkpoint_state_trie_root, + new_state_trie_root, + checkpoint_consolidated_hash, + new_consolidated_hash, + _phantom: PhantomData, } } } -impl From for FinalPublicValues { - fn from(value: PublicValues) -> Self { +impl, F: RichField> From> for FinalPublicValues { + fn from(value: PublicValues) -> Self { + let mut hash_payload = value.block_hashes.prev_hashes[1..].to_vec(); + hash_payload.push(value.block_hashes.cur_hash); + Self { - state_trie_root_before: value.trie_roots_before.state_root, - state_trie_root_after: value.trie_roots_after.state_root, + chain_id: value.block_metadata.block_chain_id, + checkpoint_state_trie_root: value.trie_roots_before.state_root, + new_state_trie_root: value.trie_roots_after.state_root, + checkpoint_consolidated_hash: value.extra_block_data.checkpoint_consolidated_hash, + new_consolidated_hash: consolidate_hashes::(&hash_payload), + _phantom: PhantomData, } } } @@ -170,57 +201,95 @@ impl From for FinalPublicValues { /// order. #[derive(Eq, PartialEq, Debug)] pub struct FinalPublicValuesTarget { + /// The chain id of this chian. + pub chain_id: Target, /// State trie root before the execution of this global state transition. - pub state_trie_root_before: [Target; TARGET_HASH_SIZE], + pub checkpoint_state_trie_root: [Target; TARGET_HASH_SIZE], /// State trie root after the execution of this global state transition. - pub state_trie_root_after: [Target; TARGET_HASH_SIZE], + pub new_state_trie_root: [Target; TARGET_HASH_SIZE], + /// A compact view of the block hashes before the previous checkpoint. + pub checkpoint_consolidated_hash: [Target; NUM_HASH_OUT_ELTS], + /// A compact view of the previous block hashes, for connection past + /// checkpoints. + pub new_consolidated_hash: [Target; NUM_HASH_OUT_ELTS], } impl FinalPublicValuesTarget { - pub(crate) const SIZE: usize = TARGET_HASH_SIZE * 2; + pub(crate) const SIZE: usize = 1 + TARGET_HASH_SIZE * 2 + NUM_HASH_OUT_ELTS * 2; /// Serializes public value targets. pub(crate) fn to_buffer(&self, buffer: &mut Vec) -> IoResult<()> { - buffer.write_target_array(&self.state_trie_root_before)?; - buffer.write_target_array(&self.state_trie_root_after)?; + buffer.write_target(self.chain_id)?; + buffer.write_target_array(&self.checkpoint_state_trie_root)?; + buffer.write_target_array(&self.new_state_trie_root)?; + buffer.write_target_array(&self.checkpoint_consolidated_hash)?; + buffer.write_target_array(&self.new_consolidated_hash)?; Ok(()) } /// Deserializes public value targets. pub(crate) fn from_buffer(buffer: &mut Buffer) -> IoResult { - let state_trie_root_before = buffer.read_target_array()?; - let state_trie_root_after = buffer.read_target_array()?; + let chain_id = buffer.read_target()?; + let checkpoint_state_trie_root = buffer.read_target_array()?; + let new_state_trie_root = buffer.read_target_array()?; + let checkpoint_consolidated_hash = buffer.read_target_array()?; + let new_consolidated_hash = buffer.read_target_array()?; Ok(Self { - state_trie_root_before, - state_trie_root_after, + chain_id, + checkpoint_state_trie_root, + new_state_trie_root, + checkpoint_consolidated_hash, + new_consolidated_hash, }) } /// Connects these `FinalPublicValuesTarget` with their corresponding /// counterpart in a full parent `PublicValuesTarget`. - pub(crate) fn connect_parent, const D: usize>( + pub(crate) fn connect_parent( &self, builder: &mut CircuitBuilder, - pv1: &PublicValuesTarget, - ) { - for i in 0..8 { + pv: &PublicValuesTarget, + ) where + F: RichField + Extendable, + C: GenericConfig + 'static, + { + builder.connect(self.chain_id, pv.block_metadata.block_chain_id); + + for i in 0..TARGET_HASH_SIZE { builder.connect( - self.state_trie_root_before[i], - pv1.trie_roots_before.state_root[i], + self.checkpoint_state_trie_root[i], + pv.trie_roots_before.state_root[i], ); builder.connect( - self.state_trie_root_after[i], - pv1.trie_roots_after.state_root[i], + self.new_state_trie_root[i], + pv.trie_roots_after.state_root[i], ); // We only use `FinalPublicValues` at the final block proof wrapping stage, // where we should enforce consistency with the known checkpoint. builder.connect( - self.state_trie_root_before[i], - pv1.extra_block_data.checkpoint_state_trie_root[i], + self.checkpoint_state_trie_root[i], + pv.extra_block_data.checkpoint_state_trie_root[i], + ); + } + + for i in 0..NUM_HASH_OUT_ELTS { + builder.connect( + self.checkpoint_consolidated_hash[i], + pv.extra_block_data.checkpoint_consolidated_hash[i], ); } + + let mut hash_payload = pv.block_hashes.prev_hashes[TARGET_HASH_SIZE..].to_vec(); + hash_payload.extend_from_slice(&pv.block_hashes.cur_hash); + let consolidated_hash = builder + .hash_n_to_hash_no_pad::(hash_payload) + .elements; + + for i in 0..NUM_HASH_OUT_ELTS { + builder.connect(self.new_consolidated_hash[i], consolidated_hash[i]); + } } } @@ -294,6 +363,19 @@ impl BlockHashes { } } +/// Generates the consolidated hash for a sequence of block hashes. +/// +/// It will pack 256 contiguous block hashes and hash them out. +pub fn consolidate_hashes, F: RichField>(hashes: &[H256]) -> [F; NUM_HASH_OUT_ELTS] { + debug_assert!(hashes.len() == 256); + + let payload = hashes.iter().flat_map(|&h| h256_limbs(h)).collect_vec(); + H::hash_no_pad(&payload) + .to_vec() + .try_into() + .expect("Digests have fixed size.") +} + /// Metadata contained in a block header. Those are identical between /// all state transition proofs within the same block. #[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)] @@ -368,10 +450,13 @@ impl BlockMetadata { /// Additional block data that are specific to the local transaction being /// proven, unlike `BlockMetadata`. -#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)] -pub struct ExtraBlockData { +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] +#[serde(bound = "")] +pub struct ExtraBlockData { /// The state trie digest of the checkpoint block. pub checkpoint_state_trie_root: H256, + /// The consolidated previous block hashes, at the checkpoint block. + pub checkpoint_consolidated_hash: [F; NUM_HASH_OUT_ELTS], /// The transaction count prior execution of the local state transition, /// starting at 0 for the initial transaction of a block. pub txn_number_before: U256, @@ -386,18 +471,42 @@ pub struct ExtraBlockData { pub gas_used_after: U256, } -impl ExtraBlockData { - pub fn from_public_inputs(pis: &[F]) -> Self { +impl Default for ExtraBlockData { + fn default() -> Self { + Self { + checkpoint_state_trie_root: H256::default(), + checkpoint_consolidated_hash: EMPTY_CONSOLIDATED_BLOCKHASH.map(F::from_canonical_u64), + txn_number_before: U256::default(), + txn_number_after: U256::default(), + gas_used_before: U256::default(), + gas_used_after: U256::default(), + } + } +} + +/// Consolidated hash for the Genesis block, where all previous block hashes +/// default to 0. +pub const EMPTY_CONSOLIDATED_BLOCKHASH: [u64; NUM_HASH_OUT_ELTS] = [ + 5498946765822202150, + 10724662260254836878, + 9161393967331872654, + 5704373722058976135, +]; + +impl ExtraBlockData { + pub fn from_public_inputs(pis: &[F]) -> Self { assert!(pis.len() == ExtraBlockDataTarget::SIZE); let checkpoint_state_trie_root = get_h256(&pis[0..8]); - let txn_number_before = pis[8].to_canonical_u64().into(); - let txn_number_after = pis[9].to_canonical_u64().into(); - let gas_used_before = pis[10].to_canonical_u64().into(); - let gas_used_after = pis[11].to_canonical_u64().into(); + let checkpoint_consolidated_hash = pis[8..12].try_into().unwrap(); + let txn_number_before = pis[12].to_canonical_u64().into(); + let txn_number_after = pis[13].to_canonical_u64().into(); + let gas_used_before = pis[14].to_canonical_u64().into(); + let gas_used_after = pis[15].to_canonical_u64().into(); Self { checkpoint_state_trie_root, + checkpoint_consolidated_hash, txn_number_before, txn_number_after, gas_used_before, @@ -574,12 +683,14 @@ impl PublicValuesTarget { let ExtraBlockDataTarget { checkpoint_state_trie_root, + checkpoint_consolidated_hash, txn_number_before, txn_number_after, gas_used_before, gas_used_after, } = self.extra_block_data; buffer.write_target_array(&checkpoint_state_trie_root)?; + buffer.write_target_array(&checkpoint_consolidated_hash)?; buffer.write_target(txn_number_before)?; buffer.write_target(txn_number_after)?; buffer.write_target(gas_used_before)?; @@ -661,6 +772,7 @@ impl PublicValuesTarget { let extra_block_data = ExtraBlockDataTarget { checkpoint_state_trie_root: buffer.read_target_array()?, + checkpoint_consolidated_hash: buffer.read_target_array()?, txn_number_before: buffer.read_target()?, txn_number_after: buffer.read_target()?, gas_used_before: buffer.read_target()?, @@ -1229,7 +1341,7 @@ pub struct BlockHashesTarget { /// hash, i.e. `prev_hashes[0..8]`, is the oldest, and the rightmost, /// i.e. `prev_hashes[255 * 7..255 * 8]` is the hash of the parent block. pub(crate) prev_hashes: [Target; 2048], - // `Target` for the hash of the current block. + // `Target`s for the hash of the current block. pub(crate) cur_hash: [Target; 8], } @@ -1302,6 +1414,9 @@ impl BlockHashesTarget { pub struct ExtraBlockDataTarget { /// `Target`s for the state trie digest of the checkpoint block. pub checkpoint_state_trie_root: [Target; 8], + /// `Target`s for the consolidated previous block hashes, at the checkpoint + /// block. + pub checkpoint_consolidated_hash: [Target; NUM_HASH_OUT_ELTS], /// `Target` for the transaction count prior execution of the local state /// transition, starting at 0 for the initial trnasaction of a block. pub txn_number_before: Target, @@ -1319,19 +1434,21 @@ pub struct ExtraBlockDataTarget { impl ExtraBlockDataTarget { /// Number of `Target`s required for the extra block data. - pub(crate) const SIZE: usize = 12; + pub(crate) const SIZE: usize = 16; /// Extracts the extra block data `Target`s from the public input `Target`s. /// The provided `pis` should start with the extra vblock data. pub(crate) fn from_public_inputs(pis: &[Target]) -> Self { let checkpoint_state_trie_root = pis[0..8].try_into().unwrap(); - let txn_number_before = pis[8]; - let txn_number_after = pis[9]; - let gas_used_before = pis[10]; - let gas_used_after = pis[11]; + let checkpoint_consolidated_hash = pis[8..12].try_into().unwrap(); + let txn_number_before = pis[12]; + let txn_number_after = pis[13]; + let gas_used_before = pis[14]; + let gas_used_after = pis[15]; Self { checkpoint_state_trie_root, + checkpoint_consolidated_hash, txn_number_before, txn_number_after, gas_used_before, @@ -1355,6 +1472,13 @@ impl ExtraBlockDataTarget { ed1.checkpoint_state_trie_root[i], ) }), + checkpoint_consolidated_hash: core::array::from_fn(|i| { + builder.select( + condition, + ed0.checkpoint_consolidated_hash[i], + ed1.checkpoint_consolidated_hash[i], + ) + }), txn_number_before: builder.select( condition, ed0.txn_number_before, @@ -1379,6 +1503,12 @@ impl ExtraBlockDataTarget { ed1.checkpoint_state_trie_root[i], ); } + for i in 0..NUM_HASH_OUT_ELTS { + builder.connect( + ed0.checkpoint_consolidated_hash[i], + ed1.checkpoint_consolidated_hash[i], + ); + } builder.connect(ed0.txn_number_before, ed1.txn_number_before); builder.connect(ed0.txn_number_after, ed1.txn_number_after); builder.connect(ed0.gas_used_before, ed1.gas_used_before); @@ -1399,6 +1529,13 @@ impl ExtraBlockDataTarget { ed1.checkpoint_state_trie_root[i], ); } + for i in 0..NUM_HASH_OUT_ELTS { + builder.conditional_assert_eq( + condition.target, + ed0.checkpoint_consolidated_hash[i], + ed1.checkpoint_consolidated_hash[i], + ); + } builder.conditional_assert_eq( condition.target, ed0.txn_number_before, diff --git a/evm_arithmetization/src/prover.rs b/evm_arithmetization/src/prover.rs index 736c900ef..ff16cc1cb 100644 --- a/evm_arithmetization/src/prover.rs +++ b/evm_arithmetization/src/prover.rs @@ -31,7 +31,7 @@ use crate::proof::{AllProof, MemCap, PublicValues, DEFAULT_CAP_LEN}; pub fn prove( all_stark: &AllStark, config: &StarkConfig, - inputs: TrimmedGenerationInputs, + inputs: TrimmedGenerationInputs, segment_data: &mut GenerationSegmentData, timing: &mut TimingTree, abort_signal: Option>, @@ -72,7 +72,7 @@ pub(crate) fn prove_with_traces( all_stark: &AllStark, config: &StarkConfig, trace_poly_values: [Vec>; NUM_TABLES], - public_values: &mut PublicValues, + public_values: &mut PublicValues, timing: &mut TimingTree, abort_signal: Option>, ) -> Result> @@ -474,7 +474,7 @@ pub fn check_abort_signal(abort_signal: Option>) -> Result<()> { /// Sanity checks on the consistency between this proof payload and the feature /// flags being used. -pub(crate) fn features_check(inputs: &TrimmedGenerationInputs) { +pub(crate) fn features_check(inputs: &TrimmedGenerationInputs) { if cfg!(feature = "polygon_pos") || cfg!(feature = "cdk_erigon") { assert!(inputs.block_metadata.parent_beacon_block_root.is_zero()); assert!(inputs.block_metadata.block_blob_gas_used.is_zero()); @@ -500,7 +500,7 @@ pub mod testing { /// Simulates the zkEVM CPU execution. /// It does not generate any trace or proof of correct state transition. - pub fn simulate_execution(inputs: GenerationInputs) -> Result<()> { + pub fn simulate_execution(inputs: GenerationInputs) -> Result<()> { features_check(&inputs.clone().trim()); let initial_stack = vec![]; @@ -520,7 +520,7 @@ pub mod testing { pub fn prove_all_segments( all_stark: &AllStark, config: &StarkConfig, - inputs: GenerationInputs, + inputs: GenerationInputs, max_cpu_len_log: usize, timing: &mut TimingTree, abort_signal: Option>, @@ -551,7 +551,7 @@ pub mod testing { } pub fn simulate_execution_all_segments( - inputs: GenerationInputs, + inputs: GenerationInputs, max_cpu_len_log: usize, ) -> Result<()> where diff --git a/evm_arithmetization/src/recursive_verifier.rs b/evm_arithmetization/src/recursive_verifier.rs index 29344ff11..417bf468d 100644 --- a/evm_arithmetization/src/recursive_verifier.rs +++ b/evm_arithmetization/src/recursive_verifier.rs @@ -14,7 +14,7 @@ use plonky2::iop::target::Target; use plonky2::iop::witness::{PartialWitness, Witness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher}; use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; use plonky2::util::serialization::{ Buffer, GateSerializer, IoResult, Read, WitnessGeneratorSerializer, Write, @@ -639,12 +639,18 @@ pub(crate) fn add_virtual_final_public_values_public_input< >( builder: &mut CircuitBuilder, ) -> FinalPublicValuesTarget { - let state_trie_root_before = builder.add_virtual_public_input_arr(); - let state_trie_root_after = builder.add_virtual_public_input_arr(); + let chain_id = builder.add_virtual_public_input(); + let checkpoint_state_trie_root = builder.add_virtual_public_input_arr(); + let new_state_trie_root = builder.add_virtual_public_input_arr(); + let checkpoint_consolidated_hash = builder.add_virtual_public_input_arr(); + let new_consolidated_hash = builder.add_virtual_public_input_arr(); FinalPublicValuesTarget { - state_trie_root_before, - state_trie_root_after, + chain_id, + checkpoint_state_trie_root, + new_state_trie_root, + checkpoint_consolidated_hash, + new_consolidated_hash, } } @@ -766,6 +772,7 @@ pub(crate) fn add_virtual_extra_block_data_public_input< builder: &mut CircuitBuilder, ) -> ExtraBlockDataTarget { let checkpoint_state_trie_root = builder.add_virtual_public_input_arr(); + let checkpoint_consolidated_hash = builder.add_virtual_public_input_arr(); let txn_number_before = builder.add_virtual_public_input(); let txn_number_after = builder.add_virtual_public_input(); let gas_used_before = builder.add_virtual_public_input(); @@ -773,6 +780,7 @@ pub(crate) fn add_virtual_extra_block_data_public_input< ExtraBlockDataTarget { checkpoint_state_trie_root, + checkpoint_consolidated_hash, txn_number_before, txn_number_after, gas_used_before, @@ -803,7 +811,7 @@ pub(crate) fn add_virtual_registers_data_public_input< } } -pub(crate) fn debug_public_values(public_values: &PublicValues) { +pub(crate) fn debug_public_values(public_values: &PublicValues) { log::debug!("Public Values:"); log::debug!( " Trie Roots Before: {:?}", @@ -818,7 +826,7 @@ pub(crate) fn debug_public_values(public_values: &PublicValues) { pub fn set_public_value_targets( witness: &mut W, public_values_target: &PublicValuesTarget, - public_values: &PublicValues, + public_values: &PublicValues, ) -> Result<(), ProgramError> where F: RichField + Extendable, @@ -884,49 +892,59 @@ where Ok(()) } -pub fn set_final_public_value_targets( +pub fn set_final_public_value_targets( witness: &mut W, public_values_target: &FinalPublicValuesTarget, - public_values: &FinalPublicValues, + public_values: &FinalPublicValues, ) -> Result<(), ProgramError> where F: RichField + Extendable, + H: Hasher, W: Witness, { + witness.set_target( + public_values_target.chain_id, + F::from_canonical_u64(public_values.chain_id.low_u64()), + ); + for (i, limb) in public_values - .state_trie_root_before + .checkpoint_state_trie_root .into_uint() .0 .into_iter() .enumerate() { witness.set_target( - public_values_target.state_trie_root_before[2 * i], + public_values_target.checkpoint_state_trie_root[2 * i], F::from_canonical_u32(limb as u32), ); witness.set_target( - public_values_target.state_trie_root_before[2 * i + 1], + public_values_target.checkpoint_state_trie_root[2 * i + 1], F::from_canonical_u32((limb >> 32) as u32), ); } for (i, limb) in public_values - .state_trie_root_after + .new_state_trie_root .into_uint() .0 .into_iter() .enumerate() { witness.set_target( - public_values_target.state_trie_root_after[2 * i], + public_values_target.new_state_trie_root[2 * i], F::from_canonical_u32(limb as u32), ); witness.set_target( - public_values_target.state_trie_root_after[2 * i + 1], + public_values_target.new_state_trie_root[2 * i + 1], F::from_canonical_u32((limb >> 32) as u32), ); } + for (i, limb) in public_values.new_consolidated_hash.iter().enumerate() { + witness.set_target(public_values_target.new_consolidated_hash[i], *limb); + } + Ok(()) } @@ -1111,7 +1129,7 @@ pub(crate) fn set_block_hashes_target( pub(crate) fn set_extra_public_values_target( witness: &mut W, ed_target: &ExtraBlockDataTarget, - ed: &ExtraBlockData, + ed: &ExtraBlockData, ) -> Result<(), ProgramError> where F: RichField + Extendable, @@ -1121,6 +1139,10 @@ where &ed_target.checkpoint_state_trie_root, &h256_limbs::(ed.checkpoint_state_trie_root), ); + witness.set_target_arr( + &ed_target.checkpoint_consolidated_hash, + &ed.checkpoint_consolidated_hash, + ); witness.set_target( ed_target.txn_number_before, u256_to_u32(ed.txn_number_before)?, diff --git a/evm_arithmetization/src/verifier.rs b/evm_arithmetization/src/verifier.rs index 89220b607..9ee5750f8 100644 --- a/evm_arithmetization/src/verifier.rs +++ b/evm_arithmetization/src/verifier.rs @@ -94,7 +94,7 @@ fn verify_initial_memory< C: GenericConfig, const D: usize, >( - public_values: &PublicValues, + public_values: &PublicValues, config: &StarkConfig, ) -> Result<()> { for (hash1, hash2) in initial_memory_merkle_cap::( @@ -271,7 +271,7 @@ fn verify_proof, C: GenericConfig, const /// - block metadata writes, /// - trie roots writes. pub(crate) fn get_memory_extra_looking_sum( - public_values: &PublicValues, + public_values: &PublicValues, challenge: GrandProductChallenge, ) -> F where @@ -497,7 +497,7 @@ pub(crate) mod debug_utils { /// Output all the extra memory rows that don't appear in the CPU trace but /// are necessary to correctly check the MemoryStark CTL. pub(crate) fn get_memory_extra_looking_values( - public_values: &PublicValues, + public_values: &PublicValues, ) -> Vec> where F: RichField + Extendable, diff --git a/evm_arithmetization/src/witness/util.rs b/evm_arithmetization/src/witness/util.rs index 5769f6600..5bd103096 100644 --- a/evm_arithmetization/src/witness/util.rs +++ b/evm_arithmetization/src/witness/util.rs @@ -1,5 +1,4 @@ use ethereum_types::U256; -use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; use super::memory::DUMMY_MEMOP; @@ -23,7 +22,7 @@ fn to_byte_checked(n: U256) -> u8 { res } -fn to_bits_le(n: u8) -> [F; 8] { +fn to_bits_le(n: u8) -> [F; 8] { let mut res = [F::ZERO; 8]; for (i, bit) in res.iter_mut().enumerate() { *bit = F::from_bool(n & (1 << i) != 0); @@ -62,7 +61,11 @@ pub(crate) fn current_context_peek( .get_with_init(MemoryAddress::new(context, segment, virt)) } -pub(crate) fn fill_channel_with_value(row: &mut CpuColumnsView, n: usize, val: U256) { +pub(crate) fn fill_channel_with_value( + row: &mut CpuColumnsView, + n: usize, + val: U256, +) { let channel = &mut row.mem_channels[n]; let val_limbs: [u64; 4] = val.0; for (i, limb) in val_limbs.into_iter().enumerate() { diff --git a/evm_arithmetization/tests/add11_yml.rs b/evm_arithmetization/tests/add11_yml.rs index a7624a6df..5b8290229 100644 --- a/evm_arithmetization/tests/add11_yml.rs +++ b/evm_arithmetization/tests/add11_yml.rs @@ -21,6 +21,8 @@ use keccak_hash::keccak; use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; use plonky2::plonk::config::KeccakGoldilocksConfig; use plonky2::util::timing::TimingTree; @@ -28,7 +30,7 @@ type F = GoldilocksField; const D: usize = 2; type C = KeccakGoldilocksConfig; -fn get_generation_inputs() -> GenerationInputs { +fn get_generation_inputs() -> GenerationInputs { let beneficiary = hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"); let sender = hex!("a94f5374fce5edbc8e2a8697c15331677e6ebf0b"); let to = hex!("095e7baea6a6c7c4c2dfeb977efac326af552d87"); @@ -180,7 +182,7 @@ fn get_generation_inputs() -> GenerationInputs { receipts_root: receipts_trie.hash(), }; - GenerationInputs { + GenerationInputs:: { signed_txns: vec![txn.to_vec()], burn_addr: None, withdrawals: vec![], @@ -190,6 +192,7 @@ fn get_generation_inputs() -> GenerationInputs { contract_code, block_metadata, checkpoint_state_trie_root: state_trie_before.hash(), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], txn_number_before: 0.into(), gas_used_before: 0.into(), gas_used_after: 0xa868u64.into(), diff --git a/evm_arithmetization/tests/erc20.rs b/evm_arithmetization/tests/erc20.rs index 61bb3f2ef..2c1a56829 100644 --- a/evm_arithmetization/tests/erc20.rs +++ b/evm_arithmetization/tests/erc20.rs @@ -19,6 +19,8 @@ use keccak_hash::keccak; use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; use plonky2::plonk::config::KeccakGoldilocksConfig; use plonky2::util::timing::TimingTree; @@ -176,7 +178,7 @@ fn test_erc20() -> anyhow::Result<()> { receipts_root: receipts_trie.hash(), }; - let inputs = GenerationInputs { + let inputs = GenerationInputs:: { signed_txns: vec![txn.to_vec()], burn_addr: None, withdrawals: vec![], @@ -185,6 +187,7 @@ fn test_erc20() -> anyhow::Result<()> { trie_roots_after, contract_code, checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm_arithmetization/tests/erc721.rs b/evm_arithmetization/tests/erc721.rs index 47d214f9e..170a19df4 100644 --- a/evm_arithmetization/tests/erc721.rs +++ b/evm_arithmetization/tests/erc721.rs @@ -20,6 +20,8 @@ use keccak_hash::keccak; use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; use plonky2::plonk::config::KeccakGoldilocksConfig; use plonky2::util::timing::TimingTree; @@ -180,7 +182,7 @@ fn test_erc721() -> anyhow::Result<()> { receipts_root: receipts_trie.hash(), }; - let inputs = GenerationInputs { + let inputs = GenerationInputs:: { signed_txns: vec![txn.to_vec()], burn_addr: None, withdrawals: vec![], @@ -189,6 +191,7 @@ fn test_erc721() -> anyhow::Result<()> { trie_roots_after, contract_code, checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm_arithmetization/tests/global_exit_root.rs b/evm_arithmetization/tests/global_exit_root.rs index 0bc41eaf8..a41d79e6f 100644 --- a/evm_arithmetization/tests/global_exit_root.rs +++ b/evm_arithmetization/tests/global_exit_root.rs @@ -17,6 +17,8 @@ use evm_arithmetization::{AllStark, Node, StarkConfig}; use keccak_hash::keccak; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; use plonky2::plonk::config::PoseidonGoldilocksConfig; use plonky2::util::timing::TimingTree; @@ -89,7 +91,7 @@ fn test_global_exit_root() -> anyhow::Result<()> { receipts_root: receipts_trie.hash(), }; - let inputs = GenerationInputs { + let inputs = GenerationInputs:: { signed_txns: vec![], burn_addr: None, withdrawals: vec![], @@ -103,6 +105,7 @@ fn test_global_exit_root() -> anyhow::Result<()> { trie_roots_after, contract_code, checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm_arithmetization/tests/log_opcode.rs b/evm_arithmetization/tests/log_opcode.rs index 0b925ceae..44453ae22 100644 --- a/evm_arithmetization/tests/log_opcode.rs +++ b/evm_arithmetization/tests/log_opcode.rs @@ -24,6 +24,8 @@ use keccak_hash::keccak; use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; use plonky2::plonk::config::PoseidonGoldilocksConfig; use plonky2::util::timing::TimingTree; @@ -246,7 +248,7 @@ fn test_log_opcodes() -> anyhow::Result<()> { false => None, }; - let inputs = GenerationInputs { + let inputs = GenerationInputs:: { signed_txns: vec![txn.to_vec()], burn_addr, withdrawals: vec![], @@ -255,6 +257,7 @@ fn test_log_opcodes() -> anyhow::Result<()> { trie_roots_after, contract_code, checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm_arithmetization/tests/selfdestruct.rs b/evm_arithmetization/tests/selfdestruct.rs index dde580498..7d8ecba5b 100644 --- a/evm_arithmetization/tests/selfdestruct.rs +++ b/evm_arithmetization/tests/selfdestruct.rs @@ -19,6 +19,8 @@ use keccak_hash::keccak; use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; use plonky2::plonk::config::KeccakGoldilocksConfig; use plonky2::util::timing::TimingTree; use zk_evm_common::eth_to_wei; @@ -151,7 +153,7 @@ fn test_selfdestruct() -> anyhow::Result<()> { receipts_root: receipts_trie.hash(), }; - let inputs = GenerationInputs { + let inputs = GenerationInputs:: { signed_txns: vec![txn.to_vec()], burn_addr: None, withdrawals: vec![], @@ -160,6 +162,7 @@ fn test_selfdestruct() -> anyhow::Result<()> { trie_roots_after, contract_code, checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm_arithmetization/tests/simple_transfer.rs b/evm_arithmetization/tests/simple_transfer.rs index 2e371071c..7dbf91399 100644 --- a/evm_arithmetization/tests/simple_transfer.rs +++ b/evm_arithmetization/tests/simple_transfer.rs @@ -20,6 +20,8 @@ use keccak_hash::keccak; use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; use plonky2::plonk::config::KeccakGoldilocksConfig; use plonky2::util::timing::TimingTree; use zk_evm_common::eth_to_wei; @@ -143,7 +145,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { receipts_root: receipts_trie.hash(), }; - let inputs = GenerationInputs { + let inputs = GenerationInputs:: { signed_txns: vec![txn.to_vec()], burn_addr: None, withdrawals: vec![], @@ -152,6 +154,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { trie_roots_after, contract_code, checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm_arithmetization/tests/two_to_one_block.rs b/evm_arithmetization/tests/two_to_one_block.rs index 2474bb82b..a70c43c8c 100644 --- a/evm_arithmetization/tests/two_to_one_block.rs +++ b/evm_arithmetization/tests/two_to_one_block.rs @@ -5,7 +5,9 @@ use evm_arithmetization::fixed_recursive_verifier::{ extract_block_final_public_values, extract_two_to_one_block_hash, }; use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; -use evm_arithmetization::proof::{BlockMetadata, FinalPublicValues, PublicValues, TrieRoots}; +use evm_arithmetization::proof::{ + BlockMetadata, FinalPublicValues, PublicValues, TrieRoots, EMPTY_CONSOLIDATED_BLOCKHASH, +}; use evm_arithmetization::testing_utils::{ beacon_roots_account_nibbles, beacon_roots_contract_from_storage, init_logger, preinitialized_state_and_storage_tries, update_beacon_roots_account_storage, @@ -14,6 +16,7 @@ use evm_arithmetization::{AllRecursiveCircuits, AllStark, Node, StarkConfig}; use hex_literal::hex; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; use plonky2::hash::poseidon::PoseidonHash; use plonky2::plonk::config::{Hasher, PoseidonGoldilocksConfig}; use plonky2::plonk::proof::ProofWithPublicInputs; @@ -25,7 +28,7 @@ type C = PoseidonGoldilocksConfig; /// Get `GenerationInputs` for a dummy payload, where the block has the given /// timestamp. -fn dummy_payload(timestamp: u64, is_first_payload: bool) -> anyhow::Result { +fn dummy_payload(timestamp: u64, is_first_payload: bool) -> anyhow::Result> { let beneficiary = hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); let block_metadata = BlockMetadata { @@ -89,6 +92,7 @@ fn dummy_payload(timestamp: u64, is_first_payload: bool) -> anyhow::Result anyhow::Result<()> { receipts_root: receipts_trie.hash(), }; - let inputs = GenerationInputs { + let inputs = GenerationInputs:: { signed_txns: vec![], burn_addr: None, withdrawals, @@ -95,6 +97,7 @@ fn test_withdrawals() -> anyhow::Result<()> { trie_roots_after, contract_code, checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_consolidated_hash: [F::ZERO; NUM_HASH_OUT_ELTS], block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/proof_gen/src/proof_gen.rs b/proof_gen/src/proof_gen.rs index 2e2e39ae2..e69d8de3c 100644 --- a/proof_gen/src/proof_gen.rs +++ b/proof_gen/src/proof_gen.rs @@ -50,7 +50,7 @@ impl From for ProofGenError { /// Generates a transaction proof from some IR data. pub fn generate_segment_proof( p_state: &ProverState, - gen_inputs: TrimmedGenerationInputs, + gen_inputs: TrimmedGenerationInputs, segment_data: &mut GenerationSegmentData, abort_signal: Option>, ) -> ProofGenResult { diff --git a/proof_gen/src/proof_types.rs b/proof_gen/src/proof_types.rs index 20be552d9..a0a1db43c 100644 --- a/proof_gen/src/proof_types.rs +++ b/proof_gen/src/proof_types.rs @@ -9,14 +9,14 @@ use evm_arithmetization::{ use plonky2::plonk::config::Hasher as _; use serde::{Deserialize, Serialize}; -use crate::types::{Hash, Hasher, PlonkyProofIntern}; +use crate::types::{Field, Hash, Hasher, PlonkyProofIntern}; /// A transaction proof along with its public values, for proper connection with /// contiguous proofs. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct GeneratedSegmentProof { /// Public values of this transaction proof. - pub p_vals: PublicValues, + pub p_vals: PublicValues, /// Underlying plonky2 proof. pub intern: PlonkyProofIntern, } @@ -29,7 +29,7 @@ pub struct GeneratedSegmentProof { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct GeneratedSegmentAggProof { /// Public values of this aggregation proof. - pub p_vals: PublicValues, + pub p_vals: PublicValues, /// Underlying plonky2 proof. pub intern: PlonkyProofIntern, } @@ -42,7 +42,7 @@ pub struct GeneratedSegmentAggProof { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct GeneratedTxnAggProof { /// Public values of this transaction aggregation proof. - pub p_vals: PublicValues, + pub p_vals: PublicValues, /// Underlying plonky2 proof. pub intern: PlonkyProofIntern, } @@ -94,7 +94,7 @@ pub enum BatchAggregatableProof { } impl SegmentAggregatableProof { - pub(crate) fn public_values(&self) -> PublicValues { + pub(crate) fn public_values(&self) -> PublicValues { match self { SegmentAggregatableProof::Seg(info) => info.p_vals.clone(), SegmentAggregatableProof::Agg(info) => info.p_vals.clone(), @@ -117,7 +117,7 @@ impl SegmentAggregatableProof { } impl BatchAggregatableProof { - pub(crate) fn public_values(&self) -> PublicValues { + pub(crate) fn public_values(&self) -> PublicValues { match self { BatchAggregatableProof::Segment(info) => info.p_vals.clone(), BatchAggregatableProof::Txn(info) => info.p_vals.clone(), diff --git a/proof_gen/src/types.rs b/proof_gen/src/types.rs index bf1b4185c..5e6c47c2d 100644 --- a/proof_gen/src/types.rs +++ b/proof_gen/src/types.rs @@ -8,6 +8,7 @@ use plonky2::{ }; /// The base field on which statements are being proven. +// TODO(Robin): https://github.com/0xPolygonZero/zk_evm/issues/531 pub type Field = GoldilocksField; /// The recursive circuit configuration to be used to shrink and aggregate /// proofs. diff --git a/trace_decoder/src/core.rs b/trace_decoder/src/core.rs index a1e85c6cc..003c07d2b 100644 --- a/trace_decoder/src/core.rs +++ b/trace_decoder/src/core.rs @@ -23,8 +23,8 @@ use zk_evm_common::gwei_to_wei; use crate::{ typed_mpt::{ReceiptTrie, StateMpt, StateTrie, StorageTrie, TransactionTrie, TrieKey}, BlockLevelData, BlockTrace, BlockTraceTriePreImages, CombinedPreImages, ContractCodeUsage, - OtherBlockData, SeparateStorageTriesPreImage, SeparateTriePreImage, SeparateTriePreImages, - TxnInfo, TxnMeta, TxnTrace, + Field, OtherBlockData, SeparateStorageTriesPreImage, SeparateTriePreImage, + SeparateTriePreImages, TxnInfo, TxnMeta, TxnTrace, }; /// TODO(0xaatif): document this after https://github.com/0xPolygonZero/zk_evm/issues/275 @@ -33,7 +33,7 @@ pub fn entrypoint( other: OtherBlockData, batch_size_hint: usize, use_burn_addr: bool, -) -> anyhow::Result> { +) -> anyhow::Result>> { ensure!(batch_size_hint != 0); let BlockTrace { @@ -52,6 +52,7 @@ pub fn entrypoint( mut withdrawals, }, checkpoint_state_trie_root, + checkpoint_consolidated_hash, } = other; for (_, amt) in &mut withdrawals { @@ -86,7 +87,7 @@ pub fn entrypoint( }, after, withdrawals, - }| GenerationInputs { + }| GenerationInputs:: { txn_number_before: first_txn_ix.into(), gas_used_before: running_gas_used.into(), gas_used_after: { @@ -104,6 +105,7 @@ pub fn entrypoint( }, trie_roots_after: after, checkpoint_state_trie_root, + checkpoint_consolidated_hash, contract_code: contract_code .into_iter() .map(|it| (keccak_hash::keccak(&it), it)) diff --git a/trace_decoder/src/decoding.rs b/trace_decoder/src/decoding.rs new file mode 100644 index 000000000..be55821a0 --- /dev/null +++ b/trace_decoder/src/decoding.rs @@ -0,0 +1,713 @@ +use std::{cmp::min, collections::HashMap, ops::Range}; + +use anyhow::{anyhow, Context as _}; +use ethereum_types::H160; +use ethereum_types::{Address, BigEndianHash, H256, U256, U512}; +use evm_arithmetization::{ + generation::{ + mpt::{decode_receipt, AccountRlp}, + GenerationInputs, TrieInputs, + }, + proof::{BlockMetadata, ExtraBlockData, TrieRoots}, + testing_utils::{ + BEACON_ROOTS_CONTRACT_ADDRESS, BEACON_ROOTS_CONTRACT_ADDRESS_HASHED, HISTORY_BUFFER_LENGTH, + }, +}; +use mpt_trie::{ + nibbles::Nibbles, + partial_trie::{HashedPartialTrie, PartialTrie as _}, + special_query::path_for_query, + trie_ops::TrieOpError, + utils::{IntoTrieKey as _, TriePath}, +}; +use plonky2::hash::hash_types::RichField; + +use crate::{ + hash, + processed_block_trace::{ + NodesUsedByTxnBatch, ProcessedBlockTrace, ProcessedTxnBatchInfo, StateWrite, TxnMetaState, + }, + typed_mpt::{ReceiptTrie, StateTrie, StorageTrie, TransactionTrie, TrieKey}, + Field, OtherBlockData, PartialTriePreImages, TryIntoExt as TryIntoBounds, +}; + +/// The current state of all tries as we process txn deltas. These are mutated +/// after every txn we process in the trace. +#[derive(Clone, Debug, Default)] +struct PartialTrieState { + state: StateTrieT, + storage: HashMap, + txn: TransactionTrie, + receipt: ReceiptTrie, +} + +/// Additional information discovered during delta application. +#[derive(Debug, Default)] +struct TrieDeltaApplicationOutput { + // During delta application, if a delete occurs, we may have to make sure additional nodes + // that are not accessed by the txn remain unhashed. + additional_state_trie_paths_to_not_hash: Vec, + additional_storage_trie_paths_to_not_hash: HashMap>, +} + +pub fn into_txn_proof_gen_ir( + ProcessedBlockTrace { + tries: PartialTriePreImages { state, storage }, + txn_info, + withdrawals, + }: ProcessedBlockTrace, + other_data: OtherBlockData, + use_burn_addr: bool, + batch_size: usize, +) -> anyhow::Result>> { + let mut curr_block_tries = PartialTrieState { + state: state.clone(), + storage: storage.iter().map(|(k, v)| (*k, v.clone())).collect(), + ..Default::default() + }; + + let mut extra_data = ExtraBlockData:: { + checkpoint_state_trie_root: other_data.checkpoint_state_trie_root, + checkpoint_consolidated_hash: other_data.checkpoint_consolidated_hash, + txn_number_before: U256::zero(), + txn_number_after: U256::zero(), + gas_used_before: U256::zero(), + gas_used_after: U256::zero(), + }; + + let num_txs = txn_info + .iter() + .map(|tx_info| tx_info.meta.len()) + .sum::(); + + let mut txn_gen_inputs = txn_info + .into_iter() + .enumerate() + .map(|(txn_idx, txn_info)| { + let txn_range = + min(txn_idx * batch_size, num_txs)..min(txn_idx * batch_size + batch_size, num_txs); + let is_initial_payload = txn_range.start == 0; + + process_txn_info( + txn_range.clone(), + is_initial_payload, + txn_info, + &mut curr_block_tries, + &mut extra_data, + &other_data, + use_burn_addr, + ) + .context(format!( + "at transaction range {}..{}", + txn_range.start, txn_range.end + )) + }) + .collect::>>() + .context(format!( + "at block num {} with chain id {}", + other_data.b_data.b_meta.block_number, other_data.b_data.b_meta.block_chain_id + ))?; + + if !withdrawals.is_empty() { + add_withdrawals_to_txns(&mut txn_gen_inputs, &mut curr_block_tries, withdrawals)?; + } + + Ok(txn_gen_inputs) +} + +/// Cancun HF specific: At the start of a block, prior txn execution, we +/// need to update the storage of the beacon block root contract. +// See . +fn update_beacon_block_root_contract_storage( + trie_state: &mut PartialTrieState, + delta_out: &mut TrieDeltaApplicationOutput, + nodes_used: &mut NodesUsedByTxnBatch, + block_data: &BlockMetadata, +) -> anyhow::Result<()> { + const HISTORY_BUFFER_LENGTH_MOD: U256 = U256([HISTORY_BUFFER_LENGTH.1, 0, 0, 0]); + + let timestamp_idx = block_data.block_timestamp % HISTORY_BUFFER_LENGTH_MOD; + let timestamp = rlp::encode(&block_data.block_timestamp).to_vec(); + + let root_idx = timestamp_idx + HISTORY_BUFFER_LENGTH_MOD; + let calldata = rlp::encode(&U256::from_big_endian( + &block_data.parent_beacon_block_root.0, + )) + .to_vec(); + + let storage_trie = trie_state + .storage + .get_mut(&BEACON_ROOTS_CONTRACT_ADDRESS_HASHED) + .context(format!( + "missing account storage trie for address {:x}", + BEACON_ROOTS_CONTRACT_ADDRESS + ))?; + + let slots_nibbles = nodes_used + .storage_accesses + .entry(BEACON_ROOTS_CONTRACT_ADDRESS_HASHED) + .or_default(); + + for (ix, val) in [(timestamp_idx, timestamp), (root_idx, calldata)] { + // TODO(0xaatif): https://github.com/0xPolygonZero/zk_evm/issues/275 + // document this + let slot = TrieKey::from_nibbles(Nibbles::from_h256_be(hash( + Nibbles::from_h256_be(H256::from_uint(&ix)).bytes_be(), + ))); + + slots_nibbles.push(slot); + + // If we are writing a zero, then we actually need to perform a delete. + match val == ZERO_STORAGE_SLOT_VAL_RLPED { + false => { + storage_trie.insert(slot, val.clone()).context(format!( + "at slot {:?} with value {}", + slot, + U512::from_big_endian(val.as_slice()) + ))?; + + delta_out + .additional_storage_trie_paths_to_not_hash + .entry(BEACON_ROOTS_CONTRACT_ADDRESS_HASHED) + .or_default() + .push(slot); + } + true => { + if let Ok(Some(remaining_slot_key)) = + delete_node_and_report_remaining_key_if_branch_collapsed( + storage_trie.as_mut_hashed_partial_trie_unchecked(), + &slot, + ) + { + delta_out + .additional_storage_trie_paths_to_not_hash + .entry(BEACON_ROOTS_CONTRACT_ADDRESS_HASHED) + .or_default() + .push(remaining_slot_key); + } + } + } + } + + delta_out + .additional_state_trie_paths_to_not_hash + .push(TrieKey::from_hash(BEACON_ROOTS_CONTRACT_ADDRESS_HASHED)); + let mut account = trie_state + .state + .get_by_address(BEACON_ROOTS_CONTRACT_ADDRESS) + .context(format!( + "missing account storage trie for address {:x}", + BEACON_ROOTS_CONTRACT_ADDRESS + ))?; + + account.storage_root = storage_trie.root(); + + trie_state + .state + .insert_by_address(BEACON_ROOTS_CONTRACT_ADDRESS, account) + // TODO(0xaatif): https://github.com/0xPolygonZero/zk_evm/issues/275 + // Add an entry API + .expect("insert must succeed with the same key as a successful `get`"); + + Ok(()) +} + +fn update_txn_and_receipt_tries( + trie_state: &mut PartialTrieState, + meta: &TxnMetaState, + txn_idx: usize, +) -> anyhow::Result<()> { + if let Some(bytes) = &meta.txn_bytes { + trie_state.txn.insert(txn_idx, bytes.clone())?; + trie_state + .receipt + .insert(txn_idx, meta.receipt_node_bytes.clone())?; + } // else it's just a dummy + Ok(()) +} + +/// If the account does not have a storage trie or does but is not +/// accessed by any txns, then we still need to manually create an entry for +/// them. +fn init_any_needed_empty_storage_tries<'a>( + storage_tries: &mut HashMap, + accounts_with_storage: impl Iterator, + accts_with_unaccessed_storage: &HashMap, +) { + for h_addr in accounts_with_storage { + if !storage_tries.contains_key(h_addr) { + let trie = accts_with_unaccessed_storage + .get(h_addr) + .map(|s_root| { + let mut it = StorageTrie::default(); + it.insert_hash(TrieKey::default(), *s_root) + .expect("empty trie insert cannot fail"); + it + }) + .unwrap_or_default(); + + storage_tries.insert(*h_addr, trie); + }; + } +} + +fn create_minimal_partial_tries_needed_by_txn( + curr_block_tries: &PartialTrieState>, + nodes_used_by_txn: &NodesUsedByTxnBatch, + txn_range: Range, + delta_application_out: TrieDeltaApplicationOutput, +) -> anyhow::Result { + let mut state_trie = curr_block_tries.state.clone(); + state_trie.trim_to( + nodes_used_by_txn + .state_accesses + .iter() + .map(|it| TrieKey::from_address(*it)) + .chain(delta_application_out.additional_state_trie_paths_to_not_hash), + )?; + + let txn_keys = txn_range.map(TrieKey::from_txn_ix); + + let transactions_trie = create_trie_subset_wrapped( + curr_block_tries.txn.as_hashed_partial_trie(), + txn_keys.clone(), + TrieType::Txn, + )?; + + let receipts_trie = create_trie_subset_wrapped( + curr_block_tries.receipt.as_hashed_partial_trie(), + txn_keys, + TrieType::Receipt, + )?; + + let storage_tries = create_minimal_storage_partial_tries( + &curr_block_tries.storage, + &nodes_used_by_txn.storage_accesses, + &delta_application_out.additional_storage_trie_paths_to_not_hash, + )?; + + Ok(TrieInputs { + state_trie: state_trie.try_into()?, + transactions_trie, + receipts_trie, + storage_tries, + }) +} + +fn apply_deltas_to_trie_state( + trie_state: &mut PartialTrieState, + deltas: &NodesUsedByTxnBatch, + meta: &[TxnMetaState], +) -> anyhow::Result { + let mut out = TrieDeltaApplicationOutput::default(); + + for (hashed_acc_addr, storage_writes) in deltas.storage_writes.iter() { + let storage_trie = trie_state + .storage + .get_mut(hashed_acc_addr) + .context(format!( + "missing account storage trie {:x}", + hashed_acc_addr + ))?; + + for (key, val) in storage_writes { + let slot = TrieKey::from_hash(hash(key.into_nibbles().bytes_be())); + // If we are writing a zero, then we actually need to perform a delete. + match val == &ZERO_STORAGE_SLOT_VAL_RLPED { + false => { + storage_trie.insert(slot, val.clone()).context(format!( + "at slot {:?} with value {}", + slot, + U512::from_big_endian(val.as_slice()) + ))?; + } + true => { + if let Some(remaining_slot_key) = + delete_node_and_report_remaining_key_if_branch_collapsed( + storage_trie.as_mut_hashed_partial_trie_unchecked(), + &slot, + )? + { + out.additional_storage_trie_paths_to_not_hash + .entry(*hashed_acc_addr) + .or_default() + .push(remaining_slot_key); + } + } + }; + } + } + + for (addr, state_write) in &deltas.state_writes { + // If the account was created, then it will not exist in the trie yet. + let is_created = !trie_state.state.contains_address(*addr); + let mut account = trie_state.state.get_by_address(*addr).unwrap_or_default(); + + state_write.apply_writes_to_state_node(&mut account, &hash(addr), &trie_state.storage)?; + + trie_state.state.insert_by_address(*addr, account)?; + + if is_created { + // If the account did not exist prior this transaction, we + // need to make sure the transaction didn't revert. + + // We will check the status of the last receipt that attempted to create the + // account in this batch. + let last_creation_receipt = &meta + .iter() + .rev() + .find(|tx| tx.created_accounts.contains(addr)) + .expect("We should have found a matching transaction") + .receipt_node_bytes; + + let (_, _, receipt) = decode_receipt(last_creation_receipt) + .map_err(|_| anyhow!("couldn't RLP-decode receipt node bytes"))?; + + if !receipt.status { + // The transaction failed, hence any created account should be removed. + if let Some(remaining_account_key) = trie_state.state.reporting_remove(*addr)? { + out.additional_state_trie_paths_to_not_hash + .push(remaining_account_key); + trie_state.storage.remove(&hash(addr)); + continue; + } + } + } + } + + // Remove any accounts that self-destructed. + for addr in deltas.self_destructed_accounts.iter() { + trie_state.storage.remove(&hash(addr)); + + if let Some(remaining_account_key) = trie_state.state.reporting_remove(*addr)? { + out.additional_state_trie_paths_to_not_hash + .push(remaining_account_key); + } + } + + Ok(out) +} + +fn get_trie_trace(trie: &HashedPartialTrie, k: &Nibbles) -> TriePath { + path_for_query(trie, *k, true).collect() +} + +/// If a branch collapse occurred after a delete, then we must ensure that +/// the other single child that remains also is not hashed when passed into +/// plonky2. Returns the key to the remaining child if a collapse occurred. +pub fn delete_node_and_report_remaining_key_if_branch_collapsed( + trie: &mut HashedPartialTrie, + key: &TrieKey, +) -> Result, TrieOpError> { + let key = key.into_nibbles(); + let old_trace = get_trie_trace(trie, &key); + trie.delete(key)?; + let new_trace = get_trie_trace(trie, &key); + Ok( + node_deletion_resulted_in_a_branch_collapse(&old_trace, &new_trace) + .map(TrieKey::from_nibbles), + ) +} + +/// Comparing the path of the deleted key before and after the deletion, +/// determine if the deletion resulted in a branch collapsing into a leaf or +/// extension node, and return the path to the remaining child if this +/// occurred. +fn node_deletion_resulted_in_a_branch_collapse( + old_path: &TriePath, + new_path: &TriePath, +) -> Option { + // Collapse requires at least 2 nodes. + if old_path.0.len() < 2 { + return None; + } + + // If the node path length decreased after the delete, then a collapse occurred. + // As an aside, note that while it's true that the branch could have collapsed + // into an extension node with multiple nodes below it, the query logic will + // always stop at most one node after the keys diverge, which guarantees that + // the new trie path will always be shorter if a collapse occurred. + let branch_collapse_occurred = old_path.0.len() > new_path.0.len(); + + // Now we need to determine the key of the only remaining node after the + // collapse. + branch_collapse_occurred.then(|| new_path.iter().into_key()) +} + +/// The withdrawals are always in the final ir payload. +fn add_withdrawals_to_txns( + txn_ir: &mut [GenerationInputs], + final_trie_state: &mut PartialTrieState< + impl StateTrie + Clone + TryIntoBounds, + >, + mut withdrawals: Vec<(Address, U256)>, +) -> anyhow::Result<()> { + // Scale withdrawals amounts. + for (_addr, amt) in withdrawals.iter_mut() { + *amt = eth_to_gwei(*amt) + } + + let withdrawals_with_hashed_addrs_iter = || { + withdrawals + .iter() + .map(|(addr, v)| (*addr, hash(addr.as_bytes()), *v)) + }; + + let last_inputs = txn_ir + .last_mut() + .expect("We cannot have an empty list of payloads."); + + if last_inputs.signed_txns.is_empty() { + let mut state_trie = final_trie_state.state.clone(); + state_trie.trim_to( + // This is a dummy payload, hence it does not contain yet + // state accesses to the withdrawal addresses. + withdrawals + .iter() + .map(|(addr, _)| *addr) + .chain(match last_inputs.txn_number_before == 0.into() { + // We need to include the beacon roots contract as this payload is at the + // start of the block execution. + true => Some(BEACON_ROOTS_CONTRACT_ADDRESS), + false => None, + }) + .map(TrieKey::from_address), + )?; + last_inputs.tries.state_trie = state_trie.try_into()?; + } + + update_trie_state_from_withdrawals( + withdrawals_with_hashed_addrs_iter(), + &mut final_trie_state.state, + )?; + + last_inputs.withdrawals = withdrawals; + last_inputs.trie_roots_after.state_root = final_trie_state.state.clone().try_into()?.hash(); + + Ok(()) +} + +/// Withdrawals update balances in the account trie, so we need to update +/// our local trie state. +fn update_trie_state_from_withdrawals<'a>( + withdrawals: impl IntoIterator + 'a, + state: &mut impl StateTrie, +) -> anyhow::Result<()> { + for (addr, h_addr, amt) in withdrawals { + let mut acc_data = state.get_by_address(addr).context(format!( + "No account present at {addr:x} (hashed: {h_addr:x}) to withdraw {amt} Gwei from!" + ))?; + + acc_data.balance += amt; + + state + .insert_by_address(addr, acc_data) + // TODO(0xaatif): https://github.com/0xPolygonZero/zk_evm/issues/275 + // Add an entry API + .expect("insert must succeed with the same key as a successful `get`"); + } + + Ok(()) +} + +/// Processes a single transaction in the trace. +fn process_txn_info( + txn_range: Range, + is_initial_payload: bool, + txn_info: ProcessedTxnBatchInfo, + curr_block_tries: &mut PartialTrieState< + impl StateTrie + Clone + TryIntoBounds, + >, + extra_data: &mut ExtraBlockData, + other_data: &OtherBlockData, + use_burn_target: bool, +) -> anyhow::Result> { + log::trace!( + "Generating proof IR for txn {} through {}...", + txn_range.start, + txn_range.end - 1 + ); + + init_any_needed_empty_storage_tries( + &mut curr_block_tries.storage, + txn_info.nodes_used_by_txn.storage_accesses.keys(), + &txn_info.nodes_used_by_txn.accts_with_unaccessed_storage, + ); + + // For each non-dummy txn, we increment `txn_number_after` and + // update `gas_used_after` accordingly. + extra_data.txn_number_after += txn_info.meta.len().into(); + extra_data.gas_used_after += txn_info.meta.iter().map(|i| i.gas_used).sum::().into(); + + // Because we need to run delta application before creating the minimal + // sub-tries (we need to detect if deletes collapsed any branches), we need to + // do this clone every iteration. + let tries_at_start_of_txn = curr_block_tries.clone(); + + for (i, meta) in txn_info.meta.iter().enumerate() { + update_txn_and_receipt_tries( + curr_block_tries, + meta, + extra_data.txn_number_before.as_usize() + i, + )?; + } + + let mut delta_out = apply_deltas_to_trie_state( + curr_block_tries, + &txn_info.nodes_used_by_txn, + &txn_info.meta, + )?; + + let nodes_used_by_txn = if is_initial_payload { + let mut nodes_used = txn_info.nodes_used_by_txn; + update_beacon_block_root_contract_storage( + curr_block_tries, + &mut delta_out, + &mut nodes_used, + &other_data.b_data.b_meta, + )?; + + nodes_used + } else { + txn_info.nodes_used_by_txn + }; + + let tries = create_minimal_partial_tries_needed_by_txn( + &tries_at_start_of_txn, + &nodes_used_by_txn, + txn_range, + delta_out, + )?; + + let burn_addr = match use_burn_target { + // TODO: https://github.com/0xPolygonZero/zk_evm/issues/565 + // Retrieve the actual burn address from `cdk-erigon`. + true => Some(H160::zero()), + false => None, + }; + let gen_inputs = GenerationInputs { + txn_number_before: extra_data.txn_number_before, + burn_addr, + gas_used_before: extra_data.gas_used_before, + gas_used_after: extra_data.gas_used_after, + signed_txns: txn_info + .meta + .iter() + .filter_map(|t| t.txn_bytes.clone()) + .collect::>(), + withdrawals: Vec::default(), /* Only ever set in a dummy txn at the end of + * the block (see `[add_withdrawals_to_txns]` + * for more info). */ + tries, + trie_roots_after: TrieRoots { + state_root: curr_block_tries.state.clone().try_into()?.hash(), + transactions_root: curr_block_tries.txn.root(), + receipts_root: curr_block_tries.receipt.root(), + }, + checkpoint_state_trie_root: extra_data.checkpoint_state_trie_root, + checkpoint_consolidated_hash: extra_data.checkpoint_consolidated_hash, + contract_code: txn_info + .contract_code_accessed + .into_iter() + .map(|code| (hash(&code), code)) + .collect(), + block_metadata: other_data.b_data.b_meta.clone(), + block_hashes: other_data.b_data.b_hashes.clone(), + ger_data: None, + }; + + // After processing a transaction, we update the remaining accumulators + // for the next transaction. + extra_data.txn_number_before = extra_data.txn_number_after; + extra_data.gas_used_before = extra_data.gas_used_after; + + Ok(gen_inputs) +} + +impl StateWrite { + fn apply_writes_to_state_node( + &self, + state_node: &mut AccountRlp, + h_addr: &H256, + acc_storage_tries: &HashMap, + ) -> anyhow::Result<()> { + let storage_root_hash_change = match self.storage_trie_change { + false => None, + true => { + let storage_trie = acc_storage_tries + .get(h_addr) + .context(format!("missing account storage trie {:x}", h_addr))?; + + Some(storage_trie.root()) + } + }; + + state_node.balance = self.balance.unwrap_or(state_node.balance); + state_node.nonce = self.nonce.unwrap_or(state_node.nonce); + state_node.storage_root = storage_root_hash_change.unwrap_or(state_node.storage_root); + state_node.code_hash = self.code_hash.unwrap_or(state_node.code_hash); + + Ok(()) + } +} + +// TODO!!!: We really need to be appending the empty storage tries to the base +// trie somewhere else! This is a big hack! +fn create_minimal_storage_partial_tries<'a>( + storage_tries: &HashMap, + accesses_per_account: impl IntoIterator)>, + additional_storage_trie_paths_to_not_hash: &HashMap>, +) -> anyhow::Result> { + accesses_per_account + .into_iter() + .map(|(h_addr, mem_accesses)| { + // Guaranteed to exist due to calling `init_any_needed_empty_storage_tries` + // earlier on. + let base_storage_trie = &storage_tries[h_addr]; + + let storage_slots_to_not_hash = mem_accesses.iter().cloned().chain( + additional_storage_trie_paths_to_not_hash + .get(h_addr) + .into_iter() + .flat_map(|slots| slots.iter().cloned()), + ); + + let partial_storage_trie = create_trie_subset_wrapped( + base_storage_trie.as_hashed_partial_trie(), + storage_slots_to_not_hash, + TrieType::Storage, + )?; + + Ok((*h_addr, partial_storage_trie)) + }) + .collect() +} + +fn create_trie_subset_wrapped( + trie: &HashedPartialTrie, + accesses: impl IntoIterator, + trie_type: TrieType, +) -> anyhow::Result { + mpt_trie::trie_subsets::create_trie_subset( + trie, + accesses.into_iter().map(TrieKey::into_nibbles), + ) + .context(format!("missing keys when creating {}", trie_type)) +} + +fn eth_to_gwei(eth: U256) -> U256 { + // 1 ether = 10^9 gwei. + eth * U256::from(10).pow(9.into()) +} + +// This is just `rlp(0)`. +const ZERO_STORAGE_SLOT_VAL_RLPED: [u8; 1] = [128]; + +/// Aid for error context. +#[derive(Debug, strum::Display)] +#[allow(missing_docs)] +enum TrieType { + Storage, + Receipt, + Txn, +} diff --git a/trace_decoder/src/interface.rs b/trace_decoder/src/interface.rs index 282671962..55ae5eaf0 100644 --- a/trace_decoder/src/interface.rs +++ b/trace_decoder/src/interface.rs @@ -8,8 +8,11 @@ use ethereum_types::{Address, U256}; use evm_arithmetization::proof::{BlockHashes, BlockMetadata}; use keccak_hash::H256; use mpt_trie::partial_trie::HashedPartialTrie; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; use serde::{Deserialize, Serialize}; +use crate::Field; + /// Core payload needed to generate proof for a block. /// Additional data retrievable from the blockchain node (using standard ETH RPC /// API) may be needed for proof generation. @@ -169,6 +172,8 @@ pub struct OtherBlockData { pub b_data: BlockLevelData, /// State trie root hash at the checkpoint. pub checkpoint_state_trie_root: H256, + /// Consolidated block hashes at the checkpoint. + pub checkpoint_consolidated_hash: [Field; NUM_HASH_OUT_ELTS], } /// Data that is specific to a block and is constant for all txns in a given diff --git a/trace_decoder/src/lib.rs b/trace_decoder/src/lib.rs index 53db82a69..8c54eea8e 100644 --- a/trace_decoder/src/lib.rs +++ b/trace_decoder/src/lib.rs @@ -55,6 +55,7 @@ const _DEVELOPER_DOCS: () = (); mod interface; pub use interface::*; +use plonky2::field::goldilocks_field::GoldilocksField; mod type1; // TODO(0xaatif): https://github.com/0xPolygonZero/zk_evm/issues/275 @@ -69,6 +70,10 @@ pub use core::entrypoint; mod core; +/// The base field on which statements are being proven. +// TODO(Robin): https://github.com/0xPolygonZero/zk_evm/issues/531 +pub type Field = GoldilocksField; + /// Like `#[serde(with = "hex")`, but tolerates and emits leading `0x` prefixes mod hex { use serde::{de::Error as _, Deserialize as _, Deserializer, Serializer}; diff --git a/trace_decoder/tests/cases/b19807080_main.json b/trace_decoder/tests/cases/b19807080_main.json index 3a09e82d0..ddd67d1e0 100644 --- a/trace_decoder/tests/cases/b19807080_main.json +++ b/trace_decoder/tests/cases/b19807080_main.json @@ -1010,7 +1010,13 @@ ] ] }, - "checkpoint_state_trie_root": "0xbbd66174555d27c88e285ff4797de401470d8d2486d15513ab36e491e864bca2" + "checkpoint_state_trie_root": "0xbbd66174555d27c88e285ff4797de401470d8d2486d15513ab36e491e864bca2", + "checkpoint_consolidated_hash": [ + 7715853179812774584, + 12908177954576181071, + 11068935829000177885, + 16446535885506885907 + ] } } ] \ No newline at end of file diff --git a/trace_decoder/tests/cases/b19840104_main.json b/trace_decoder/tests/cases/b19840104_main.json index 6537bc456..6c788e0bf 100644 --- a/trace_decoder/tests/cases/b19840104_main.json +++ b/trace_decoder/tests/cases/b19840104_main.json @@ -1,366 +1,374 @@ -[{ - "block_trace": { - "trie_pre_images": { - "combined": { - "compact": "0x0103e13c370f7ce6f9de81dd4068775d7c39d1e19051063dea7b4f0dc570ab06868103940aa0f44732cfe96e03cc53d65cc93839531689de2370a6bc12eb515a75f6ea03cce25a8e8a0b65fddd641e8856e8baec7cd1a012b7470e92aea3d4f6fd02c1c80386d98f1b6d13f0446b302efc1197100dc2d2d10c9e7db46ec2a34d55b2f0bc9f0345a634828040159ea3390d453145c5e97f3406575308f3803fc63944db067cbf03cb91ecd916f16b6227a60215cab43c4b9a409b19cb9af242375517af5841ac5d0329a14ef57d4d2282d4f7479ea6d37f728b45af8ac42a621a953369de0b54535503c4c441ce0b6d427b5577cd15b9cd890ff95d1434d101165be1623b9cd1ef67b6035ffdb8ef07117acdf909af168d381bf8e503dba36547fe5895671e9d495add1c03324e1dcc50950c11240379740d5b383f879719bb1d477d04592d65471d973e8203f355ecc89a4b76dfdd7fa0f0318293854c502c03a74c0c4ce388fcd79835e0bd03bb455a53b6153bf3fb7e0fc6db20d7ef3661942e9e957af3b9120f91f755984103be0773cd56d7c9df1c8062a9c35b731b1359b4b9ef8c31a5c74c7286d96fcac103f7dde717fe02b995df87659a9cf25cc95f994360e2b8cba31db4183c14c9670203c669e29de38188ac1e9b8662b0d995e31e500883d08affadd4eaf71cb7ae43b603dbe9990a2e3a1b78a7e86924142e73d32e6a5fe8ff15f9d923df57f5f5667c02036a42738b24621de70cf0a5975e4e0de90c279602ed12d99c46e9951927348d1f03476ce5c4306a2f9875011e1b52bfad9af7f9eaa53a0c09725b641957f6e5abd1033a6eee3a707b54e089427a7df5f4d780cc9bf727b8527a2670b3e558fc580ebd037c900a244c50a273971a28d09b3e5448a2d3b92248efb447d5e914c83885d94c03cbb3c52e38138f069c39c31753b3a1e333713637c57dc2f38dade06d65833c4e032e9e786d65c8c00c3053a66aafa6d738b6029bd9b44ca911fadbb1b22bbccd3803f23a75947392a97153c9fabd3ebe5d109892d7ae8a4d3b64458d60fb5b0cdef0034c0924eddf164fd85e99748a48284ca73c4b2dc83edb9d3072551b3a6be0f94703bcf4e068ce6001b29bd880451c3388ef1c144cd79c727000046ef06b8b6beaa403b615536da0f1386f5dd58645a0955875bf7e4c00c8bf8397054268b30a5ca536038f67227b47f06ade1eb106d7b50bd823a327fc6d04556d011b98e4e695a6578e0328a17cd0c678af3871f0a5d3dfe41ff24967fbb7f11726dbf53707b5c27a5961036ce3286ec2d725cfeb234d4a29386ac1b057ea5109e381b59f5816430e82386c03a2d833f5221678f65bb919bab928e1ac2a21fb16c768c802385743c1f20f33bd0394ef837d0a9420521c9b61374d3433c534a22365b1ef1d34c305b1d4d508b17803245d8e881b569e0f2859d441687596d69a1f13172b721b798abdaa13cd61acf10331b17ef9b060f53595553fba5298848848045635c1ddd4867fb8834193531efb03b254caa5808fc83395b676f33b88eb741b88fbd627dcfbe735a4924fb3a7ef47032c53e4633f67dd8f1cd3b97857e2fa1888a08113bd4ab0ddd9f3f0667b75f31d03ebfe5a0154be1c4918681bb0b84185583e2381f1c034dbfeed740abe5a18a73e03e0414af533edb23b377e58da622436a7e1bc72da8005d38e7403e9c796fc8d7d0354fdd1dcf7c140089c99e10173a00bde1620974e76caa85b89c61386854d2e1e03a4fe5ae7bb248ad34f6d6c3cc546f3945bcabb9ea6832e5b2c126fb2948d37b0038436e7414d7bd51873cf6d66cd7100548bc241391940c4596cb8fd8318c9eb43033ef1123618d733594d9bde1b472f2695835b273426ef0e82d2901eced8db7402036499aa00f5cc368850094bfc120b9b888f16d1b2882fd29bae671a5c415cb83c03d27584f834991d48dd9d39eaf146fd21299f67af62a7f0f8c56f316b58c812f503c22ffb33a73ace056ec28dccf8f19920c8075a47151913e13bb76de334454350035bef61b2be3a91a5d66d92b259cb46bbe3a8a5866efac22f59f73f70174791b503c892127d3f6cceb7c41af2f17aa67450342f091879adb9acf3a7b5a8c1035ddd03556d3ec12e5343a2ef72db2e7ef381104279b2476ce4ae4a56b660b50347595203835ea527241d3ff19f15c1d172c75245fc94e1e2680fe5d2551b6225417ecdbb03fffa2540a1573b228956fa86248745aed31ae6e2c983714f32fd9dd7fc58c36a05581e0329328c87be9836183768908f30171daf16714c1f39a360b617bd23df400c0a4629546746ae0805581e03934cc196d443b1d2c5588f9fe55fa70f673923ac0eef128d9203835d500c0147c7a8357a0fa80005581e038bc60869ca403f3d41ddf8575cfa5be7785783dfb7dccc395b1ad999b00c01470d35cd2acec40005581e03d4abd7a5e810b20841e6aaf7fdba78949602e371cc5ff9aac8f74876200c054702c0246afc0c000458613373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff0155000358c5239b1dd310f0537a237bc27563369523c442d801ec8818db3671c74674540365826e2e7ab17befd18111567901f4d1c040051467d927e308ce4b248822a0cb03b1c225aa33368624bda2174d75e18cf62636a5b76c4c6e1b2e418d4f5b2a355f03f9f0c35958ba855fe3b67c2d3e281098a811faf015ff970c2ac1ed7519b7a9f90340d8abd4aea2178e472a6fb5d9a54ab7d9da7b4cec41de15657ae7d7ee47ee9203b4b2017ac478ec2fecab17810a12138dd142aed069ddb547bc6ca75f30d6edbe0306ea5daf16f46213f499aabb9937cce13f5fef58bb32f6e0cb3e9a06a0b51e5e035f11d8c8b2a04750588c9cb0a75e46b7e6e954dd62adfd624acf8da2643082d903a0eed321da78a0ebdd5fe9921d733518413a2cb187ca6c1105f7abd1cb2fbb1b0311b7c5e1e609f177f216cde5180864e5b646e33cccdacb581e3f588664f2aa29037d0990dcadece1c27990f6006dfb1b06731a2e38f30a794da8bad6323491555b03fe92a1e51e25e90d509a1d38bc6f2a9fe43e4f72047a2a24b870c8d30fc64b6703bcde60f65dd3d2ca3a2f2f4b0fea9276db48ca7062d6b0b6aaa3a0510d812fc003df6748c404401faeb51fffb775298fa91f0dd2b737b0f8595ddd8053103833c50367ba887e07b40051afda724bac2d9295be9135f1fabf12fcb95ef8762bbc5e54005820035b0fcf3bd800db1425c3b5cea82894f4bcd6c6e3f3681233ecaa3a21a22a3044663cc98f03a6b7d063b82dec0e83c94ca4a3eb6519dad637b47c2321d17ec61548a784c95703fbf5999fcabba0e2ed169e657630905ddaa06e1ff8ded70eec12494da396b04f039ebc1b67747b6a172ee99df6e8debb1b98d1bb2af2fd4d7d9233c6f86fb8bb9a03262f082f2f808c68b5102bd0ca743333881bcdf56c5b0caf594c71733ed0c34700582003cddb82bd7d6f65fe1dc37f3f335825dafeac204521b498c3035fca9d24671044663d7ae3034ccdf84f270e9fb07171b769d1737ca3cb47be3d33be2cd32aab896647a32da0031f8901f34af3b4a8bac1e2b5d52650022a64650558a0c04c5fb4599c094dd08f03f52e9a5bf4207d9cd90239f7199782d58a55fceb3895fa2cb4cc9542d2a5872303e3af39c59d84c6dd4bbb43417edf1e939070570d233bb5a1b7198c4d67b1567100581f02b50381a466ad9b3f5753ae9d99dc1961955a9450f39a54fe5ed20f23703944663cfcbf00581f02d7283d573d576507b2896b999a1774e22aadc14d202294c19a0f513a12fb44663ca90700581f022d34ba1eaa86355c866834b1f968ae22db024991e5f42a9a675196c9459d44663de78b02198410035714c53a00c63f7abf88010b7d8641a6f7c834c8c8b6ab07d1304165dd133e2603fb951dd6719d0846becbb4d55276d92a7a77f6687eba589ff57bdfdb799fe4ce0328f4625c2a4b7929cbf0ea4f0b0e3459896a55de82446c8997a5856856abffd90391340802d5194304e8a2f4323c84da7647cf985a3c6d2a1ef795dbd8a53817800219bfff03576e9c67f4913b6dec689d445a1d0cd79a90fb1c9a2f0c87a2ba84d25171980603d924cd2dd4d5362c29bcbb0fc4f61e17558e556aea838c8d09ab96901ba11fe3033517c66a20bd6abd4b1ee2e5cd45298563b00fd979ad371af28dfe95b868322a033e0ce59b58426d4eb6806b518e0a18ab4d6ebeda65951a616eb9c9c917b983520219ffff03387f24a9b1c6be19fad5f890ca5c502479f798fa7a51ebdf492ec7752bb784ba03244183a300b82435242d6e0b450a90dd10e49846e00e2cda1481f2cd6893f04b03356f09c737f039614e52e2e0c37fb7a70313ace29b2154d9114db788f0ae541a03ad4ee9196fcc075e9a4dc9fd2bb8c75338dab17003f968d73480b3db389bf9d7031d739c09b9667fbd3f6ab1ef093a08e2c5366e1d6acda970be8d1c3fddedc2a2031afcc8c217d91826795f263a1f09fe4f6130bbd58deca5fd7c33077375fa1cf5032a8efece59d3d07314f21a48b9d4e15cb7c42c0780b4da74b5713427a941530403f0804f578891545342627171f5a9f2262c76551c8dff1d87e1d4f600e0dba569034e67010819e15c986e4fc147d9d699936155d18e88644fabd15bd556521a9b7203b6fd210aee5e046b5053ad7132b8c705eaeeee963dd7c5efe7209d356667b6e803b5c9b2a4290b6130b89889f84edc7688e2d8893cf6671a82834411fe9bf6f27003ec93db40b8df894e80edcf0202cd39373099967eb1e75f285e6cc998e7b5b26803692dcb502f53043296639d68228f69c17e83663caf8ab3cae97b1674befdb8e103d5c209b220a62d28e6f24c89d7d6a37de20b3fe53afa4e39f71b5759f4d3e4c4032a92f5ace6d6fe31425c6282bbda8e84e2db0345cf5662433266e1bf343a12b403e12845abeacbb0beb485495bef7d65bf834364233fece312a49b576ff3c340bc03e6a66e06863ede15f9f2aa3ade52cec2ca242e3f806c40699a40d9284bd88b94037d6889baaf1cc4d81c4acd0d0e884c685ffb3a2d29cae5b0727b2ecd3e8d8dd2035982174780f06ddfdd84d88987dcbdc69ae1279de27976eb62d2e5abcfa1c18b03e13a3a9a9b2880112b3171f114eed30dcbc533ff7d56980c8898a82d1f4482c7030e65acda5fde29d1cc76bbd3ffc17d8acbbde66d3e68b6a5d9dabe5204525aa103c5a998297fe5c2766bf6dcaa34f57328a1961bbb6140e34f22155c4904bcdcb203f53af6a0b865c4f515acc6d3c93000e2cddc6f8e8d961c2672a7629d1907994303a7385e81588f6c99b53022f433eb8c00efc96fa67eb6331327cac4b1a07d7585037f98a226ecdb56c0d8651302d8b22d2acff8bc0eecd3e3213753028839c0d92903cf753d039db5e738d1ee967356555d047215a4bb82aab79373c359ff70a4478b0379a542cab81cfd9d454470df1e42547fa517c5d3120e5bd3730d98934b64e62603a05dfba906e040db50a0afa79a425201f74146354d88c2754c5821eb719b5190037b2a32ea2c5f26a8552a7872f3ce840aa447e7d9c0efb0b03c99d131161b810903f7b2d22dd98c0f407dc59ac30c13260cec6e6565f54b9d9b09c4bf1bff9829e50371a35ec266c88aed1b2897e3f36a14cbb329816629742399d38ccf05c541a55700582003c8baf22843559d0eb809346dcfbcc9cae4248ce96c61ee9416d0767869af1044663d262f0395451063870cbebd1a1c414c042a67a269e123a33eefbe12795ca4533cbee4210377696199292b63a284658963a209f97c039eabfad945fd77a3e3d3a2431baf2f03c62ede3a485a67f19ceee383b691bd1579d726b72f36bd25966b245d2658c99f0362f50e33577871564dd39157ff97bca77d58296e10eaf771487a741d7c032be10364f74730c91f576090ca0ba7b1e956e4003c70aa7dd5bfc978ce3110ff013e5b00581f0238787dd0e1f5d8a1615fa968dea23acfd3d692e6fc565b123f7caf145eff5820fd7d812e8f33936363ce5cc165cab273cc02af6aee8da3d42370f4d343c6f1fd00581f031906aedc23fbbf5f6acc171555cde2fc54aafcf7c2b796b6c9407434c47058201dd3ed11c47ea3f75e3c5ca68e5ab9e0bbb7ecda2318917c262c27a9af24af1900581f03c2e6f82dfc83b58e2df5c82f2a4b3a3d5a9f68fbfa24b96adf46c00deeb044663cb0330206021928000219ffff0219ffff03db912c435e75072736adad652ecfc4673017ec25347326549992227d294d856b0309e3878fa9a66b2f5cc86044daab843416ab5977bcf6dc06b760060f09ec7ca2037c1fe9f58ca2408965a47d402563a15f2fcba83a4a6eb0df1b030da50ba63a4b0219ffff05581e03a92c6bc4c13a5ec45527f0c18ea8932588728769ec7aecfe6d9f32e4200701186103efc4a95eba2b0e8ca1e7050522d539fcaee456a9baaed13b74846ce6e9f5284f05581e0387d430445038d44dfe5f67a6a29f0e61137f74004f19eb39df5f6507100c134622a41c687260035a6395100cee14b8619641123268781a56f8d9fad4ec4d364c15d99ab81fd8650219d595035d3b51473708235f94b7786ec3d9e1141cffde44d1b3c2f8f50735bc89406bdc0219ffff03bb6dce5781ee1b12b6667ebff1c6a7e00b27f644760beec12fb305c5eca6748703c2659bef399996280795da7d7c6cc8380980b8ed448477279fce86cb1439815903e45da9fe37e969afed21a06e65aab4b8219e0be940cf6c2d96a3312dde77c4ba03cbeb42d91012dfa7755211b9ebebc4e6481daa53edeaceb78a26478589a5171c0355e8cbfb54708ecacf62e4d8e82d3ac23e130e81a0a767b06f854fc5a76a803203d82d3c30bfa72b176d2285d259d03f43e6dccdc50cc03dff946f850414c15e6103b84ba827a5ef576ce6db5eeb236b0b05db5fa57d18448dfa5685297e76ae072103494925526b1d70068072e28e02df4d43941cfb627cfba3d4a148a8e857bee15e03cd19d837ba2dea15c076f66e441a92c62e7c353901568a45ba5f71e66e88d278038ba8c6e5027ea75be5cc7cb96300e7201167a07c4c58fb06c272593502d8b9dd0219ffff0301b8e895dbf6e8f0d41d8a44ae0ad8221319b0b3232425ee213ed801d9eb9ddb03c15636c31d015e3f4a306e5ca113823cf9bcf4422ae44ce6f9833e1a4c92a87b03e4b068e19c0ce1a9cde31af1072d04cdbe5f101a86ab598ee61a8ccb7a5160e3035131433214d21d38997d1bd4d2eaf4a69ee15f096d86344b920532b298824fc303152393ebcf209df305d93fcdb3ee0d6c9c28dd5fed398bdaf44f0e32a1253e5b03c28ccc74e893b02e05d6d5447b79d210a80b3799c658e3b2cae91e64f250d52d03b663e80603c7f9bb86ac127aa3726183321274f5675178b609500bd338fe6689034a4d70349a6c431a3edaefc60a1dfa6f6151ad5d23e0028b924ea72676af2798033122fd4a0193f4e18ca6f08a697c0af1c8141e2659da5c6bf0f87f5ed86ed8a70219ffff0372acd27b85056450bebd86a5a917527908636a4c781fa8535f6801d52643cbe60313561846f55baa646d462f32f65378782aeb0a36ec4396cb1dd95ff2e32a73cb0219ffff03ab23c03eb82757b5599c6b1b720f61171157020454f78fb6fba98f50b444103603d21ed651d18455a8a402320838db0c0ee34b4fd81fa20fdd9fe9bc10a3f6756f03f215f60497fcb591efea4098f8e6d1af4260aa34dd0143154ccca2ff7a41371103390f008988bcb2194db38af1ae0c5b450fc67aa63847c3333631236ff160ddca0392da5bcac8b88fa85dd08f6c0a2c54c8049826621e9de17655a5ac61c896422e03361866a4d5b1c4ae521a022b8d0bf3f956cce9f4558293865b4e2e09b679f5fc03c1204c89e187aa54d5bc785652301c858d3b8a3a271e3b29970f5e35b03f03b003e5d334dae613ef68f86ecc885179c64542cbe18c5b4aa3bd929eb6d2bf5d9e430219ffff03001cc050182fb06ae5d5cb21738d6a93d6acec33ffbada6bb24116265a0d418203eec4298676ca64e441552ff83659d2575ad601c6fc53e98344ea7882a0fe1c56039d6b1ff6c754633d01894c26d7ec56ad635490dfb291b08544cfd1b5dcb0cec3039a6d2abc2c326ca7b11f03d687495f40353542ae9b674bb6c59bcc6956657d8b03fb6d16aa3f68791b386410f1c544051aef6b48a87517f2c2f60be6c45290bc0b0364b38a393150f0aeb5df8ae532cc8017202732b532046e192a385a1df530a1db03cbb43ac36287287ae24670a0c4214587495798add9fbd6124993f2c6629d4236035826a6a848d733844dd5987c128e28517f21bc7c06fd3742853a2d94c29cca9203f49b340fc1b72e277463376094dbbb5ab76de329e2984dffaa0324bff1cf9c6b03c61f7518e360642bc12298499dea86e091bad02e3082654be4ab16ade8be481303f3cc663d1119c0e755090ff50e657071c1b7aaf76f5049f8f68efd2fb3e2a76c034f1fc53876be73fe021b3da55b1b841bb1e1d6ca99a8687da7557638ec4021cc03152f541cf3ee990146f63fea1d9b53abaf06a58b00a2ab68fce1c0f5b0c489120387f624a5927e67b0a59632a5850f1c011737bfa8f3a51c937ea14a3988e066b20323c3238b822b325fe11ec12c14e024ddf5710d8802e5c85d1ce7c47fb02a52b303fc2eab2d511cbc973f0716322261116d8b81f804ad73d6d380caf1c42989ecea03067c67cd91a2747c892fd1605d2a38c8b7409376e9684323b7694d359eabf9ff03097bfa2378565be66df31046bbd59bd5d4c2c14299553cc58d7ffb2ecf27699603ddbec2457d43fcf01730e63a612c370b56bb911de1147bd597396fc1a116484e0390b76a69782f11b0cbea81d1398b41e2927e5edb66688c6c728806bce71839d103a1d7ebab554c080cb2fb2cb17667e3058fb3537ed64855620f7305c9c45973e5039c2e37751faff09ddd740b02db8f0ee80d92547b41e50ef9a3d2113bdd2f18be0330ae1b86a3326ef4be28d5c2470d8808df51f32e5399ba760da826f46905959f0362cad7ebe4f2c9f7e283ebe4f1ca1dc9e8e7c8bedc52ae4bde537a19beea1f1d03d51b9c0f3ccf30ef1a3754573521f05d4981b3c7a0eb635ddc81684ab75fdc9b03766ce30501987085efd915e492dc68eb6fb728a13070605c762c2dd8fc65c9e503d2be7794bc7b7ac3eff3e2bf8fca6721b9d7304e19263153d566066109a5fab505581e0329e4cb84257f3a85c60d49d690d86c942f7d8521e57336a24bd99719500846f84ac406100005581d0231e95b8419eb826136a480dd3e995ed8b16c389a83abf73d262522a80c18434a049d41dbc0f641387da905581d021defeb7d022491798adb92c6a0e0bbd3e028c60b710678fcfc65bdc804030219804003f0a45890bea7520a3246b1d46241f5163e20df1f78ed7ae79c9d2c9c8491ce5003c33fc0d0e68fbd9b43795a1d49f372864646e80a64b2ae991aafe78cf1a6b8bc05581e031342fc8a455f0bb4cf1cf5c8d538e0fc58be64fa5515ece1f52ab69a9007011bffffffffffffffff05581e0377c6fb8536ebf253b0a73a57f2d3dd389ca68dd09a55ca7c9402700640040105581e038548cf6f40bc75e6b2075230a9b50dab25ae567bbff331319892bb76200c0847207fdc31f0253705581e03e43b5623140b81b5788ab27a9b607435c29e998d62d7041c02aa5497b00c01461e55d5526400035cc05631b99585c07c74357703c6536ee955b7fc282ec27b997ee3cfc7db376305581e033e96d0303c74a5f280436b54c6cb65c305ca1432bce3657a886fa885600c0147c9ac605151e00005581e037248f8cba499143afad86bc4846e956fc50ef032d10256e551b3342c900c0346a2c1a8265fb805581e03448abfbdc1f8a978d1266c4e652cfe22c375ac38e7fec717c83e4464700c03472cde779ad41d6c036657955b7ec60ccd679d744e3007ebed64a1c193b1f5e6764e5fd5098f5621a4039be7f2f51b6926d91717387c7d931554000322f401f33bae238c59d16d1bc25005581e0304099b4cfbfbef7c9241d66211f3db31de111d250cb83214371a03052007011bffffffffffffffff02197f550306084be24dad54cc280b3bf8ec4aaabe90ef39d4a1d3de01361e7978f2333e6203d070f1709a1cee0cb0f2dc904d4a97ba0bb0899e7c44573daf0c4481dd0acdef037256332e427d6fbea337f43cf2cdfff5aff4243af95cea9f189e5215b4da468003a8eba973b3479f7730e2da45137f7025dabe1729a91367de311f71e2a554b9d2032388595cefb05ecc623b4644216fa13da46bf66e0af30c3b6e61e980e47f2f4103a78c06eacefde35ab475592d485471fd7c9e2ed061a66683db9e0f938c6eeea103943cf313af4d005afba941eaf012b10bfeba6c27bab6a5b500e7a463beb4ce8603cba2737f18889d6a5f490126166eccf6eeedf56294b6983e211caddd1e958bde03e70c0538d263e7153e98080dd8651340c6a16c61ccac8e72faf62b3ce0035e6c032c7f02e20d33992e4a756861c214ea04fd1fa5b7d7b77054043d909012ce7ca6033ddebcaaabe1a9f3fc9f1433bd43c275272753ecffc73f4dc4d147106d060bac03501228901ee23e51b629d809fe86ca91b857ebc264348fa6711d52ec799e49790380856eaf2c16d41b7c5851c8b8be074e2796ef9fc5a51af35abf82e7064d8ce70219ffff0373457bb1c2d5a37570f05f98d0da6ab88337ebb1dc5e69d8905424c0d25f3ff5035ceaa6bbae7d847a6b71ed0fd91751f23a221217cae0cca560eca0ed46641fe203baefa85ed25f86ec38ffeb1dce60e649268ec9253f9ea2e937177cac4a32c02103deb8799b4ebd27039932274a35b805633be4c4f9e316424c0da29cfeee1413500319e279bdc8e991271380be21083446fef85aaae12b0ee658bd0a4472344497c80379866774e2f225b8895e3de8a034c7cda76505fe5a0bbf4cee28bcf03a50889103f207db476fd76b340723f6806bf05778064c1b8c03ea762913042a6deaa83bf00333ab1293f95b00e0f5ae9eb29d2b2914f25a9e927ff18e077fabb6ed05166bc00219ffff030f435593b37c6e7e90456965f90baccca95ec22f18726dba77f969586563319a0374f3bf4b37dfba97d3bb836784a582d5387f1825e37bae15cef044e4a400ee10034224592b2898cf17dc3412815aa5d8306aa68fd1897203f32a00fde6614829db03b141e7b53041cedc0726c3eb62ccf7ef8594064490e280a085412683871b3de0039ad73dd089132dd4797a0dbd3bd6fe1b098c46f06c517ef1e3797ef8c51dd21003c0ccc062063d494691863a58cffb0498c3ecf32b97fe6bafbfa4f91a3aadbd3403ca29993c9ab4769f55b1668e25e86366c58315e90c52fbfbbdaeb966f0d8213a035444b46af6e3c94f584c4dc0c7cee1e3e9750071fa4f648b452633be27cee3d103dd0ef771e03aa7643e5ebc78ad7ba2ba6e3029f1f54503f575b2c1db3a50484e032fb5287c04e5b0440901877a095a4a433cb704c875ab4faf5d92b890f83a368d0342182d0d0b8b8f6888219bb5441e71ed5247061f247b3e5beb05256fd437446703057fea1a0b7e2ad1b0dac40108d98219a77820023ae54f6aa1ccd599dbbfaf90030bcd00ac7b07c9a993662985753fd20a5ad28aac1cad7cafef8550f76d905bf003fdc6ae80d23be595b425ec6bf90d701c20aa537c992ae517519c1c9132cd35b00219ffff0300b3538138548d8e7cdfe3ec6a0649346cab821a2c12759a2d5c735ca1e2476b0397f9be41801a5e5cfb6d5aa5fdffc062a433b8403c000683a3eff412dceb69d303ae5583703a0d55910f9e00556ed1e99f16b07e48d8063abec2fc81036899731f03468233cd70fdd2f93ca606aacf821aa5b529aa0b97ad5fe3e01834e23fd2f26f0380dbd6361c810ebf3dd1e1d37a2708bacdbfa655f6f65184e4c77d428d18dc65030fa56fdff3c568c91864f230f49dcd3071208ac2c6f2e9f436777e5f8a3600060394e5b49d3a8c2f88390491996babb83300f840ef28c6dca64d89405e3a39151d03a8be77041b3cc39fd155bb8c1634cbc4f642485cc1bf74edd32f8097e2b9d1d00219ffff038ee69e0c947fa4b09f8d38dde182267b4c4a16ea0242c041369619c16b2f69500392065172c22a81711d3803081e2c66a408e0727400ad2d83ef13c570633d5fea03ec289b0aa52aff14cdb4d22bb62e330c7e4ca2aa611ebae50902c190e9d0c99703b5288a3d3514fb46b592e754af10a92ec8a7f724ce0c27d8406956ac2b8f5b8b032f969988b3bb0cc7bbc443189f47d5900025e8f77ac5500ca95baf449e774c7103c4154482e9e26c9bc32112b211d4717775216f694bfddfc8b269ab56a46205d80219ffff03b86aaf4643a9522fbbae67b172edc7c77393325dc9c31c9a7abd8d3994c847c20389ee3ccc7222da174ba639ecac039602c3e717952af7296b84ed11b7e6f2309e037361d147efae615395c158f88bca05f3945005fc43a8196e1bbc97e710e13cd10342525c1620a81a4b104fc85e3694cb32589489ce2ee5b01cd9e6ab14a5cebace0343e3b06cddcce5e0f06baed99ecd0a20775a5ff0e74cc5a76fc9c61010739764038b6c262adfe371830f62289777185cf8f52217c9f95282c67923a377eaaf86ed035dda29994853c06889e9e46917a2a0f79400940167b9aef146ab347b55d664e703559ca936f787bfb77440659de1c59ad30eeb28eebc23817b843ae74f761b283e036bb1e58c1e30f46e3e5a17c627b36840ce672a1b4576340c39a5ab5614686d62036d4da0172d96c64cf89c5e12666fff5bae46b070b11ff34d32f8cd1e16c31de903b51b58d1619a46dcfc5d4137a3842bbb299e2fc846ce6f87bbb6b89c2b0b9bdf03d913f2df7f405954f7f3ddec0f6b6fb418ebc3eb0748d9195474e98518ae658a034f042a8a0a48b51cab19b6ff5b512e2e54ff0bdfb317f28c999791cb204411d203e5d907601a73120bae4431e4d05d07deb1eb429c219bd2219dcb26e71fd9affe03cb44b7d70efc4351355d73d14d0022521f1b259212653ad83e8baa6cec3c23d3031dc993b12dc23a0d67244bf463405d99e8000baa1fbd040708ceeebc4fdbad8203d0d7e8ea93789f0857b17f2698c99009e8d53b35eaa1e292ffc9714d45adc00d0395d70f0441aafcca4c87ba0a8e565313ea2d2b242fb3cad8d04d6fb8483fadbf0355534b75d3c88e148d52a6870f57d19ba0ac801caa76e08476b90b48d7245a4003baa59f2afa6444c81244b86b7c9dd17b6edca4ac623a93762aa2db74658760e6035b375faf8e6b683046c729754d73b5625199502802051d1b437d400cdcb0cf3603600009c54247532fa59301cf9015172f85b4dc83cc238f70df51f73262af9457039fa254060036f7f90b710bc3b17f2d866d5db4c06b175506c911246f6d0b50f5036d5b2af4df1e2f292bf9b5cb4e13e1ceb528bcd8ac00fdb041d777a456ae4d1b03e7f4e78e600c3126f4691665f1a867963f504bf7e5f272f7e269369d693885370390d6c43e3dede80b4c6759b42c5d330666f3fd1146f164889637c446b1673469038dd25b7adccd1a9cc378ec8a4c419b593e30f6c853535e3f3c3a7675d9f5948a03b6c688039c4174b06ad78c703fba69d3145fde491a9ea057e0ca4689ce6f083b03b5591bb5ba5bd4c45ac3827151cc5af7614e1bfed7809196971af8362c19490403c07c7fc3f92e6ebff32d0fce3961aefd7ee2e0c5090158ee8578d094fdc5b2e203e91b66637cde3244ee7a4f3c0c6f2d41e5d3d51f2fb161fde3b3e46a7be5d2e403ca6f9f545f835eb201a5cb3a64e0c6a3d382ec7bf5bd18d1ee4128de0d5c8fb303d2ff40753b8f0eec2e458c6c092129ecdf4da77d7b95645ca1ef6a47af7135db0342225c8b5558e35ea88dec62a89b5dddca727ca654cd826c19ea4bacc6fbeb6703b0de12445e9e9b542fa6214e604fc40e069fb71044af40d50d4b741d3a3791eb037d577156ee5867430b360d6a12c062c7557e0fe2cfdc2c23c24675676109820603e4abd4b3b402bf6ca99131af823b1f1e3dc564cd30eb6b83aeb4e6295678639c033c1f38bb537c6eb904d7f5068a749092053dfb9fd8445dd54829d6f8c96024650380fecf187fecb501dd15f7452fb9a5b4030af29bbb400caab89d9fd1f6b32d0603bdedc66f85c076c34ddaa82d7f153bf1940a7a05e35f70ee5078634ff0d9529f038c72a5acd831a0cdfd5fa323c3d53bd217dd034aa9adea20652ed7fd52458f230337e3badcb7453ce9eda24b15ef374242c727263e5f5d002190cd5723f3fa6c180380ffb85a7a5817f873341fb95fadb78e688522800706a26f5721c9cc29cd9a2005581e03eb820fd1bffc460d328d2689d7ffe13c4443877bebf25bc3502cd345900c02472427ac4344f80003a31f886c62f676187a889179625c86a313cef7b2e41693325ff5e023fba049f203508d78823e3c33ea99a6bf0627dce396125c96e0f94f2752a9ff05880c38b1dc03e886b0f9abe462c549e7b057256e86d99e81713aa80dcddbafc8f00a0c3fb71605581e0371534472d82ce1ddcefa8a9a081057fa05952073b437c3327c830078f00402031f8b67be329f6419c9282095843235301b6b3475e42bc9e3262b646aba8072060605581e03f53b77d7a78435e2976275d2001631a331bf18d7cd453410c7e13373f007011bffffffffffffffff031d93f60f105899172f7255c030301c3af4564edd4a48577dbdc448aec7ddb0ac0605581e03ae96e94082f9c665a9a9b7f6b303fa097b51f1de5b42723c5fb44dad7007011bffffffffffffffff05581e0339df67ea70629138640dd9da3fc27fd679261a5ed2042474aa5feaa5400c084712cd0bc426c00005581e03cbf8b6bbea8c53f00e0fb58e1ca24db29869fdfa1a0b1ca084233002100c02471b5fd6500abfbf021973b80219ffff03e7428ac36fde822f7b83a928647fe466714ccf84913a6c5aaab7ac82d2b59c7b03d5f0df5e6a2783e918a037a9ee7fa2685115ba141d07037d7b5d46e2054dd5e7039f79a9182ba3b1d9aae33023b9070a638797d05e7f4a44729aa17849d5223a24035fdcd59a931ec1e91064d844c649073f657e4203d36eacb2351521e9e4954ac603af08685cc91bca4266afab1357e6e9f2f219f11bdd5e1261f3d98327009541ab03f8593ca6ef3232bf440abe37ff28edeba31191f213e5d4b2c3b5e1439decbc4b037730aa436fa2aacac76aec54eb6182c0ca79133e33d8131d4554eefe4d75ef1403916342879007e01d97b956f624ce44c84248f89bab906ad9c5b606db31c8588a0372587fa7fb363fd94c739e3143d15247587726f61c87b0d21223c25021bba3ed039481046e71013bc6b2a66cd833a256a6b6463c9fe29691a062792221433402d80356ec3acc0a875b7d4d1c3d8fad6fd9368ea37b473ec6f1e19b78bfe9688e599f0362eca503aebc0ffd7ebf4011dd3b5a9c0d801d14f9ffccdc1d19bfcfca7200c8039a28638fa0c05db0d14a30bc9ad3c7098402739c7e17b7da6b480c83e70b3734030aaa978382ea98c6ad771b344bb123f56ee7d5411df29e368eb8c0b4f38423d103059c72e2ba055b1657fd968572d1f163a911c55b7e10b7098e5394e265cbd79a0219ffff03edc2850f10888801ac80c00884047f5f1f9544044abfa9ab59823ad741a2400403f51b244fbd3f59b9a76bb6bd4e26ce99a5fb4a0356949d052bf8e1a61212e8c8035085eab9c1ea2fd2a560bb213b6d65267407f6db09f61e2dbaf4e4a7008279ee03540d382e5593c6ae6206d3279c3eadb38dca924833afdc4ca438a9937b4c27520337f218ee8dd919d2e018d8c42eb15735b7d2bbe0a74839a890c46788319fbcfd033ac886856797396af4c01108aa53ea9372d271d2b9acbc1330f74a8677e4c2030219ffff032299a13f697369a2b8c8cd261698d2c8787129b582643aa4a927107a7660802803bc910df7c9217db39175a9572de2d6e7b40223794d53ba7c243144bc16d2847a034c997b100bd7d9daeb847ef6a709d188e83d39df005cb3680a1b86ff656d718e035f53bbfea1cbd32e1cb555de9e02c8670a100a58dc33bd879f6ae31c83623c530379a28106c797704a0effe2026865167c4da61f6f36350cecacdbb4a552d223e203e92c82c1edb4bf407b8d4c88e76983f82c06025827a8448d940953d3e344ab9803415a787536042dcce97a33582d622b3c234fc3830a69c4c4a69f6cb5b747ffe303204e8dca3471264a5d4a52f7fc903b258b615b152237ea048a368e60801c8ee803379d91c811e24844e170e2a6b7eeb60f0bc974dd7770e1658ec9093fb561912a03478c6781a8b905bd91ba3277ad73fd8f441063ad8b4ceb471630d8f3ed66721303031a7750b7920766c5a83f2f2536cebac67ed4ac864e67e19b983b125711b4530219ffff037bf29d067ad70cfe53cfaca684a37229afe02b269a966eed4ed1468e28150b7403493e70d29d51289a7d856c5f354a06e786c281d154b3400e808102badc2388850302ff93a3d24cbb140307b0eef2cd8f54c657b10eafb610840855e336ff7d506603f4fe654f6a1f9d54fa6ded013deceb6bd263f60aa743472d43d0847671421b6603b79fdfee4d00a18b9b2bf952e6e3bf6e8c58143ff6bd625b85910f82c989e9a0037d6bab9c0422fcb453d57c21d8d125f8111f44e0e77e5b85292d811e9b1b49bd0308f33ccd920808d75225fdcc533b87d62202c3c57695853bb328da416ccef01303564a099ace8ddd129f8fa6ffb1424cf467b5c8d3e42ff0a86006db8c76ebf2fc0219ffff039f6c2732d7b95617cb8197e7e4002cc002c64b144b5845e9daecc07fd3339b5003bd2bcf581ad903637e4b18193b7f9be573ac1cc2937acab93bf51d6e988a42e50386494bbfb0aa70413b277552286c6f29bdefcd7272de4e0157a9b0941dfae682035b5b82d8a2aab2799f37814d9c86295de5931fcfcfdd704f8aec87c1a138b7950306f1364261d9ebf275893b908531ea5b3a477fab09954a136e867b35f1d2f0d303a488dc121ff72c6a93a87347962f56baa5d7ca73fe9d843b61bea8ad6abac63a033743dbd1d0c596f2a960a19a9828f1804b0f7b7bb2ea5e0cde398adb8ea475a603338a53de165699f747dbca896213f929be1829790e8375571f32bea3b9dcf80b037a23d8955e02626c2d9fd140ff89ecb66065fa37307d13a2e091a88d50be0da503fce5604a841794dd825a8230ac71ac0b39e20d50e06a76c5e01054fe236e7b9c039c401fe781b9c7c3a3c5404c3c4534e7efbf6814bf59ffbade4f69191cb801da033ddbe85c6065e70c8607c2b56a55c611d921fc7254fa6c20e3b0cd1d34e3e6f003cd236c04aae3f2c1d68481eb9bc358740d4bafb2ae08006ccfcd011d6afed38f031bbb02dd05d10628864a88112243e6894c305e535f73e727a4d52f403e143ca103819e66518a3856d1d846aa1d5dc35dc477febcf8bc0907ceecbf8cf79aa27fae03d2cf80a073783fae139933f1118b3464f00a14500d42dde47448e74100c6e77203de3c2a255b9b8bf74ee7b19feea80661889633fd0276b9628aec54d3d205b5ea03a7e6f134ee27e789afd55d643954b0eb2eebe8c7a371156db10b438eea837175039491a0c87ccc44b8836fab4b9759c5ccbf54c64f9a79aaa5b17d8c998631aa59036c9a03b3ecf60fef21257cdf8c1e29218b5803c7af18ed5144c1d117df3472f203933976cd2b0d1b8aa5f90a0f05897ea5cfef9719e26b44c045a45ba9c31f008a031d040db431c1fb7f7f1d03948d9460864f252e74802469844850a06bcbb9427e034cca4db733293a24d9ac26f272ba20d508028a6bd06f11de91ef40863e7e69b70303f8de524306c156a570cc25d8338c395c1d3f250c6f99895dcc60cdd2f682e3035cadbcd3d4e5e0653750a7b95e0b23a8d99528089bad926e1eefd78e42f6f5f3035e38338aecc7ac3cde429b7e3ca376145c5f47b227675c83aeddfa37730e7bbe0396af2dd1fcea069b5d7ec3c83208498da143d91ddca8b76a026484ed0a6c675f03a00b51ba6358fe3421a49355bce187b96bc2ee92bb024717c9308964ba93b1d60353f300e70b2a63b7c0d61d497bde74e0fd2dd87ba270bb896db24248e9f18752032e32d8311e84f7669859ab7142d248057171786d538b72b3b224f99390f5487303d3586623ba49d4a46a0d22a44c5d21975812461e0b98198bf602f91fc600bd1703ffe1b3a1a75a68ea426847a428f6abc359c7fc3f2254410c0b18bfdfdb2df636031b290c8af2c6b40f4413944c55645e780c6bd37db2397a369694b03519eb1b5f0374470a5751c368eff94a85f83d58ca0deb060f16bbcc115cd0f3bc5ca1c1c79103d0117d2b9071d72802a9a798fc10d91517b8e153afd593a7766ee3c6fe5a50aa038a461051b15d2b75df6c9895928735cc2614bad3c8fa997cea767b7f245491da031147cc7e1da5fc3970ff386d6e178e39e2e3f256ed9c5234312439ccc09bb7770381a1aa551415e356b298808eff24d7cc13f0e4a4e042531b704d0978dd348d9e033d8d47d0b3ab8f53caa5462ec26e18ffd435793ce80d454d3a0de3a66b8f4dd3037cc67dd0f9e0b3c1dec99b0a939a542f806924dd609dc79b15e879e374c2ddd603db1edd88da31b9173b3a01a4bcb70736f1fb7d3d7c4ff994859c9853af8d13ad03368a3deceddbf642196ed53eccf27173a264a7676dd248d202620423db656dba03dcaddf110217ee48bfb8eeff146af24219a51ac93ca67f522482e2a3564b460103304bf37f15689fcfc3757c0cb8a9c73e888edf17c9ae9b058175ae200c1a49ae0351b04acdc59d6d2676cb376513e6ef4e0e457fb7667841912288d0e20a2a80b303cf603aa4de6a946d150a191044c72b182176fb4021c6b2d18a383855a8f0234e031b5526d099906496a3a33d60306caefad770cd03a0881fe26d7f1a0de66b43ac035e59a8277f34b835258b96b4508bec0ef3922515e4142f0490770b3b2175569f03293dce157508c58129da9fdebc65200c1c1d983a8107e0f00d93b0cfe25af3e005581e03e61bc331fa2bcfdfbcbaaffe43953dd29f5dae150f901483658d263be00c044707b05cbe758c7d05581e03e98f02ec287a7bc81664c3bd3547c9c43fc30dd780deb035cc572ed0200c044683c5a2e4fd4005581e0301b4c5ac518015a0bce436357c6ffae80bb8291afc971ebe35544f24400c024501aa2450d005581e03fe83da1ccaef9d9bd78ce53543b6368d6df3947d410bf2d34eb594c300040205581e03ec48afe9bed2ccb5532d8a32fc0cbb2e1ba61c7556de5f51e397c4be200c01463d1ec5ffb1f0032df39c0062882ba634fb24c89e7f9871ecef10a6e6a6e79a336f6ed463d5c94203576d247b864a9c9c193245be5262a86aceeb51240a250d7b4354c293d83a678d05581e0397fc5d38badeb2417fc4af69d36e4965c61f33bb84f646b7d58a9da68007011bffffffffffffffff033fb0fa6f5661fde6378c4db73cf7f1243b922e4b55a3435735c010e477f1c24405581e037a436184a5fc4ce62ad4b2daaf8a45e35f2947e33aeb11416da640405004060219e48e03026455994a7764223a128fa757f29d61c41ac8e28bbab1f879c66e232fddb035036c4372246d91297c5eca3d8d1d450153f9522df23de517957182e29d8416b60c039c41360797c1aa7097a0a9af04c1f817bb5c454d0f772e8ebe2fd352ca7e0d8003ba5c25d3ffc47ad414f2443245ed620a381ce9d9f0d1ee70505a1db59120de1403c0b160d239ce0c71812917d0798c6964edb234491c2f32eb7574c8d7a16270d1034424e96e0a1731300a2559039dea0424a1e764dd8d7d15d03aeaad0ad4f3c4510219ffff036d14a8da010d275acfb59254cdcb9eae8cf5fe7b6ab4a71a2a36194c74b9a3bc03731ac71e9d419e6d1673e09527d61c4f7b9d634dec4cf33946a8ea03f67fa57e03a916837a533d8f341b1bb7fb0e55bcc6b3331f628dde4d08d5ac4d72b8da516703c20aaaece2b73a3a9adc8e7a8806aca1e659dcab0526d1437690766ff0b4452d03d21f43153c769cbbc6c78b5dcf8b9a5d5f139ab0d0f24fd215618da92a34226a03d152c22b71f6c3039c0923a13d58ba41db780be6dbee23526315a0a7cf0431f103c90bb142fa9e97c9d16aab891708825684b56324f90029d149c20ad2d236a30703401ae904b5b28a574e99197b56de5407bb0eef555f36f65acfe9f1819fa6a2dd03966249ae6fb9ba9de1c890a1de3ecf7da07fa01d7602346d1d2a3b0f829cbb750379694c8599c0f3eb1711dfed98e2e4ff393e83f1c8132f830c1298d0a76c182603355149d946dfa2ad5f816899256dbb60ca00eecff995689c2bbd7370215729a80219ffff03fa4bc73fd4b3e5ef71f2079c8c7d0367d6c5e067eaed4b34656b1926863401bc03aef7db107436b3c50134ad9bdba4ab448c0b3cf02a7e2b8c0c88fbdb4b0c2cb50219ffff035193acd8f798b1956536dcf7fe595d15a5dd7454a103659708015d2297bdbcef03c5619d369433bf9fcfb86dbc288cde781cab61a13890d23d8e35269f21df280603173e6adb834c681b932bab9925c8017b62ee314a1a96d5785219e76ed6e6fff903e34b9c0599f8c2ef3b96a881ffdcaec6e123973792fd3b5afa5ef14a69a289880219ffff036d601f7967997e14f0b8ddec3cd67d8c4758d5849ca7356bce8860758ee9c848036b190a0ac12310f42571c2af0c442bac657e635a7e06b05aa0139febf8aef0a003c8825581763941270cb3e17f04c73fd4484788da4848a24a6b4ac5c87f1e31840219ffff0219ffff" - } +[ + { + "block_trace": { + "trie_pre_images": { + "combined": { + "compact": "0x0103e13c370f7ce6f9de81dd4068775d7c39d1e19051063dea7b4f0dc570ab06868103940aa0f44732cfe96e03cc53d65cc93839531689de2370a6bc12eb515a75f6ea03cce25a8e8a0b65fddd641e8856e8baec7cd1a012b7470e92aea3d4f6fd02c1c80386d98f1b6d13f0446b302efc1197100dc2d2d10c9e7db46ec2a34d55b2f0bc9f0345a634828040159ea3390d453145c5e97f3406575308f3803fc63944db067cbf03cb91ecd916f16b6227a60215cab43c4b9a409b19cb9af242375517af5841ac5d0329a14ef57d4d2282d4f7479ea6d37f728b45af8ac42a621a953369de0b54535503c4c441ce0b6d427b5577cd15b9cd890ff95d1434d101165be1623b9cd1ef67b6035ffdb8ef07117acdf909af168d381bf8e503dba36547fe5895671e9d495add1c03324e1dcc50950c11240379740d5b383f879719bb1d477d04592d65471d973e8203f355ecc89a4b76dfdd7fa0f0318293854c502c03a74c0c4ce388fcd79835e0bd03bb455a53b6153bf3fb7e0fc6db20d7ef3661942e9e957af3b9120f91f755984103be0773cd56d7c9df1c8062a9c35b731b1359b4b9ef8c31a5c74c7286d96fcac103f7dde717fe02b995df87659a9cf25cc95f994360e2b8cba31db4183c14c9670203c669e29de38188ac1e9b8662b0d995e31e500883d08affadd4eaf71cb7ae43b603dbe9990a2e3a1b78a7e86924142e73d32e6a5fe8ff15f9d923df57f5f5667c02036a42738b24621de70cf0a5975e4e0de90c279602ed12d99c46e9951927348d1f03476ce5c4306a2f9875011e1b52bfad9af7f9eaa53a0c09725b641957f6e5abd1033a6eee3a707b54e089427a7df5f4d780cc9bf727b8527a2670b3e558fc580ebd037c900a244c50a273971a28d09b3e5448a2d3b92248efb447d5e914c83885d94c03cbb3c52e38138f069c39c31753b3a1e333713637c57dc2f38dade06d65833c4e032e9e786d65c8c00c3053a66aafa6d738b6029bd9b44ca911fadbb1b22bbccd3803f23a75947392a97153c9fabd3ebe5d109892d7ae8a4d3b64458d60fb5b0cdef0034c0924eddf164fd85e99748a48284ca73c4b2dc83edb9d3072551b3a6be0f94703bcf4e068ce6001b29bd880451c3388ef1c144cd79c727000046ef06b8b6beaa403b615536da0f1386f5dd58645a0955875bf7e4c00c8bf8397054268b30a5ca536038f67227b47f06ade1eb106d7b50bd823a327fc6d04556d011b98e4e695a6578e0328a17cd0c678af3871f0a5d3dfe41ff24967fbb7f11726dbf53707b5c27a5961036ce3286ec2d725cfeb234d4a29386ac1b057ea5109e381b59f5816430e82386c03a2d833f5221678f65bb919bab928e1ac2a21fb16c768c802385743c1f20f33bd0394ef837d0a9420521c9b61374d3433c534a22365b1ef1d34c305b1d4d508b17803245d8e881b569e0f2859d441687596d69a1f13172b721b798abdaa13cd61acf10331b17ef9b060f53595553fba5298848848045635c1ddd4867fb8834193531efb03b254caa5808fc83395b676f33b88eb741b88fbd627dcfbe735a4924fb3a7ef47032c53e4633f67dd8f1cd3b97857e2fa1888a08113bd4ab0ddd9f3f0667b75f31d03ebfe5a0154be1c4918681bb0b84185583e2381f1c034dbfeed740abe5a18a73e03e0414af533edb23b377e58da622436a7e1bc72da8005d38e7403e9c796fc8d7d0354fdd1dcf7c140089c99e10173a00bde1620974e76caa85b89c61386854d2e1e03a4fe5ae7bb248ad34f6d6c3cc546f3945bcabb9ea6832e5b2c126fb2948d37b0038436e7414d7bd51873cf6d66cd7100548bc241391940c4596cb8fd8318c9eb43033ef1123618d733594d9bde1b472f2695835b273426ef0e82d2901eced8db7402036499aa00f5cc368850094bfc120b9b888f16d1b2882fd29bae671a5c415cb83c03d27584f834991d48dd9d39eaf146fd21299f67af62a7f0f8c56f316b58c812f503c22ffb33a73ace056ec28dccf8f19920c8075a47151913e13bb76de334454350035bef61b2be3a91a5d66d92b259cb46bbe3a8a5866efac22f59f73f70174791b503c892127d3f6cceb7c41af2f17aa67450342f091879adb9acf3a7b5a8c1035ddd03556d3ec12e5343a2ef72db2e7ef381104279b2476ce4ae4a56b660b50347595203835ea527241d3ff19f15c1d172c75245fc94e1e2680fe5d2551b6225417ecdbb03fffa2540a1573b228956fa86248745aed31ae6e2c983714f32fd9dd7fc58c36a05581e0329328c87be9836183768908f30171daf16714c1f39a360b617bd23df400c0a4629546746ae0805581e03934cc196d443b1d2c5588f9fe55fa70f673923ac0eef128d9203835d500c0147c7a8357a0fa80005581e038bc60869ca403f3d41ddf8575cfa5be7785783dfb7dccc395b1ad999b00c01470d35cd2acec40005581e03d4abd7a5e810b20841e6aaf7fdba78949602e371cc5ff9aac8f74876200c054702c0246afc0c000458613373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff0155000358c5239b1dd310f0537a237bc27563369523c442d801ec8818db3671c74674540365826e2e7ab17befd18111567901f4d1c040051467d927e308ce4b248822a0cb03b1c225aa33368624bda2174d75e18cf62636a5b76c4c6e1b2e418d4f5b2a355f03f9f0c35958ba855fe3b67c2d3e281098a811faf015ff970c2ac1ed7519b7a9f90340d8abd4aea2178e472a6fb5d9a54ab7d9da7b4cec41de15657ae7d7ee47ee9203b4b2017ac478ec2fecab17810a12138dd142aed069ddb547bc6ca75f30d6edbe0306ea5daf16f46213f499aabb9937cce13f5fef58bb32f6e0cb3e9a06a0b51e5e035f11d8c8b2a04750588c9cb0a75e46b7e6e954dd62adfd624acf8da2643082d903a0eed321da78a0ebdd5fe9921d733518413a2cb187ca6c1105f7abd1cb2fbb1b0311b7c5e1e609f177f216cde5180864e5b646e33cccdacb581e3f588664f2aa29037d0990dcadece1c27990f6006dfb1b06731a2e38f30a794da8bad6323491555b03fe92a1e51e25e90d509a1d38bc6f2a9fe43e4f72047a2a24b870c8d30fc64b6703bcde60f65dd3d2ca3a2f2f4b0fea9276db48ca7062d6b0b6aaa3a0510d812fc003df6748c404401faeb51fffb775298fa91f0dd2b737b0f8595ddd8053103833c50367ba887e07b40051afda724bac2d9295be9135f1fabf12fcb95ef8762bbc5e54005820035b0fcf3bd800db1425c3b5cea82894f4bcd6c6e3f3681233ecaa3a21a22a3044663cc98f03a6b7d063b82dec0e83c94ca4a3eb6519dad637b47c2321d17ec61548a784c95703fbf5999fcabba0e2ed169e657630905ddaa06e1ff8ded70eec12494da396b04f039ebc1b67747b6a172ee99df6e8debb1b98d1bb2af2fd4d7d9233c6f86fb8bb9a03262f082f2f808c68b5102bd0ca743333881bcdf56c5b0caf594c71733ed0c34700582003cddb82bd7d6f65fe1dc37f3f335825dafeac204521b498c3035fca9d24671044663d7ae3034ccdf84f270e9fb07171b769d1737ca3cb47be3d33be2cd32aab896647a32da0031f8901f34af3b4a8bac1e2b5d52650022a64650558a0c04c5fb4599c094dd08f03f52e9a5bf4207d9cd90239f7199782d58a55fceb3895fa2cb4cc9542d2a5872303e3af39c59d84c6dd4bbb43417edf1e939070570d233bb5a1b7198c4d67b1567100581f02b50381a466ad9b3f5753ae9d99dc1961955a9450f39a54fe5ed20f23703944663cfcbf00581f02d7283d573d576507b2896b999a1774e22aadc14d202294c19a0f513a12fb44663ca90700581f022d34ba1eaa86355c866834b1f968ae22db024991e5f42a9a675196c9459d44663de78b02198410035714c53a00c63f7abf88010b7d8641a6f7c834c8c8b6ab07d1304165dd133e2603fb951dd6719d0846becbb4d55276d92a7a77f6687eba589ff57bdfdb799fe4ce0328f4625c2a4b7929cbf0ea4f0b0e3459896a55de82446c8997a5856856abffd90391340802d5194304e8a2f4323c84da7647cf985a3c6d2a1ef795dbd8a53817800219bfff03576e9c67f4913b6dec689d445a1d0cd79a90fb1c9a2f0c87a2ba84d25171980603d924cd2dd4d5362c29bcbb0fc4f61e17558e556aea838c8d09ab96901ba11fe3033517c66a20bd6abd4b1ee2e5cd45298563b00fd979ad371af28dfe95b868322a033e0ce59b58426d4eb6806b518e0a18ab4d6ebeda65951a616eb9c9c917b983520219ffff03387f24a9b1c6be19fad5f890ca5c502479f798fa7a51ebdf492ec7752bb784ba03244183a300b82435242d6e0b450a90dd10e49846e00e2cda1481f2cd6893f04b03356f09c737f039614e52e2e0c37fb7a70313ace29b2154d9114db788f0ae541a03ad4ee9196fcc075e9a4dc9fd2bb8c75338dab17003f968d73480b3db389bf9d7031d739c09b9667fbd3f6ab1ef093a08e2c5366e1d6acda970be8d1c3fddedc2a2031afcc8c217d91826795f263a1f09fe4f6130bbd58deca5fd7c33077375fa1cf5032a8efece59d3d07314f21a48b9d4e15cb7c42c0780b4da74b5713427a941530403f0804f578891545342627171f5a9f2262c76551c8dff1d87e1d4f600e0dba569034e67010819e15c986e4fc147d9d699936155d18e88644fabd15bd556521a9b7203b6fd210aee5e046b5053ad7132b8c705eaeeee963dd7c5efe7209d356667b6e803b5c9b2a4290b6130b89889f84edc7688e2d8893cf6671a82834411fe9bf6f27003ec93db40b8df894e80edcf0202cd39373099967eb1e75f285e6cc998e7b5b26803692dcb502f53043296639d68228f69c17e83663caf8ab3cae97b1674befdb8e103d5c209b220a62d28e6f24c89d7d6a37de20b3fe53afa4e39f71b5759f4d3e4c4032a92f5ace6d6fe31425c6282bbda8e84e2db0345cf5662433266e1bf343a12b403e12845abeacbb0beb485495bef7d65bf834364233fece312a49b576ff3c340bc03e6a66e06863ede15f9f2aa3ade52cec2ca242e3f806c40699a40d9284bd88b94037d6889baaf1cc4d81c4acd0d0e884c685ffb3a2d29cae5b0727b2ecd3e8d8dd2035982174780f06ddfdd84d88987dcbdc69ae1279de27976eb62d2e5abcfa1c18b03e13a3a9a9b2880112b3171f114eed30dcbc533ff7d56980c8898a82d1f4482c7030e65acda5fde29d1cc76bbd3ffc17d8acbbde66d3e68b6a5d9dabe5204525aa103c5a998297fe5c2766bf6dcaa34f57328a1961bbb6140e34f22155c4904bcdcb203f53af6a0b865c4f515acc6d3c93000e2cddc6f8e8d961c2672a7629d1907994303a7385e81588f6c99b53022f433eb8c00efc96fa67eb6331327cac4b1a07d7585037f98a226ecdb56c0d8651302d8b22d2acff8bc0eecd3e3213753028839c0d92903cf753d039db5e738d1ee967356555d047215a4bb82aab79373c359ff70a4478b0379a542cab81cfd9d454470df1e42547fa517c5d3120e5bd3730d98934b64e62603a05dfba906e040db50a0afa79a425201f74146354d88c2754c5821eb719b5190037b2a32ea2c5f26a8552a7872f3ce840aa447e7d9c0efb0b03c99d131161b810903f7b2d22dd98c0f407dc59ac30c13260cec6e6565f54b9d9b09c4bf1bff9829e50371a35ec266c88aed1b2897e3f36a14cbb329816629742399d38ccf05c541a55700582003c8baf22843559d0eb809346dcfbcc9cae4248ce96c61ee9416d0767869af1044663d262f0395451063870cbebd1a1c414c042a67a269e123a33eefbe12795ca4533cbee4210377696199292b63a284658963a209f97c039eabfad945fd77a3e3d3a2431baf2f03c62ede3a485a67f19ceee383b691bd1579d726b72f36bd25966b245d2658c99f0362f50e33577871564dd39157ff97bca77d58296e10eaf771487a741d7c032be10364f74730c91f576090ca0ba7b1e956e4003c70aa7dd5bfc978ce3110ff013e5b00581f0238787dd0e1f5d8a1615fa968dea23acfd3d692e6fc565b123f7caf145eff5820fd7d812e8f33936363ce5cc165cab273cc02af6aee8da3d42370f4d343c6f1fd00581f031906aedc23fbbf5f6acc171555cde2fc54aafcf7c2b796b6c9407434c47058201dd3ed11c47ea3f75e3c5ca68e5ab9e0bbb7ecda2318917c262c27a9af24af1900581f03c2e6f82dfc83b58e2df5c82f2a4b3a3d5a9f68fbfa24b96adf46c00deeb044663cb0330206021928000219ffff0219ffff03db912c435e75072736adad652ecfc4673017ec25347326549992227d294d856b0309e3878fa9a66b2f5cc86044daab843416ab5977bcf6dc06b760060f09ec7ca2037c1fe9f58ca2408965a47d402563a15f2fcba83a4a6eb0df1b030da50ba63a4b0219ffff05581e03a92c6bc4c13a5ec45527f0c18ea8932588728769ec7aecfe6d9f32e4200701186103efc4a95eba2b0e8ca1e7050522d539fcaee456a9baaed13b74846ce6e9f5284f05581e0387d430445038d44dfe5f67a6a29f0e61137f74004f19eb39df5f6507100c134622a41c687260035a6395100cee14b8619641123268781a56f8d9fad4ec4d364c15d99ab81fd8650219d595035d3b51473708235f94b7786ec3d9e1141cffde44d1b3c2f8f50735bc89406bdc0219ffff03bb6dce5781ee1b12b6667ebff1c6a7e00b27f644760beec12fb305c5eca6748703c2659bef399996280795da7d7c6cc8380980b8ed448477279fce86cb1439815903e45da9fe37e969afed21a06e65aab4b8219e0be940cf6c2d96a3312dde77c4ba03cbeb42d91012dfa7755211b9ebebc4e6481daa53edeaceb78a26478589a5171c0355e8cbfb54708ecacf62e4d8e82d3ac23e130e81a0a767b06f854fc5a76a803203d82d3c30bfa72b176d2285d259d03f43e6dccdc50cc03dff946f850414c15e6103b84ba827a5ef576ce6db5eeb236b0b05db5fa57d18448dfa5685297e76ae072103494925526b1d70068072e28e02df4d43941cfb627cfba3d4a148a8e857bee15e03cd19d837ba2dea15c076f66e441a92c62e7c353901568a45ba5f71e66e88d278038ba8c6e5027ea75be5cc7cb96300e7201167a07c4c58fb06c272593502d8b9dd0219ffff0301b8e895dbf6e8f0d41d8a44ae0ad8221319b0b3232425ee213ed801d9eb9ddb03c15636c31d015e3f4a306e5ca113823cf9bcf4422ae44ce6f9833e1a4c92a87b03e4b068e19c0ce1a9cde31af1072d04cdbe5f101a86ab598ee61a8ccb7a5160e3035131433214d21d38997d1bd4d2eaf4a69ee15f096d86344b920532b298824fc303152393ebcf209df305d93fcdb3ee0d6c9c28dd5fed398bdaf44f0e32a1253e5b03c28ccc74e893b02e05d6d5447b79d210a80b3799c658e3b2cae91e64f250d52d03b663e80603c7f9bb86ac127aa3726183321274f5675178b609500bd338fe6689034a4d70349a6c431a3edaefc60a1dfa6f6151ad5d23e0028b924ea72676af2798033122fd4a0193f4e18ca6f08a697c0af1c8141e2659da5c6bf0f87f5ed86ed8a70219ffff0372acd27b85056450bebd86a5a917527908636a4c781fa8535f6801d52643cbe60313561846f55baa646d462f32f65378782aeb0a36ec4396cb1dd95ff2e32a73cb0219ffff03ab23c03eb82757b5599c6b1b720f61171157020454f78fb6fba98f50b444103603d21ed651d18455a8a402320838db0c0ee34b4fd81fa20fdd9fe9bc10a3f6756f03f215f60497fcb591efea4098f8e6d1af4260aa34dd0143154ccca2ff7a41371103390f008988bcb2194db38af1ae0c5b450fc67aa63847c3333631236ff160ddca0392da5bcac8b88fa85dd08f6c0a2c54c8049826621e9de17655a5ac61c896422e03361866a4d5b1c4ae521a022b8d0bf3f956cce9f4558293865b4e2e09b679f5fc03c1204c89e187aa54d5bc785652301c858d3b8a3a271e3b29970f5e35b03f03b003e5d334dae613ef68f86ecc885179c64542cbe18c5b4aa3bd929eb6d2bf5d9e430219ffff03001cc050182fb06ae5d5cb21738d6a93d6acec33ffbada6bb24116265a0d418203eec4298676ca64e441552ff83659d2575ad601c6fc53e98344ea7882a0fe1c56039d6b1ff6c754633d01894c26d7ec56ad635490dfb291b08544cfd1b5dcb0cec3039a6d2abc2c326ca7b11f03d687495f40353542ae9b674bb6c59bcc6956657d8b03fb6d16aa3f68791b386410f1c544051aef6b48a87517f2c2f60be6c45290bc0b0364b38a393150f0aeb5df8ae532cc8017202732b532046e192a385a1df530a1db03cbb43ac36287287ae24670a0c4214587495798add9fbd6124993f2c6629d4236035826a6a848d733844dd5987c128e28517f21bc7c06fd3742853a2d94c29cca9203f49b340fc1b72e277463376094dbbb5ab76de329e2984dffaa0324bff1cf9c6b03c61f7518e360642bc12298499dea86e091bad02e3082654be4ab16ade8be481303f3cc663d1119c0e755090ff50e657071c1b7aaf76f5049f8f68efd2fb3e2a76c034f1fc53876be73fe021b3da55b1b841bb1e1d6ca99a8687da7557638ec4021cc03152f541cf3ee990146f63fea1d9b53abaf06a58b00a2ab68fce1c0f5b0c489120387f624a5927e67b0a59632a5850f1c011737bfa8f3a51c937ea14a3988e066b20323c3238b822b325fe11ec12c14e024ddf5710d8802e5c85d1ce7c47fb02a52b303fc2eab2d511cbc973f0716322261116d8b81f804ad73d6d380caf1c42989ecea03067c67cd91a2747c892fd1605d2a38c8b7409376e9684323b7694d359eabf9ff03097bfa2378565be66df31046bbd59bd5d4c2c14299553cc58d7ffb2ecf27699603ddbec2457d43fcf01730e63a612c370b56bb911de1147bd597396fc1a116484e0390b76a69782f11b0cbea81d1398b41e2927e5edb66688c6c728806bce71839d103a1d7ebab554c080cb2fb2cb17667e3058fb3537ed64855620f7305c9c45973e5039c2e37751faff09ddd740b02db8f0ee80d92547b41e50ef9a3d2113bdd2f18be0330ae1b86a3326ef4be28d5c2470d8808df51f32e5399ba760da826f46905959f0362cad7ebe4f2c9f7e283ebe4f1ca1dc9e8e7c8bedc52ae4bde537a19beea1f1d03d51b9c0f3ccf30ef1a3754573521f05d4981b3c7a0eb635ddc81684ab75fdc9b03766ce30501987085efd915e492dc68eb6fb728a13070605c762c2dd8fc65c9e503d2be7794bc7b7ac3eff3e2bf8fca6721b9d7304e19263153d566066109a5fab505581e0329e4cb84257f3a85c60d49d690d86c942f7d8521e57336a24bd99719500846f84ac406100005581d0231e95b8419eb826136a480dd3e995ed8b16c389a83abf73d262522a80c18434a049d41dbc0f641387da905581d021defeb7d022491798adb92c6a0e0bbd3e028c60b710678fcfc65bdc804030219804003f0a45890bea7520a3246b1d46241f5163e20df1f78ed7ae79c9d2c9c8491ce5003c33fc0d0e68fbd9b43795a1d49f372864646e80a64b2ae991aafe78cf1a6b8bc05581e031342fc8a455f0bb4cf1cf5c8d538e0fc58be64fa5515ece1f52ab69a9007011bffffffffffffffff05581e0377c6fb8536ebf253b0a73a57f2d3dd389ca68dd09a55ca7c9402700640040105581e038548cf6f40bc75e6b2075230a9b50dab25ae567bbff331319892bb76200c0847207fdc31f0253705581e03e43b5623140b81b5788ab27a9b607435c29e998d62d7041c02aa5497b00c01461e55d5526400035cc05631b99585c07c74357703c6536ee955b7fc282ec27b997ee3cfc7db376305581e033e96d0303c74a5f280436b54c6cb65c305ca1432bce3657a886fa885600c0147c9ac605151e00005581e037248f8cba499143afad86bc4846e956fc50ef032d10256e551b3342c900c0346a2c1a8265fb805581e03448abfbdc1f8a978d1266c4e652cfe22c375ac38e7fec717c83e4464700c03472cde779ad41d6c036657955b7ec60ccd679d744e3007ebed64a1c193b1f5e6764e5fd5098f5621a4039be7f2f51b6926d91717387c7d931554000322f401f33bae238c59d16d1bc25005581e0304099b4cfbfbef7c9241d66211f3db31de111d250cb83214371a03052007011bffffffffffffffff02197f550306084be24dad54cc280b3bf8ec4aaabe90ef39d4a1d3de01361e7978f2333e6203d070f1709a1cee0cb0f2dc904d4a97ba0bb0899e7c44573daf0c4481dd0acdef037256332e427d6fbea337f43cf2cdfff5aff4243af95cea9f189e5215b4da468003a8eba973b3479f7730e2da45137f7025dabe1729a91367de311f71e2a554b9d2032388595cefb05ecc623b4644216fa13da46bf66e0af30c3b6e61e980e47f2f4103a78c06eacefde35ab475592d485471fd7c9e2ed061a66683db9e0f938c6eeea103943cf313af4d005afba941eaf012b10bfeba6c27bab6a5b500e7a463beb4ce8603cba2737f18889d6a5f490126166eccf6eeedf56294b6983e211caddd1e958bde03e70c0538d263e7153e98080dd8651340c6a16c61ccac8e72faf62b3ce0035e6c032c7f02e20d33992e4a756861c214ea04fd1fa5b7d7b77054043d909012ce7ca6033ddebcaaabe1a9f3fc9f1433bd43c275272753ecffc73f4dc4d147106d060bac03501228901ee23e51b629d809fe86ca91b857ebc264348fa6711d52ec799e49790380856eaf2c16d41b7c5851c8b8be074e2796ef9fc5a51af35abf82e7064d8ce70219ffff0373457bb1c2d5a37570f05f98d0da6ab88337ebb1dc5e69d8905424c0d25f3ff5035ceaa6bbae7d847a6b71ed0fd91751f23a221217cae0cca560eca0ed46641fe203baefa85ed25f86ec38ffeb1dce60e649268ec9253f9ea2e937177cac4a32c02103deb8799b4ebd27039932274a35b805633be4c4f9e316424c0da29cfeee1413500319e279bdc8e991271380be21083446fef85aaae12b0ee658bd0a4472344497c80379866774e2f225b8895e3de8a034c7cda76505fe5a0bbf4cee28bcf03a50889103f207db476fd76b340723f6806bf05778064c1b8c03ea762913042a6deaa83bf00333ab1293f95b00e0f5ae9eb29d2b2914f25a9e927ff18e077fabb6ed05166bc00219ffff030f435593b37c6e7e90456965f90baccca95ec22f18726dba77f969586563319a0374f3bf4b37dfba97d3bb836784a582d5387f1825e37bae15cef044e4a400ee10034224592b2898cf17dc3412815aa5d8306aa68fd1897203f32a00fde6614829db03b141e7b53041cedc0726c3eb62ccf7ef8594064490e280a085412683871b3de0039ad73dd089132dd4797a0dbd3bd6fe1b098c46f06c517ef1e3797ef8c51dd21003c0ccc062063d494691863a58cffb0498c3ecf32b97fe6bafbfa4f91a3aadbd3403ca29993c9ab4769f55b1668e25e86366c58315e90c52fbfbbdaeb966f0d8213a035444b46af6e3c94f584c4dc0c7cee1e3e9750071fa4f648b452633be27cee3d103dd0ef771e03aa7643e5ebc78ad7ba2ba6e3029f1f54503f575b2c1db3a50484e032fb5287c04e5b0440901877a095a4a433cb704c875ab4faf5d92b890f83a368d0342182d0d0b8b8f6888219bb5441e71ed5247061f247b3e5beb05256fd437446703057fea1a0b7e2ad1b0dac40108d98219a77820023ae54f6aa1ccd599dbbfaf90030bcd00ac7b07c9a993662985753fd20a5ad28aac1cad7cafef8550f76d905bf003fdc6ae80d23be595b425ec6bf90d701c20aa537c992ae517519c1c9132cd35b00219ffff0300b3538138548d8e7cdfe3ec6a0649346cab821a2c12759a2d5c735ca1e2476b0397f9be41801a5e5cfb6d5aa5fdffc062a433b8403c000683a3eff412dceb69d303ae5583703a0d55910f9e00556ed1e99f16b07e48d8063abec2fc81036899731f03468233cd70fdd2f93ca606aacf821aa5b529aa0b97ad5fe3e01834e23fd2f26f0380dbd6361c810ebf3dd1e1d37a2708bacdbfa655f6f65184e4c77d428d18dc65030fa56fdff3c568c91864f230f49dcd3071208ac2c6f2e9f436777e5f8a3600060394e5b49d3a8c2f88390491996babb83300f840ef28c6dca64d89405e3a39151d03a8be77041b3cc39fd155bb8c1634cbc4f642485cc1bf74edd32f8097e2b9d1d00219ffff038ee69e0c947fa4b09f8d38dde182267b4c4a16ea0242c041369619c16b2f69500392065172c22a81711d3803081e2c66a408e0727400ad2d83ef13c570633d5fea03ec289b0aa52aff14cdb4d22bb62e330c7e4ca2aa611ebae50902c190e9d0c99703b5288a3d3514fb46b592e754af10a92ec8a7f724ce0c27d8406956ac2b8f5b8b032f969988b3bb0cc7bbc443189f47d5900025e8f77ac5500ca95baf449e774c7103c4154482e9e26c9bc32112b211d4717775216f694bfddfc8b269ab56a46205d80219ffff03b86aaf4643a9522fbbae67b172edc7c77393325dc9c31c9a7abd8d3994c847c20389ee3ccc7222da174ba639ecac039602c3e717952af7296b84ed11b7e6f2309e037361d147efae615395c158f88bca05f3945005fc43a8196e1bbc97e710e13cd10342525c1620a81a4b104fc85e3694cb32589489ce2ee5b01cd9e6ab14a5cebace0343e3b06cddcce5e0f06baed99ecd0a20775a5ff0e74cc5a76fc9c61010739764038b6c262adfe371830f62289777185cf8f52217c9f95282c67923a377eaaf86ed035dda29994853c06889e9e46917a2a0f79400940167b9aef146ab347b55d664e703559ca936f787bfb77440659de1c59ad30eeb28eebc23817b843ae74f761b283e036bb1e58c1e30f46e3e5a17c627b36840ce672a1b4576340c39a5ab5614686d62036d4da0172d96c64cf89c5e12666fff5bae46b070b11ff34d32f8cd1e16c31de903b51b58d1619a46dcfc5d4137a3842bbb299e2fc846ce6f87bbb6b89c2b0b9bdf03d913f2df7f405954f7f3ddec0f6b6fb418ebc3eb0748d9195474e98518ae658a034f042a8a0a48b51cab19b6ff5b512e2e54ff0bdfb317f28c999791cb204411d203e5d907601a73120bae4431e4d05d07deb1eb429c219bd2219dcb26e71fd9affe03cb44b7d70efc4351355d73d14d0022521f1b259212653ad83e8baa6cec3c23d3031dc993b12dc23a0d67244bf463405d99e8000baa1fbd040708ceeebc4fdbad8203d0d7e8ea93789f0857b17f2698c99009e8d53b35eaa1e292ffc9714d45adc00d0395d70f0441aafcca4c87ba0a8e565313ea2d2b242fb3cad8d04d6fb8483fadbf0355534b75d3c88e148d52a6870f57d19ba0ac801caa76e08476b90b48d7245a4003baa59f2afa6444c81244b86b7c9dd17b6edca4ac623a93762aa2db74658760e6035b375faf8e6b683046c729754d73b5625199502802051d1b437d400cdcb0cf3603600009c54247532fa59301cf9015172f85b4dc83cc238f70df51f73262af9457039fa254060036f7f90b710bc3b17f2d866d5db4c06b175506c911246f6d0b50f5036d5b2af4df1e2f292bf9b5cb4e13e1ceb528bcd8ac00fdb041d777a456ae4d1b03e7f4e78e600c3126f4691665f1a867963f504bf7e5f272f7e269369d693885370390d6c43e3dede80b4c6759b42c5d330666f3fd1146f164889637c446b1673469038dd25b7adccd1a9cc378ec8a4c419b593e30f6c853535e3f3c3a7675d9f5948a03b6c688039c4174b06ad78c703fba69d3145fde491a9ea057e0ca4689ce6f083b03b5591bb5ba5bd4c45ac3827151cc5af7614e1bfed7809196971af8362c19490403c07c7fc3f92e6ebff32d0fce3961aefd7ee2e0c5090158ee8578d094fdc5b2e203e91b66637cde3244ee7a4f3c0c6f2d41e5d3d51f2fb161fde3b3e46a7be5d2e403ca6f9f545f835eb201a5cb3a64e0c6a3d382ec7bf5bd18d1ee4128de0d5c8fb303d2ff40753b8f0eec2e458c6c092129ecdf4da77d7b95645ca1ef6a47af7135db0342225c8b5558e35ea88dec62a89b5dddca727ca654cd826c19ea4bacc6fbeb6703b0de12445e9e9b542fa6214e604fc40e069fb71044af40d50d4b741d3a3791eb037d577156ee5867430b360d6a12c062c7557e0fe2cfdc2c23c24675676109820603e4abd4b3b402bf6ca99131af823b1f1e3dc564cd30eb6b83aeb4e6295678639c033c1f38bb537c6eb904d7f5068a749092053dfb9fd8445dd54829d6f8c96024650380fecf187fecb501dd15f7452fb9a5b4030af29bbb400caab89d9fd1f6b32d0603bdedc66f85c076c34ddaa82d7f153bf1940a7a05e35f70ee5078634ff0d9529f038c72a5acd831a0cdfd5fa323c3d53bd217dd034aa9adea20652ed7fd52458f230337e3badcb7453ce9eda24b15ef374242c727263e5f5d002190cd5723f3fa6c180380ffb85a7a5817f873341fb95fadb78e688522800706a26f5721c9cc29cd9a2005581e03eb820fd1bffc460d328d2689d7ffe13c4443877bebf25bc3502cd345900c02472427ac4344f80003a31f886c62f676187a889179625c86a313cef7b2e41693325ff5e023fba049f203508d78823e3c33ea99a6bf0627dce396125c96e0f94f2752a9ff05880c38b1dc03e886b0f9abe462c549e7b057256e86d99e81713aa80dcddbafc8f00a0c3fb71605581e0371534472d82ce1ddcefa8a9a081057fa05952073b437c3327c830078f00402031f8b67be329f6419c9282095843235301b6b3475e42bc9e3262b646aba8072060605581e03f53b77d7a78435e2976275d2001631a331bf18d7cd453410c7e13373f007011bffffffffffffffff031d93f60f105899172f7255c030301c3af4564edd4a48577dbdc448aec7ddb0ac0605581e03ae96e94082f9c665a9a9b7f6b303fa097b51f1de5b42723c5fb44dad7007011bffffffffffffffff05581e0339df67ea70629138640dd9da3fc27fd679261a5ed2042474aa5feaa5400c084712cd0bc426c00005581e03cbf8b6bbea8c53f00e0fb58e1ca24db29869fdfa1a0b1ca084233002100c02471b5fd6500abfbf021973b80219ffff03e7428ac36fde822f7b83a928647fe466714ccf84913a6c5aaab7ac82d2b59c7b03d5f0df5e6a2783e918a037a9ee7fa2685115ba141d07037d7b5d46e2054dd5e7039f79a9182ba3b1d9aae33023b9070a638797d05e7f4a44729aa17849d5223a24035fdcd59a931ec1e91064d844c649073f657e4203d36eacb2351521e9e4954ac603af08685cc91bca4266afab1357e6e9f2f219f11bdd5e1261f3d98327009541ab03f8593ca6ef3232bf440abe37ff28edeba31191f213e5d4b2c3b5e1439decbc4b037730aa436fa2aacac76aec54eb6182c0ca79133e33d8131d4554eefe4d75ef1403916342879007e01d97b956f624ce44c84248f89bab906ad9c5b606db31c8588a0372587fa7fb363fd94c739e3143d15247587726f61c87b0d21223c25021bba3ed039481046e71013bc6b2a66cd833a256a6b6463c9fe29691a062792221433402d80356ec3acc0a875b7d4d1c3d8fad6fd9368ea37b473ec6f1e19b78bfe9688e599f0362eca503aebc0ffd7ebf4011dd3b5a9c0d801d14f9ffccdc1d19bfcfca7200c8039a28638fa0c05db0d14a30bc9ad3c7098402739c7e17b7da6b480c83e70b3734030aaa978382ea98c6ad771b344bb123f56ee7d5411df29e368eb8c0b4f38423d103059c72e2ba055b1657fd968572d1f163a911c55b7e10b7098e5394e265cbd79a0219ffff03edc2850f10888801ac80c00884047f5f1f9544044abfa9ab59823ad741a2400403f51b244fbd3f59b9a76bb6bd4e26ce99a5fb4a0356949d052bf8e1a61212e8c8035085eab9c1ea2fd2a560bb213b6d65267407f6db09f61e2dbaf4e4a7008279ee03540d382e5593c6ae6206d3279c3eadb38dca924833afdc4ca438a9937b4c27520337f218ee8dd919d2e018d8c42eb15735b7d2bbe0a74839a890c46788319fbcfd033ac886856797396af4c01108aa53ea9372d271d2b9acbc1330f74a8677e4c2030219ffff032299a13f697369a2b8c8cd261698d2c8787129b582643aa4a927107a7660802803bc910df7c9217db39175a9572de2d6e7b40223794d53ba7c243144bc16d2847a034c997b100bd7d9daeb847ef6a709d188e83d39df005cb3680a1b86ff656d718e035f53bbfea1cbd32e1cb555de9e02c8670a100a58dc33bd879f6ae31c83623c530379a28106c797704a0effe2026865167c4da61f6f36350cecacdbb4a552d223e203e92c82c1edb4bf407b8d4c88e76983f82c06025827a8448d940953d3e344ab9803415a787536042dcce97a33582d622b3c234fc3830a69c4c4a69f6cb5b747ffe303204e8dca3471264a5d4a52f7fc903b258b615b152237ea048a368e60801c8ee803379d91c811e24844e170e2a6b7eeb60f0bc974dd7770e1658ec9093fb561912a03478c6781a8b905bd91ba3277ad73fd8f441063ad8b4ceb471630d8f3ed66721303031a7750b7920766c5a83f2f2536cebac67ed4ac864e67e19b983b125711b4530219ffff037bf29d067ad70cfe53cfaca684a37229afe02b269a966eed4ed1468e28150b7403493e70d29d51289a7d856c5f354a06e786c281d154b3400e808102badc2388850302ff93a3d24cbb140307b0eef2cd8f54c657b10eafb610840855e336ff7d506603f4fe654f6a1f9d54fa6ded013deceb6bd263f60aa743472d43d0847671421b6603b79fdfee4d00a18b9b2bf952e6e3bf6e8c58143ff6bd625b85910f82c989e9a0037d6bab9c0422fcb453d57c21d8d125f8111f44e0e77e5b85292d811e9b1b49bd0308f33ccd920808d75225fdcc533b87d62202c3c57695853bb328da416ccef01303564a099ace8ddd129f8fa6ffb1424cf467b5c8d3e42ff0a86006db8c76ebf2fc0219ffff039f6c2732d7b95617cb8197e7e4002cc002c64b144b5845e9daecc07fd3339b5003bd2bcf581ad903637e4b18193b7f9be573ac1cc2937acab93bf51d6e988a42e50386494bbfb0aa70413b277552286c6f29bdefcd7272de4e0157a9b0941dfae682035b5b82d8a2aab2799f37814d9c86295de5931fcfcfdd704f8aec87c1a138b7950306f1364261d9ebf275893b908531ea5b3a477fab09954a136e867b35f1d2f0d303a488dc121ff72c6a93a87347962f56baa5d7ca73fe9d843b61bea8ad6abac63a033743dbd1d0c596f2a960a19a9828f1804b0f7b7bb2ea5e0cde398adb8ea475a603338a53de165699f747dbca896213f929be1829790e8375571f32bea3b9dcf80b037a23d8955e02626c2d9fd140ff89ecb66065fa37307d13a2e091a88d50be0da503fce5604a841794dd825a8230ac71ac0b39e20d50e06a76c5e01054fe236e7b9c039c401fe781b9c7c3a3c5404c3c4534e7efbf6814bf59ffbade4f69191cb801da033ddbe85c6065e70c8607c2b56a55c611d921fc7254fa6c20e3b0cd1d34e3e6f003cd236c04aae3f2c1d68481eb9bc358740d4bafb2ae08006ccfcd011d6afed38f031bbb02dd05d10628864a88112243e6894c305e535f73e727a4d52f403e143ca103819e66518a3856d1d846aa1d5dc35dc477febcf8bc0907ceecbf8cf79aa27fae03d2cf80a073783fae139933f1118b3464f00a14500d42dde47448e74100c6e77203de3c2a255b9b8bf74ee7b19feea80661889633fd0276b9628aec54d3d205b5ea03a7e6f134ee27e789afd55d643954b0eb2eebe8c7a371156db10b438eea837175039491a0c87ccc44b8836fab4b9759c5ccbf54c64f9a79aaa5b17d8c998631aa59036c9a03b3ecf60fef21257cdf8c1e29218b5803c7af18ed5144c1d117df3472f203933976cd2b0d1b8aa5f90a0f05897ea5cfef9719e26b44c045a45ba9c31f008a031d040db431c1fb7f7f1d03948d9460864f252e74802469844850a06bcbb9427e034cca4db733293a24d9ac26f272ba20d508028a6bd06f11de91ef40863e7e69b70303f8de524306c156a570cc25d8338c395c1d3f250c6f99895dcc60cdd2f682e3035cadbcd3d4e5e0653750a7b95e0b23a8d99528089bad926e1eefd78e42f6f5f3035e38338aecc7ac3cde429b7e3ca376145c5f47b227675c83aeddfa37730e7bbe0396af2dd1fcea069b5d7ec3c83208498da143d91ddca8b76a026484ed0a6c675f03a00b51ba6358fe3421a49355bce187b96bc2ee92bb024717c9308964ba93b1d60353f300e70b2a63b7c0d61d497bde74e0fd2dd87ba270bb896db24248e9f18752032e32d8311e84f7669859ab7142d248057171786d538b72b3b224f99390f5487303d3586623ba49d4a46a0d22a44c5d21975812461e0b98198bf602f91fc600bd1703ffe1b3a1a75a68ea426847a428f6abc359c7fc3f2254410c0b18bfdfdb2df636031b290c8af2c6b40f4413944c55645e780c6bd37db2397a369694b03519eb1b5f0374470a5751c368eff94a85f83d58ca0deb060f16bbcc115cd0f3bc5ca1c1c79103d0117d2b9071d72802a9a798fc10d91517b8e153afd593a7766ee3c6fe5a50aa038a461051b15d2b75df6c9895928735cc2614bad3c8fa997cea767b7f245491da031147cc7e1da5fc3970ff386d6e178e39e2e3f256ed9c5234312439ccc09bb7770381a1aa551415e356b298808eff24d7cc13f0e4a4e042531b704d0978dd348d9e033d8d47d0b3ab8f53caa5462ec26e18ffd435793ce80d454d3a0de3a66b8f4dd3037cc67dd0f9e0b3c1dec99b0a939a542f806924dd609dc79b15e879e374c2ddd603db1edd88da31b9173b3a01a4bcb70736f1fb7d3d7c4ff994859c9853af8d13ad03368a3deceddbf642196ed53eccf27173a264a7676dd248d202620423db656dba03dcaddf110217ee48bfb8eeff146af24219a51ac93ca67f522482e2a3564b460103304bf37f15689fcfc3757c0cb8a9c73e888edf17c9ae9b058175ae200c1a49ae0351b04acdc59d6d2676cb376513e6ef4e0e457fb7667841912288d0e20a2a80b303cf603aa4de6a946d150a191044c72b182176fb4021c6b2d18a383855a8f0234e031b5526d099906496a3a33d60306caefad770cd03a0881fe26d7f1a0de66b43ac035e59a8277f34b835258b96b4508bec0ef3922515e4142f0490770b3b2175569f03293dce157508c58129da9fdebc65200c1c1d983a8107e0f00d93b0cfe25af3e005581e03e61bc331fa2bcfdfbcbaaffe43953dd29f5dae150f901483658d263be00c044707b05cbe758c7d05581e03e98f02ec287a7bc81664c3bd3547c9c43fc30dd780deb035cc572ed0200c044683c5a2e4fd4005581e0301b4c5ac518015a0bce436357c6ffae80bb8291afc971ebe35544f24400c024501aa2450d005581e03fe83da1ccaef9d9bd78ce53543b6368d6df3947d410bf2d34eb594c300040205581e03ec48afe9bed2ccb5532d8a32fc0cbb2e1ba61c7556de5f51e397c4be200c01463d1ec5ffb1f0032df39c0062882ba634fb24c89e7f9871ecef10a6e6a6e79a336f6ed463d5c94203576d247b864a9c9c193245be5262a86aceeb51240a250d7b4354c293d83a678d05581e0397fc5d38badeb2417fc4af69d36e4965c61f33bb84f646b7d58a9da68007011bffffffffffffffff033fb0fa6f5661fde6378c4db73cf7f1243b922e4b55a3435735c010e477f1c24405581e037a436184a5fc4ce62ad4b2daaf8a45e35f2947e33aeb11416da640405004060219e48e03026455994a7764223a128fa757f29d61c41ac8e28bbab1f879c66e232fddb035036c4372246d91297c5eca3d8d1d450153f9522df23de517957182e29d8416b60c039c41360797c1aa7097a0a9af04c1f817bb5c454d0f772e8ebe2fd352ca7e0d8003ba5c25d3ffc47ad414f2443245ed620a381ce9d9f0d1ee70505a1db59120de1403c0b160d239ce0c71812917d0798c6964edb234491c2f32eb7574c8d7a16270d1034424e96e0a1731300a2559039dea0424a1e764dd8d7d15d03aeaad0ad4f3c4510219ffff036d14a8da010d275acfb59254cdcb9eae8cf5fe7b6ab4a71a2a36194c74b9a3bc03731ac71e9d419e6d1673e09527d61c4f7b9d634dec4cf33946a8ea03f67fa57e03a916837a533d8f341b1bb7fb0e55bcc6b3331f628dde4d08d5ac4d72b8da516703c20aaaece2b73a3a9adc8e7a8806aca1e659dcab0526d1437690766ff0b4452d03d21f43153c769cbbc6c78b5dcf8b9a5d5f139ab0d0f24fd215618da92a34226a03d152c22b71f6c3039c0923a13d58ba41db780be6dbee23526315a0a7cf0431f103c90bb142fa9e97c9d16aab891708825684b56324f90029d149c20ad2d236a30703401ae904b5b28a574e99197b56de5407bb0eef555f36f65acfe9f1819fa6a2dd03966249ae6fb9ba9de1c890a1de3ecf7da07fa01d7602346d1d2a3b0f829cbb750379694c8599c0f3eb1711dfed98e2e4ff393e83f1c8132f830c1298d0a76c182603355149d946dfa2ad5f816899256dbb60ca00eecff995689c2bbd7370215729a80219ffff03fa4bc73fd4b3e5ef71f2079c8c7d0367d6c5e067eaed4b34656b1926863401bc03aef7db107436b3c50134ad9bdba4ab448c0b3cf02a7e2b8c0c88fbdb4b0c2cb50219ffff035193acd8f798b1956536dcf7fe595d15a5dd7454a103659708015d2297bdbcef03c5619d369433bf9fcfb86dbc288cde781cab61a13890d23d8e35269f21df280603173e6adb834c681b932bab9925c8017b62ee314a1a96d5785219e76ed6e6fff903e34b9c0599f8c2ef3b96a881ffdcaec6e123973792fd3b5afa5ef14a69a289880219ffff036d601f7967997e14f0b8ddec3cd67d8c4758d5849ca7356bce8860758ee9c848036b190a0ac12310f42571c2af0c442bac657e635a7e06b05aa0139febf8aef0a003c8825581763941270cb3e17f04c73fd4484788da4848a24a6b4ac5c87f1e31840219ffff0219ffff" + } + }, + "txn_info": [] }, - "txn_info": [] - }, - "other_data": { - "b_data": { - "b_meta": { - "block_beneficiary": "0x0000000000000000000000000000000000000000", - "block_timestamp": "0x663e28fb", - "block_number": "0x12ebc68", - "block_difficulty": "0x0", - "block_random": "0x2e5e4c5b459345002e2597c5b8b556f0fb51fd9c6c45f7892eb98cb4de973795", - "block_gaslimit": "0x1c9c380", - "block_chain_id": "0x1", - "block_base_fee": "0x1aafac7f2", - "block_gas_used": "0x0", - "block_blob_gas_used": "0x0", - "block_excess_blob_gas": "0x60000", - "parent_beacon_block_root": "0x5ab8b5a8f53fb6e010ee24d46334a9ce1051a5ba1691b6383ce8b2a03c10f158", - "block_bloom": [ - "0x0", - "0x0", - "0x0", - "0x0", - "0x0", - "0x0", - "0x0", - "0x0" + "other_data": { + "b_data": { + "b_meta": { + "block_beneficiary": "0x0000000000000000000000000000000000000000", + "block_timestamp": "0x663e28fb", + "block_number": "0x12ebc68", + "block_difficulty": "0x0", + "block_random": "0x2e5e4c5b459345002e2597c5b8b556f0fb51fd9c6c45f7892eb98cb4de973795", + "block_gaslimit": "0x1c9c380", + "block_chain_id": "0x1", + "block_base_fee": "0x1aafac7f2", + "block_gas_used": "0x0", + "block_blob_gas_used": "0x0", + "block_excess_blob_gas": "0x60000", + "parent_beacon_block_root": "0x5ab8b5a8f53fb6e010ee24d46334a9ce1051a5ba1691b6383ce8b2a03c10f158", + "block_bloom": [ + "0x0", + "0x0", + "0x0", + "0x0", + "0x0", + "0x0", + "0x0", + "0x0" + ] + }, + "b_hashes": { + "prev_hashes": [ + "0x55c186b1bbde8e25b506461db3948d0ee3420042b5fe5a7410af110c1de0554c", + "0xaeed1603c512f372a2edadeb3d4cbd206835a22b25cd9d39c3e144804b26c16f", + "0x8dca61b2f49865cc3effd9e925230c787baf87e30919bd49b738ea4f9dd036b2", + "0x784d858125b4d78a6e0dba2b7ff74bbdc3d6cdc5ef978d08ab3c7ce504229394", + "0x5bb4ba2e0ac463c24628bdd92b74e7a47e0502c8c96089de64f98fd35521dfcd", + "0xcadf72a2755406bb8059cd8dba4c72f97994e51e5ea12b8133bf7f525a428169", + "0xec80579f0f3ffb6658e493e6f1483bb0806356edc411dcaaec825724a3e85e55", + "0xcda45eab952474a2adda67ba2b623716d391bae8d5b2fd81941dd84eeafe83bf", + "0x43155a9903b32ed536bff6788430cd522a275e94c405f619da62c9f41b018a56", + "0x1dda2c3bd2b5216008e68146df9d8cc1caece12dcb2ff13f2d66c16ec1f56aee", + "0x5bcd9b6bfa39e238cef925d01df0d26cd670e0ba714825862f9cb850284774d4", + "0x3b3c0b38b57668e82873490e17ca1ef17b6dad0601c34f2972d7fc8b8d79d22e", + "0x61b483cd38bcf09fd561812bba39b3e0575e93cba262fb454dee0a36e26ab024", + "0x5ff6964818c36655c7482419013438b32b7bf43dc1d0bd80afefc563849d4cd6", + "0x9d06161a501ffd95aa500f5df003b02fdab30b429c3c6de48b7cd32a367fc9c3", + "0x5e1b8c54af7fdaee9c27c67ed4990b609922c54e5fdfadfe928183304ff8cd45", + "0xafd7f313fb970bde5669de90b24b56ff010a3485ffa4229746d6d8000f892f5c", + "0xd10b7f3f17f6a0b00f9947380b0f509e595d3c52059e7bd52a2294fcd5003d4e", + "0x708d167c7dc11778cb2016d12caadb0c38c4c9f173f499c71f4030b87a7b7b28", + "0x29ba6bbb96afc0058f9ab3fe3f22a70a94a91adba5a671798fac8569abf7ba17", + "0x7ed2fa00a64618717df2375d8eeca6eb00b26a69772891d29d53bcc4eb97d7c0", + "0xa2031bdafa03772d8e8504c380ca08269e89761519083027c64bd27108650bc3", + "0x4cbb35640dae5ac34a0aaf0e22f68266ae98b4edeb0906781e24cfc0d2c1228e", + "0x58f159fbfea30bd5848f382e8cefe0df41c355f2000f0f67ed1c38ed41844b24", + "0xe09a822d4bf4cfb20b9fc45e996b452668920a22f397cd02d5ee1f13cae4d641", + "0x9e6ab278fcace59150124fe6472e7bd931674e6370f240abcb38fde46d01cc22", + "0x1b69a6375b4c78ffa61e023a2c3ffb8f21e59f567ab40c647e5248d2763ddcae", + "0x5d2d637fec24b5fa7b72709c699b0605f20c4f77d02bf7e7450a2f845054e472", + "0xa1086afa9e6aff4921a7f3744b7eb28c3441f4e4e359b3a25e7007c65c640531", + "0x8f2cb0870c743235582ca9cae7a5948af500bc1b374f93df3a574e32fbc38f3f", + "0x1a7094e313b8c766f54be0f5da29c29e43b05d6ae42ba517ac1b487bc5c96b29", + "0xcc819e929bede7df0a415f55c1ab062970f815326af426de9f5fbfb992e7e437", + "0x2f051da3ca994b22fb131a27d68bcb2c9726154744a10d46298f40140f6a56fe", + "0x6c853ce7a1da5258cd093e6cd033391a68d0a459038ce37a67d9d17cb88036c1", + "0xc8b0a654e358d7ea93973e2de403d258fdf63da30d6d4034c6827d63fb0edc94", + "0x079cd237218aeaf9a0806360b659ca28762c81f635a3cc501004bb285da58d45", + "0xce1a58a6ed09e666cb0079d48bed5325d161b1c9799f1376a6e4f5822d56800e", + "0xc2136e2aaabd540ca25376c74fb0f675f74eaf47dfe8338a55bfe7ca09ebf0c5", + "0x455e0f3f874619fce323640983b9cc6ab7e0939fa3554c1d6e6f1dc2850536a4", + "0x0cb731db488d51696f60b38c15e0fbbf2ee9ffcc070601192a9e02f6adbb19d9", + "0xe190ec154493546f06322e499ac6bd923438403c676674dd40e0a02e1e45dce5", + "0x1c7c738bf9d0bbf2210090da40774221dad6d159cedf46e51af981282b92856d", + "0xe253577ef8179f8ea765286b6ac234748508c2a79aacb1cafa6993301bf2eb97", + "0x173d63641a7e8f3a7f53fa111b1bec0a2582adb18b3a5c78c81226d311ff079b", + "0xe8d8838dbde5c9150f82e297fe3d76a0c57f12e6f9dfe32453c7e94fcd7a9eb9", + "0x9a61bb64b265aee98d017b3859ad07e76266993c20d1a88ca1bbac3d5d1fcd46", + "0x6bd8bd7da7c642f94b8e0f3186ff027e09df12e34d8d2af607f59e06b87a48b5", + "0x45f6a8d776c000e9cad3f0f120b4986ab94ef4c6bd6d56aa80abe556552c7b7e", + "0x3d907fbbde00deb31cec9c06658b215c943b54127a2c48a462ff0e0c903dcd65", + "0xf5a91976a772292a27b5b54d5fc3ff8a983516eb91c052bb8b3379b1ad0176ed", + "0xd81e25a6ce87305c0d8787dba67dcb66f27b120dc46a91705d080676c81987c5", + "0x773bd2e85389ee5ddd8ec5dcf3795b99e338fa7bb6585dedf74e4483835884ea", + "0xe13a5ffea3cfebf9a0c4624e7cb6881a107a64a271b23bc4835001600f3bc2c2", + "0x535984a643ffb027cfc10476ea2954da4051e48f6157e08530785c2037687267", + "0xff25bad36168818211de295f993032077845e7548739290870055d412a9122b2", + "0x4421ac0d5d5744b71964409561bfd967357511feba5fde27f52302a28fc6b95d", + "0x8f459e102509740b99c3c8f7c3381c283b17d9b1f666a684f07c613954303214", + "0x149d211899e93714c2d702667f5d4d846faa8ddd2797ef997eadfb8d04e70830", + "0x939857b774469e5fa629f4974b0af64c852f0ab4b9f2f694c47c2185c0884c59", + "0x455506f075651b27e59360e405bb3ceba1b284eaaae9f8b7ededab0144241397", + "0x7794f14899d895626054a6775da2d759972ca19a2c7b7fcdafefd3ac81044dbb", + "0xcb1bf88f145349f03b12ad36ba1e2654cd0490262d2686a0390f871447c2dcb5", + "0xb06dabbf192e0f83a2ef9a5c64dd13ad925c0ba3bccd49ba4b9a8cdaa03e0f90", + "0x03a872389b9add1a56eb0ea9737e5f6324849c3f9a618052671b48b11a9ee51a", + "0xd3d865376c8affae8ab310e5cb18c45caec2fd3c8ae2881f06b8229b5855a69d", + "0x4ac61a400ea11b5470f7d2fb3429ea1dc3d4873154c3f7b357246deca3ec4f68", + "0x8f14c907c7bf50bcea75ae65c7d62e66772e5ff15faf430faa5898abbcf92363", + "0x6d151ff1347f6204806c5349fa3dd19bd0221a00773a3c5423328cfcdd64bbe3", + "0x4d4f747eea3eae7dc0423da074e257f523ea688874bcd3afc28e0cdfeab0c7a8", + "0x00a6c2c059ebb164a9377e084206ac5832cc5297cdc0200ca86762e31be4f134", + "0x8de486c426447c83cd81c2f4200e2026abd8833f2803da7568a9ddf11117aaf5", + "0x6ea90881d941139490f2d278593586a7a229ac789532627569c25af254539415", + "0xcb5f64f11bd0a0907b26e13c1f0e22f755907334307c26d2427a387ce70d482c", + "0x359f8609c02c2ef873c5524687a35f1608c71eba9d34c0afb2765a6519e4de3e", + "0xb65483aa05099003d212ec7bb1eac1dd62165d67da35ae1df758778591a778f7", + "0x6bb00536c7d49f225bb7eb094fea16b263549b585c019293dd6018817a82c100", + "0x2566da7d2213e0157c91b6e6644a17b978b93feb2b522621473c3f7bed541d76", + "0xb720814c561850a476c1070fa9fdce8a7fc4269bd7c56bb14479f4b1636800b2", + "0x84932dc6d0879e3b01bd311362403854fd9e4b1690fd59c323ba3b04cf19a969", + "0xe4250b66c3b5b017603e06477a5c252e9596595fd3d787c298ad2ac45e24019b", + "0x3941e8083df52e04e2a3fea6a6c310e558e6747146e676dd0e5942655e9ee3ab", + "0x2240c0287ef3b987e01d00db447982d5143fb272b9846b1af226664197c78292", + "0x0bebcaca64b07b7536c2f6fbfeb9d5141a2d8e309dd942852409bd21d17cbab2", + "0x4e32243bedcdb9f2a5c7f8d423d2a8aa2b487f23b1e3d7d8c220aa4a55cc0a9a", + "0x279a114f51480e923292c58807523e7da08fa9aeea5214f09d27dcb229ca3b1c", + "0xe7a4d1977c4aa7b776bf74e46f66c2e15589c67684bda719e3a6526b90bbc158", + "0x6cc1f2a3880c2aa41d11c901ba91926758e252ce1f148c51a769a81ae34303f8", + "0xbf9e7f17c786e48f5ac09b605da6619ae50788bea08cd42500835802e67b8729", + "0x8a6b70454cda7934a39cd374405f3f5f7c39977273912abb841c4eab738b1237", + "0xb3f52f9b2f7e6a37074d1e20751da4b4fac4fbe0a91386966670631f2a545f7e", + "0x7ec81bbdbbb56a40ad2d00ee6f34110ad97d9935c7dad83d7968ed5512ebdc7f", + "0x40a7df3b63d2f7c4fb05e37b1836dde00becd7166c82fe0df45bbaafa8d7d338", + "0x62ea7fdccc874b5f39f0290e4c0ba8b7b0b5eb12e2a83734a1e236cc87e6453d", + "0xd990e2aeffd23a789d298673c88498322ddc13729bdc6324b62ad6e0a6b2d939", + "0x13f5571d094bb53856ce1e6573a61dece7f32e0f593da75439d2cc59690828d7", + "0xf003ae90a37ca406f346082ff47df498cbdd720e2ed487277f31bdfe495fbd5c", + "0x1ac6ef95f6e007da86fcb50652491da28924854b45cb4d4cd8d574a5ae6da337", + "0x55f27c6633a639527034f2889551243ba50847721b11380bbbcae5ed9eba7c1c", + "0xe9f06076dfe328442393dae25b8fd8667b52c20b860b619947aeb758b5161288", + "0x93665a5b3ff727fabed298a5117a07214f44c80369c12b788e98e50adc9af06f", + "0x214b1e759711d63acd3aece629f1eb5d207b306c868cac471b40d4a264c425c0", + "0x88d2ef86af833ac6146fc687e93972b5f59089a0aadf14b7a731d60c1dc0aac9", + "0xf30a23080c5cb8a76bc1772a811fc7d770ac0595c7b52b606dc660965cab5218", + "0xa136d539a24861b4bdfc4f156347b436c2ea0b69d3e28f75863ab6e90d485e6c", + "0xfdcbcaf63e67009e531ff489c46b7a1433107ef7a54274190d4011d3190d34f2", + "0x70b735311bbd5733eedb484d4d11f88d3de47f3d14afa4fa182525801991f560", + "0x0b7cfa03f5c925257041b19f0ded62df6c29999d258b164592b54badbc0a1ee6", + "0x134e8d9ece216b70d69e369c28f38eca6a0c61b1d1242dcef7b576aa4ac57d3c", + "0x5dd966a462f85da54f3d1dc30b5a629977fbb7c279f754887bda19d89177ac31", + "0x4f2700f4b972c826c3d6bae610c1bf21f716ec99a4b1e1a37bd778a37ed1d81d", + "0x26e86dbdd46fa58dc7c0f23e3402def08d7f09b6600a012eb7503e868ef82239", + "0x1f009da6c2b59286201b3c12a9e52d821e520bb067ddee3c6d57b29b60394c16", + "0x36953b01dfbbb273002d819beb306d703688d6ade4430f8b258bf925c9bfcb1e", + "0x7a94d795bc76fba6899dba6b677d526dce7f01518f4cc8cd18bdbfc31a778b9d", + "0xaa8ad1cc6c206dd616eecfc976cbf2caf1e522facc73ca9d9494d89887d1e302", + "0xc8e5fb05d201e951af9be69c7afbff266cdb11110ad69be6748da319757596f3", + "0xfb394b3865fc15ebaab85682ebe8caf1e7a6ae340c127d9c6675447a8f87807a", + "0xc978e59542a478bba83a9890692f0ae88a0bb7a3df30b7cda0dea4ed7d34eae2", + "0x00832dc5f938a74505d93d3d5c4ab78a50752d45d27eec9ed1ab7a462abd8990", + "0x31cf0cf7fe510d6bc4108ede74063e1bdc3113a21f0212e5c6ab36eaa1faed37", + "0xdc87984673693bdb250a1896305262b2346ba3af4fa0676eca2eeba52eb040ed", + "0xfc945bf877357905dda2af20404e426a82db019437bf1b59f60b31bcdedfbe55", + "0x7f4cc1a12ef5979e6953d3e40f40a4dc932c6c174f183b30f701e6fa4f1b34cd", + "0xcbb31cec8319fa2fea3e7781f981e98aa0769ec751b2e97888b2bd2b5e5d8e58", + "0xee48275f37a5306d7c5d52a1ff2200d3150248f6c596994ee0e78fdde42f3811", + "0x5378d6d66892ceaf1089db912d546f565a2993de54e82eb548545eba7250b31d", + "0xbff7a5b25847fb689db38926fbba529b66374886952d641319cd8fb85731c58a", + "0xa2b4ff87dfb05b3cb88ac945706ef5e82765d11536a428c2ad27fecd19bd8947", + "0x71be8e30b0f2cf7df16495cdfd86e0012c5bb8f728374d86e772d4efa2beda20", + "0xdfe133c543e32cffec7bdf9febab7bb0eaf3d213094a102e4a1c21842fe7afdc", + "0x7874bfed2ae039536a7f92b4aa6f7b7f231152b04895ab0c6efbd3505cde5ae6", + "0x86f49a60e84b885fae20af792a164c679be96a5975ec83fc896cfe19a27a3181", + "0xd1f4af1826401ec1636d039bd528e496ac7ea3f181205eab5751778622129dd6", + "0xefa40fc9cc91899653d4218b8473bc49c3b64d84869cc996987729df1eaa4219", + "0xbdb65de637fa89949f69e6b39635e76fe3da079179612c8101c92df404388e6d", + "0xe13e4e0e93cd3e9e881688079ab5caeb603d53f3f8c3f159a3216dac654003a2", + "0x5b3bdd265d4c516c62a9685cd2e6343c3b542762f45d381aa10adbe4cc2a8ca1", + "0x3fbe2934edb9b4c74feac47a10c34f43c73ce9c04fd4aff4da9e9d53ae1a3b27", + "0xe7f738ca0d301c92913c1c5bd670f2958bc3bccd349206f798ff38615704da02", + "0xd6023f0729c366624fc9581e69c8217352113d2b15e8824d36b05fef5640d228", + "0x2a426c808ee5b9f8c405875e564962a318666acd06bc6942dfc7a4960dfc0a78", + "0x1346589ec5380ee0dcb41cf0af9e8b39a7395a13b94b97150bcc11a71e2b4c1f", + "0x2fcafbf9b787434cf0f745acd8d880cc553a432810acf1bbd66b433ed11c2c18", + "0x33290d023a695c514e8dc94f04719532e377eb81790e288a0b017312b41a0ff5", + "0xf8befaf58584c66572ce8251e42d002cfc5355a9efc8d5f9bc9088a1f7b9edfd", + "0x1f9f9f7a63d43d358f2499ce9b04ce9f0a4b35546011215fb83a22e68df87844", + "0x9a9c4815d5827ec055e39ec001252a5035e6317a05b508bbc3e6907b53109706", + "0x3b277af862fc12912cb482182175edd1ad4dd7f15b2614e0970c3ea09d1a8de3", + "0xf8967669bc80f68ea5c966bb42117851d80c18e81dfd184efc59491971a9165d", + "0x00814afcf1ecf5f401b450afcb6d73ce3fbf6338e8bc4dcec4c32d5b2ecc6454", + "0x63ce5390474616f8b3b70820e67460c6fda75f41f2a2c66ab467b0c311733f3b", + "0x176619adb025ee77960fcdabada971e20bd2789d8e3cf045c03d4ec2e97b2f79", + "0xcd01a05497515a98f69a8a48b534ea1e741bdee0dadb2a32a97c631212e2e5a5", + "0x0b808e84cb0904210581a81e312236efed3bca37e624f6a6c66bfed4134ebf9b", + "0x42ed1705030f23cbf6525095491f6f82914727b116c85bc24ebd9d3579508554", + "0xeb6c3c39f07929e4d0a2ae0a8f9390f2f286f715095f31f82b471cc3f02ab770", + "0x6d0b0405e16a27285e6645ff8a29e05a6f8d4a4ada9ce08b729caa89af96ea48", + "0xc02fd4ca15b5c7a0eb193e1a679fef5ce2cc9e5732209c8739b31cde876b524a", + "0xed2560d142a34db7c5b20125882fb61b8edc1cf22e12c81f860c47a1239706f2", + "0x9f9d607cb7d98b099460c97bd9bf4abe27524de0aa0494068d52cf380aa36293", + "0xca530177bdd648a62d09f77f03f134e3e3bc0d64bcb93a335ee2ca73d73ac2d3", + "0xf2bd87e7e61b6efaf4339ca27cc8d73df9d3d71799bd50ce1465ce9386350023", + "0xfef3aab8dceff11c8cf8fa282e482c9a4a7c53c471a7e329e9720bf917f744ce", + "0x56002bf72faf92897f58fe2679e3571ca490d6c036f724a80b74aac20970641c", + "0xb207591550eb9be35178a224e6ca46ec82b2a6a019bf961f13e7df2026009b9d", + "0x2b52868f8b17ef786cecd0a9a4fcfcee6d9551d4c9104a5ab8d8eeadb707d2dc", + "0x7c4acd1df61f61cc5e2f4ee9decc296d98f3f3fc89ae66bd07d41c84ff56a288", + "0x30adce03c6c2b1532e07e33a24c7f73d08feccb5497e33910226388032a80812", + "0xc79ae82c871ef39b9558c1339ea365dac86469a1165fa0d36b7775c49d3ac7f1", + "0xe4e52fb5b9f83cce4205f09f720c5a4556d0511e20c5c3e0c63f9a954a010adf", + "0xf53f57bfaa2aad6de5fd3f236bc8a4361e2af82fcc198bc058e5d7a5bccd0a02", + "0x5098a75b4dd1d02507416a6e3b8cf0b0ea6cb15bd68420ebc3b7915eb7839f1f", + "0xf9c0e2cbce9fe64623de15c2f85d7c3928ab0b37275660a242770219e3a96d93", + "0xc5b62e1433192d067cbd106d3c0ca218383ddbf14c00c9a13d56449f2bbb3a08", + "0x80d8820d2078d42c1a38e8d6f9f81d58cee3846aaa899261ee1ed85ff4d42533", + "0xd886a4c921ab8b11a3e855a7893664f09629814ad6df0f3bd36cfc37a42a0bbf", + "0xc1375c4f051bd893b5e8a3d768f398b396efec9c4b0e4c2b0d352bb69c9fb394", + "0x20ae02c26b613b05737e26202e18100c3eeeb84c078bb3d4912be5cd99787a2e", + "0xcfa25f8226fe9e61e35fc2ed63a52f2b2a4c3dee8e192831f7a0cda7b77022e7", + "0xf1506b0bb1dda73bbc12eaf379580952e65880b0aef361231d8686619da83b9b", + "0x0033b129deb9e2591fd3375084de6f00fc3f72d37911eb2d623820de7c03ed9c", + "0x245b2677360776f20b01ae7278b41980a63eb45cf6f7566f5804dbcb7e3ea66c", + "0x73081e452c9aa38f130ad22fa653519888b429d3e1aae6701fa5407ed088872a", + "0xcf8224c7675985b9d8411694d881a452b850c3d41331602c6d2ddc552500d9b6", + "0x8278bf3e350fa2532dba0e7082f64bb1fc08f3d2279525545a62ea488835c756", + "0x134a0e1ae78dd0da790d1dc3b1710caaeb3a6015c82fda8efdbd1e5ceb154767", + "0xa5a77ceb096cbc27b2eae356c942fde9db8d72161e9e559ad6376143d7f4d609", + "0xb34c9ca03d44c2512795c8572527f6285c3a6e954cf17668c51e8f22de24efb0", + "0x7cbf51c29022b4cf1e6203cf1322481a36f510c35bc1d78d972101e9593fcdc9", + "0xc3162682c647172119a2cebd3ce42fab8f20be84b20b3c4a85b4b2196eefb80b", + "0x4c8e78cad3ed836eb63af411b683a3d21d7a854004d026ee928870e7d8c94239", + "0x92a9ccef236e16e8d527f9b4e25861a670763b2845b9e7f2831d83f7411c1bb1", + "0xf82d9c2c67a3a6050a1003dfbcdbc6861ca699d41b2bdd69099196122365e218", + "0xafbe03db4a223222536b6ae7e65a66303bb2c89f978a49db05dcee8ce3eb9bfd", + "0x97db73ba455ac03902bfa5335d1efd1c3a08fdc5fe1bda5c402413a6c6bf6439", + "0xe87c9f587da80c6ebf6416e7851fdbd1a5e44b7bf68b7b5b93cae18f5b71001d", + "0x04977189709d5e8243e2cff4d6e9bebae049fcd78854c414276049c1dd8899a2", + "0x0dfb0bc4588450ba7f992ac46b5e68b740bc2373a944c70a440a25222451f868", + "0x2092f8d8303fdfd369f4a24ef504a9d48acdfdfab2e37115d5778a0adfac0082", + "0x19d81b509c576de5a558f9c8fb929d84fea577428fed5af023a7f7bb502e3643", + "0x935fb703a9a030bdad9db265cb3292c2c9a038f1837e049d1d5045b09047a4f0", + "0xbec9f75266da91b02a2d1b5f5b5449f7e6ba28ae402979af40a83c9b39cb483a", + "0x320c3fb2a136d04495087d27b0a5dc6ce90bf7a1bf15ae65d48146a9661f2aa9", + "0x364c285cabc386ccf0140bd24bbc98e37a88b6f88bdb7d34ff1d4a75f29573fc", + "0xe595476b0844351af48748f788d15b53eed8507c6c45faddc189d602d8de1bcc", + "0x803f52547a1ca56abdca4b4ccc28bff586fb3372d9bf677b3ca3400184d009ba", + "0xb90914aebed7eee12fb7d25e80c2f37f68dbf2a698faf2ac92faf0cffafdaf8f", + "0x129abb430b863be8ccb3e33a3194552ede9eca4bebdf34d6b53748213a734ff8", + "0x9a6dcb68b7b37e705ce7457fb1ca954cb5549eebcc4397ed29083df51362d779", + "0x12bd07e3b6ae0add86cc1467208532430c0c8d7d0e832e9c05134b07e46d1768", + "0x69d228b5d0f85a16596aff9f2b51ffc21497d4331a0c9b6fc5b3b1834654df09", + "0x3cd093afcf1b1588b12da25cdbeab67cf99fbbe9df026f78d3abffbd378eff6b", + "0xecb8e829dae8134f700eec6d11e0157bd761fcf0779bb603cd024d0ee8496717", + "0x0fb6faa0e9b556d1ca1e91f56117d417c29b7368445c18cdd0bc5060ee6c86f4", + "0xf126590823b117b19491aae44cdcfb18a3e130f00371398a254c3c3845ff0592", + "0x5f2432d15b4f94234961ce9e6165e9761accc88999c523315001340b96227519", + "0x60d53f01e91fde0da7f3a05a795a491466a211d6cc91e9e49e42d5bc4bd78606", + "0xf575fd0cb12b72eec6b639210f04b5bbad1a7c806fbc6c2c15ea62f97c2185c3", + "0x3ffe76eb15010487bfd65c38db0425d5df9a14df60dfcf0849bcd540aa1300db", + "0x6dfcea9390145d196db57f5b427d9c5e89f336a5bc81bdc3a4e246370feee2f0", + "0xe3c2e58ff9ff293dd8e2084b333bfefb506382848b1884ad03546f457f0559c2", + "0x807d9d862e2b760628b579b66b206ebcaf247f3d041fd9863fb375dd715b74f6", + "0x11e8e648599d5bbabd99f3693c090d95a7ebb66b82e5ce33ae47f7b570154423", + "0x4b59ea6016b208f2e5bef0606a7e81f05cd679eb7635db9e27e8458980281dbe", + "0x5afe3f29cd36132c4db3fe0d989dac1eb5cd6c7c4fffd22a03691a695df95489", + "0x5fc081154e1402309a9ada4d39f90a083bda62aaf4e643a58b2a1bbff8c030c2", + "0xc8f835e4abfa2f4d3cd3e1f92ed878a78253b828ddb8e89300e3de63cfc01775", + "0xa94346dc4441d16b65996b0b44d1ee7b737f75e6857d22a7a03f5cc9b7156c97", + "0x7a9d66965c11cedc5af224b42d407423d56dc291f9a6903f013e4c2801e28f94", + "0xe1592fdfc80452f70c8372bf59824166ccfed92ca6bbfb0a7f196bfbc11a3d7d", + "0x5800287a2051dc265161d6197ab2f0221dfc918f1b37b685f8d23c66af24412e", + "0x875c7d11313b43a3b2df625bf5f0f816b2743ba44165fda1a34c0d3c9d53c54c", + "0x9d87149d991d4a54cdd689e156c37eccb9c2e3022cef97d91bc04667905f8a7b", + "0xd39a5b4c38441cb4a7dff3a22d8ab37691f21dc3af438f4a1591058c214d1284", + "0x6de58f2f7f2b3f756b6c3683596b11c1b68235f032ff31561f92c6d2e0d31575", + "0x0d4b0e13f898561309b8b4ed0dae1f0698d4433aeb81a4e66a045b69c4356c94", + "0x82e58ed2c7e584e42f9f284a1171461338cdc40661e5457ce86621fb9939e3a5", + "0x0f6af8168a7e2e6f35539a5477d9dc4901af3eca6e3257d7f0ecc0b573bf2c73", + "0xe3eb2cce31d8e65106536c608a154388fa00cc5a481ce635c55eb130f021f218", + "0xf6829b8da3ddc1f71b3b14ca1b06c13e9e454a364899c4ce726d3b9a9b55b1ca", + "0x248b513050ea763394365a1ff6a295b6648fd1af0a5703daa7dac423cf5967ad", + "0xcbbd5076dc646780f3e582343c66090e477e32b56210adb84992e340b74a798d", + "0x6e844d7759a5aff03abb0efcc0cd74285a20521afd06c0ff98b82a2bf17a7224", + "0x116a574a2fd13487716a1e3bf78cbbc998dd5b3604caa567662055de8691a459", + "0xfe36c7f148af1c056b913b4f52c8dc4fa0e6cba42b1e7f5204c1d300f9ae1ab4", + "0x114da06ec0e3d1b14027802c9c3bb80922213786464dd5b6a1ee2a12523761aa", + "0x9c451c4cce3cf45b173cf2abf03ffcd11f5d471db49c5abc66603795c6c55494", + "0xd0dca6ee9e3cf1d9277aa5b9a97acf7a45d63d0f76ea8cd84366e2c787489061", + "0x4f93256e5e4af9d0771ee8cf5cf84b80d2f7298a76c77ddaeccd835d4717864f", + "0x174ab2c74403d9538aa14bb0549c33756095c78e647b18eaa818790876996f8a", + "0x0d62cbeb56e7c3db3c6845badab75d504695b40ae7e8b1e6ad13097f5cf65154", + "0x70c96dd19bca237759ee01a00ae6ec75873e2c1384908c86310e766e8352c299", + "0x2ba3360edd065360b551e07aac2fe6a1b646fae955c29d39c1e981b8b8541a72", + "0x64400f31f7e3deb29c6f22aee609a502db3e9c6c9eebd5a93087b6a1636d44ba", + "0x255c5d43117d4d6e3ee88610b3fa54a679ab1eb358153147188a5fbde1556db1", + "0x290e2c3125591d2f128758525955799fe08eb933dc0e22519810e63a10f0ea69" + ], + "cur_hash": "0x3c869591ac4295afc75154eaaf7a8b59a41af3cdcbad9d8c48fb7ef9853f9ec6" + }, + "withdrawals": [ + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x119204e" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x1193fa3" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x118a669" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x118d295" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x1195db7" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x3c46d9e" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x118b8bb" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x11994d6" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x11822b1" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x118b828" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x118b7e1" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x117492d" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x3c1adb5" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x11713d0" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x1197bef" + ], + [ + "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", + "0x1181b16" + ] ] }, - "b_hashes": { - "prev_hashes": [ - "0x55c186b1bbde8e25b506461db3948d0ee3420042b5fe5a7410af110c1de0554c", - "0xaeed1603c512f372a2edadeb3d4cbd206835a22b25cd9d39c3e144804b26c16f", - "0x8dca61b2f49865cc3effd9e925230c787baf87e30919bd49b738ea4f9dd036b2", - "0x784d858125b4d78a6e0dba2b7ff74bbdc3d6cdc5ef978d08ab3c7ce504229394", - "0x5bb4ba2e0ac463c24628bdd92b74e7a47e0502c8c96089de64f98fd35521dfcd", - "0xcadf72a2755406bb8059cd8dba4c72f97994e51e5ea12b8133bf7f525a428169", - "0xec80579f0f3ffb6658e493e6f1483bb0806356edc411dcaaec825724a3e85e55", - "0xcda45eab952474a2adda67ba2b623716d391bae8d5b2fd81941dd84eeafe83bf", - "0x43155a9903b32ed536bff6788430cd522a275e94c405f619da62c9f41b018a56", - "0x1dda2c3bd2b5216008e68146df9d8cc1caece12dcb2ff13f2d66c16ec1f56aee", - "0x5bcd9b6bfa39e238cef925d01df0d26cd670e0ba714825862f9cb850284774d4", - "0x3b3c0b38b57668e82873490e17ca1ef17b6dad0601c34f2972d7fc8b8d79d22e", - "0x61b483cd38bcf09fd561812bba39b3e0575e93cba262fb454dee0a36e26ab024", - "0x5ff6964818c36655c7482419013438b32b7bf43dc1d0bd80afefc563849d4cd6", - "0x9d06161a501ffd95aa500f5df003b02fdab30b429c3c6de48b7cd32a367fc9c3", - "0x5e1b8c54af7fdaee9c27c67ed4990b609922c54e5fdfadfe928183304ff8cd45", - "0xafd7f313fb970bde5669de90b24b56ff010a3485ffa4229746d6d8000f892f5c", - "0xd10b7f3f17f6a0b00f9947380b0f509e595d3c52059e7bd52a2294fcd5003d4e", - "0x708d167c7dc11778cb2016d12caadb0c38c4c9f173f499c71f4030b87a7b7b28", - "0x29ba6bbb96afc0058f9ab3fe3f22a70a94a91adba5a671798fac8569abf7ba17", - "0x7ed2fa00a64618717df2375d8eeca6eb00b26a69772891d29d53bcc4eb97d7c0", - "0xa2031bdafa03772d8e8504c380ca08269e89761519083027c64bd27108650bc3", - "0x4cbb35640dae5ac34a0aaf0e22f68266ae98b4edeb0906781e24cfc0d2c1228e", - "0x58f159fbfea30bd5848f382e8cefe0df41c355f2000f0f67ed1c38ed41844b24", - "0xe09a822d4bf4cfb20b9fc45e996b452668920a22f397cd02d5ee1f13cae4d641", - "0x9e6ab278fcace59150124fe6472e7bd931674e6370f240abcb38fde46d01cc22", - "0x1b69a6375b4c78ffa61e023a2c3ffb8f21e59f567ab40c647e5248d2763ddcae", - "0x5d2d637fec24b5fa7b72709c699b0605f20c4f77d02bf7e7450a2f845054e472", - "0xa1086afa9e6aff4921a7f3744b7eb28c3441f4e4e359b3a25e7007c65c640531", - "0x8f2cb0870c743235582ca9cae7a5948af500bc1b374f93df3a574e32fbc38f3f", - "0x1a7094e313b8c766f54be0f5da29c29e43b05d6ae42ba517ac1b487bc5c96b29", - "0xcc819e929bede7df0a415f55c1ab062970f815326af426de9f5fbfb992e7e437", - "0x2f051da3ca994b22fb131a27d68bcb2c9726154744a10d46298f40140f6a56fe", - "0x6c853ce7a1da5258cd093e6cd033391a68d0a459038ce37a67d9d17cb88036c1", - "0xc8b0a654e358d7ea93973e2de403d258fdf63da30d6d4034c6827d63fb0edc94", - "0x079cd237218aeaf9a0806360b659ca28762c81f635a3cc501004bb285da58d45", - "0xce1a58a6ed09e666cb0079d48bed5325d161b1c9799f1376a6e4f5822d56800e", - "0xc2136e2aaabd540ca25376c74fb0f675f74eaf47dfe8338a55bfe7ca09ebf0c5", - "0x455e0f3f874619fce323640983b9cc6ab7e0939fa3554c1d6e6f1dc2850536a4", - "0x0cb731db488d51696f60b38c15e0fbbf2ee9ffcc070601192a9e02f6adbb19d9", - "0xe190ec154493546f06322e499ac6bd923438403c676674dd40e0a02e1e45dce5", - "0x1c7c738bf9d0bbf2210090da40774221dad6d159cedf46e51af981282b92856d", - "0xe253577ef8179f8ea765286b6ac234748508c2a79aacb1cafa6993301bf2eb97", - "0x173d63641a7e8f3a7f53fa111b1bec0a2582adb18b3a5c78c81226d311ff079b", - "0xe8d8838dbde5c9150f82e297fe3d76a0c57f12e6f9dfe32453c7e94fcd7a9eb9", - "0x9a61bb64b265aee98d017b3859ad07e76266993c20d1a88ca1bbac3d5d1fcd46", - "0x6bd8bd7da7c642f94b8e0f3186ff027e09df12e34d8d2af607f59e06b87a48b5", - "0x45f6a8d776c000e9cad3f0f120b4986ab94ef4c6bd6d56aa80abe556552c7b7e", - "0x3d907fbbde00deb31cec9c06658b215c943b54127a2c48a462ff0e0c903dcd65", - "0xf5a91976a772292a27b5b54d5fc3ff8a983516eb91c052bb8b3379b1ad0176ed", - "0xd81e25a6ce87305c0d8787dba67dcb66f27b120dc46a91705d080676c81987c5", - "0x773bd2e85389ee5ddd8ec5dcf3795b99e338fa7bb6585dedf74e4483835884ea", - "0xe13a5ffea3cfebf9a0c4624e7cb6881a107a64a271b23bc4835001600f3bc2c2", - "0x535984a643ffb027cfc10476ea2954da4051e48f6157e08530785c2037687267", - "0xff25bad36168818211de295f993032077845e7548739290870055d412a9122b2", - "0x4421ac0d5d5744b71964409561bfd967357511feba5fde27f52302a28fc6b95d", - "0x8f459e102509740b99c3c8f7c3381c283b17d9b1f666a684f07c613954303214", - "0x149d211899e93714c2d702667f5d4d846faa8ddd2797ef997eadfb8d04e70830", - "0x939857b774469e5fa629f4974b0af64c852f0ab4b9f2f694c47c2185c0884c59", - "0x455506f075651b27e59360e405bb3ceba1b284eaaae9f8b7ededab0144241397", - "0x7794f14899d895626054a6775da2d759972ca19a2c7b7fcdafefd3ac81044dbb", - "0xcb1bf88f145349f03b12ad36ba1e2654cd0490262d2686a0390f871447c2dcb5", - "0xb06dabbf192e0f83a2ef9a5c64dd13ad925c0ba3bccd49ba4b9a8cdaa03e0f90", - "0x03a872389b9add1a56eb0ea9737e5f6324849c3f9a618052671b48b11a9ee51a", - "0xd3d865376c8affae8ab310e5cb18c45caec2fd3c8ae2881f06b8229b5855a69d", - "0x4ac61a400ea11b5470f7d2fb3429ea1dc3d4873154c3f7b357246deca3ec4f68", - "0x8f14c907c7bf50bcea75ae65c7d62e66772e5ff15faf430faa5898abbcf92363", - "0x6d151ff1347f6204806c5349fa3dd19bd0221a00773a3c5423328cfcdd64bbe3", - "0x4d4f747eea3eae7dc0423da074e257f523ea688874bcd3afc28e0cdfeab0c7a8", - "0x00a6c2c059ebb164a9377e084206ac5832cc5297cdc0200ca86762e31be4f134", - "0x8de486c426447c83cd81c2f4200e2026abd8833f2803da7568a9ddf11117aaf5", - "0x6ea90881d941139490f2d278593586a7a229ac789532627569c25af254539415", - "0xcb5f64f11bd0a0907b26e13c1f0e22f755907334307c26d2427a387ce70d482c", - "0x359f8609c02c2ef873c5524687a35f1608c71eba9d34c0afb2765a6519e4de3e", - "0xb65483aa05099003d212ec7bb1eac1dd62165d67da35ae1df758778591a778f7", - "0x6bb00536c7d49f225bb7eb094fea16b263549b585c019293dd6018817a82c100", - "0x2566da7d2213e0157c91b6e6644a17b978b93feb2b522621473c3f7bed541d76", - "0xb720814c561850a476c1070fa9fdce8a7fc4269bd7c56bb14479f4b1636800b2", - "0x84932dc6d0879e3b01bd311362403854fd9e4b1690fd59c323ba3b04cf19a969", - "0xe4250b66c3b5b017603e06477a5c252e9596595fd3d787c298ad2ac45e24019b", - "0x3941e8083df52e04e2a3fea6a6c310e558e6747146e676dd0e5942655e9ee3ab", - "0x2240c0287ef3b987e01d00db447982d5143fb272b9846b1af226664197c78292", - "0x0bebcaca64b07b7536c2f6fbfeb9d5141a2d8e309dd942852409bd21d17cbab2", - "0x4e32243bedcdb9f2a5c7f8d423d2a8aa2b487f23b1e3d7d8c220aa4a55cc0a9a", - "0x279a114f51480e923292c58807523e7da08fa9aeea5214f09d27dcb229ca3b1c", - "0xe7a4d1977c4aa7b776bf74e46f66c2e15589c67684bda719e3a6526b90bbc158", - "0x6cc1f2a3880c2aa41d11c901ba91926758e252ce1f148c51a769a81ae34303f8", - "0xbf9e7f17c786e48f5ac09b605da6619ae50788bea08cd42500835802e67b8729", - "0x8a6b70454cda7934a39cd374405f3f5f7c39977273912abb841c4eab738b1237", - "0xb3f52f9b2f7e6a37074d1e20751da4b4fac4fbe0a91386966670631f2a545f7e", - "0x7ec81bbdbbb56a40ad2d00ee6f34110ad97d9935c7dad83d7968ed5512ebdc7f", - "0x40a7df3b63d2f7c4fb05e37b1836dde00becd7166c82fe0df45bbaafa8d7d338", - "0x62ea7fdccc874b5f39f0290e4c0ba8b7b0b5eb12e2a83734a1e236cc87e6453d", - "0xd990e2aeffd23a789d298673c88498322ddc13729bdc6324b62ad6e0a6b2d939", - "0x13f5571d094bb53856ce1e6573a61dece7f32e0f593da75439d2cc59690828d7", - "0xf003ae90a37ca406f346082ff47df498cbdd720e2ed487277f31bdfe495fbd5c", - "0x1ac6ef95f6e007da86fcb50652491da28924854b45cb4d4cd8d574a5ae6da337", - "0x55f27c6633a639527034f2889551243ba50847721b11380bbbcae5ed9eba7c1c", - "0xe9f06076dfe328442393dae25b8fd8667b52c20b860b619947aeb758b5161288", - "0x93665a5b3ff727fabed298a5117a07214f44c80369c12b788e98e50adc9af06f", - "0x214b1e759711d63acd3aece629f1eb5d207b306c868cac471b40d4a264c425c0", - "0x88d2ef86af833ac6146fc687e93972b5f59089a0aadf14b7a731d60c1dc0aac9", - "0xf30a23080c5cb8a76bc1772a811fc7d770ac0595c7b52b606dc660965cab5218", - "0xa136d539a24861b4bdfc4f156347b436c2ea0b69d3e28f75863ab6e90d485e6c", - "0xfdcbcaf63e67009e531ff489c46b7a1433107ef7a54274190d4011d3190d34f2", - "0x70b735311bbd5733eedb484d4d11f88d3de47f3d14afa4fa182525801991f560", - "0x0b7cfa03f5c925257041b19f0ded62df6c29999d258b164592b54badbc0a1ee6", - "0x134e8d9ece216b70d69e369c28f38eca6a0c61b1d1242dcef7b576aa4ac57d3c", - "0x5dd966a462f85da54f3d1dc30b5a629977fbb7c279f754887bda19d89177ac31", - "0x4f2700f4b972c826c3d6bae610c1bf21f716ec99a4b1e1a37bd778a37ed1d81d", - "0x26e86dbdd46fa58dc7c0f23e3402def08d7f09b6600a012eb7503e868ef82239", - "0x1f009da6c2b59286201b3c12a9e52d821e520bb067ddee3c6d57b29b60394c16", - "0x36953b01dfbbb273002d819beb306d703688d6ade4430f8b258bf925c9bfcb1e", - "0x7a94d795bc76fba6899dba6b677d526dce7f01518f4cc8cd18bdbfc31a778b9d", - "0xaa8ad1cc6c206dd616eecfc976cbf2caf1e522facc73ca9d9494d89887d1e302", - "0xc8e5fb05d201e951af9be69c7afbff266cdb11110ad69be6748da319757596f3", - "0xfb394b3865fc15ebaab85682ebe8caf1e7a6ae340c127d9c6675447a8f87807a", - "0xc978e59542a478bba83a9890692f0ae88a0bb7a3df30b7cda0dea4ed7d34eae2", - "0x00832dc5f938a74505d93d3d5c4ab78a50752d45d27eec9ed1ab7a462abd8990", - "0x31cf0cf7fe510d6bc4108ede74063e1bdc3113a21f0212e5c6ab36eaa1faed37", - "0xdc87984673693bdb250a1896305262b2346ba3af4fa0676eca2eeba52eb040ed", - "0xfc945bf877357905dda2af20404e426a82db019437bf1b59f60b31bcdedfbe55", - "0x7f4cc1a12ef5979e6953d3e40f40a4dc932c6c174f183b30f701e6fa4f1b34cd", - "0xcbb31cec8319fa2fea3e7781f981e98aa0769ec751b2e97888b2bd2b5e5d8e58", - "0xee48275f37a5306d7c5d52a1ff2200d3150248f6c596994ee0e78fdde42f3811", - "0x5378d6d66892ceaf1089db912d546f565a2993de54e82eb548545eba7250b31d", - "0xbff7a5b25847fb689db38926fbba529b66374886952d641319cd8fb85731c58a", - "0xa2b4ff87dfb05b3cb88ac945706ef5e82765d11536a428c2ad27fecd19bd8947", - "0x71be8e30b0f2cf7df16495cdfd86e0012c5bb8f728374d86e772d4efa2beda20", - "0xdfe133c543e32cffec7bdf9febab7bb0eaf3d213094a102e4a1c21842fe7afdc", - "0x7874bfed2ae039536a7f92b4aa6f7b7f231152b04895ab0c6efbd3505cde5ae6", - "0x86f49a60e84b885fae20af792a164c679be96a5975ec83fc896cfe19a27a3181", - "0xd1f4af1826401ec1636d039bd528e496ac7ea3f181205eab5751778622129dd6", - "0xefa40fc9cc91899653d4218b8473bc49c3b64d84869cc996987729df1eaa4219", - "0xbdb65de637fa89949f69e6b39635e76fe3da079179612c8101c92df404388e6d", - "0xe13e4e0e93cd3e9e881688079ab5caeb603d53f3f8c3f159a3216dac654003a2", - "0x5b3bdd265d4c516c62a9685cd2e6343c3b542762f45d381aa10adbe4cc2a8ca1", - "0x3fbe2934edb9b4c74feac47a10c34f43c73ce9c04fd4aff4da9e9d53ae1a3b27", - "0xe7f738ca0d301c92913c1c5bd670f2958bc3bccd349206f798ff38615704da02", - "0xd6023f0729c366624fc9581e69c8217352113d2b15e8824d36b05fef5640d228", - "0x2a426c808ee5b9f8c405875e564962a318666acd06bc6942dfc7a4960dfc0a78", - "0x1346589ec5380ee0dcb41cf0af9e8b39a7395a13b94b97150bcc11a71e2b4c1f", - "0x2fcafbf9b787434cf0f745acd8d880cc553a432810acf1bbd66b433ed11c2c18", - "0x33290d023a695c514e8dc94f04719532e377eb81790e288a0b017312b41a0ff5", - "0xf8befaf58584c66572ce8251e42d002cfc5355a9efc8d5f9bc9088a1f7b9edfd", - "0x1f9f9f7a63d43d358f2499ce9b04ce9f0a4b35546011215fb83a22e68df87844", - "0x9a9c4815d5827ec055e39ec001252a5035e6317a05b508bbc3e6907b53109706", - "0x3b277af862fc12912cb482182175edd1ad4dd7f15b2614e0970c3ea09d1a8de3", - "0xf8967669bc80f68ea5c966bb42117851d80c18e81dfd184efc59491971a9165d", - "0x00814afcf1ecf5f401b450afcb6d73ce3fbf6338e8bc4dcec4c32d5b2ecc6454", - "0x63ce5390474616f8b3b70820e67460c6fda75f41f2a2c66ab467b0c311733f3b", - "0x176619adb025ee77960fcdabada971e20bd2789d8e3cf045c03d4ec2e97b2f79", - "0xcd01a05497515a98f69a8a48b534ea1e741bdee0dadb2a32a97c631212e2e5a5", - "0x0b808e84cb0904210581a81e312236efed3bca37e624f6a6c66bfed4134ebf9b", - "0x42ed1705030f23cbf6525095491f6f82914727b116c85bc24ebd9d3579508554", - "0xeb6c3c39f07929e4d0a2ae0a8f9390f2f286f715095f31f82b471cc3f02ab770", - "0x6d0b0405e16a27285e6645ff8a29e05a6f8d4a4ada9ce08b729caa89af96ea48", - "0xc02fd4ca15b5c7a0eb193e1a679fef5ce2cc9e5732209c8739b31cde876b524a", - "0xed2560d142a34db7c5b20125882fb61b8edc1cf22e12c81f860c47a1239706f2", - "0x9f9d607cb7d98b099460c97bd9bf4abe27524de0aa0494068d52cf380aa36293", - "0xca530177bdd648a62d09f77f03f134e3e3bc0d64bcb93a335ee2ca73d73ac2d3", - "0xf2bd87e7e61b6efaf4339ca27cc8d73df9d3d71799bd50ce1465ce9386350023", - "0xfef3aab8dceff11c8cf8fa282e482c9a4a7c53c471a7e329e9720bf917f744ce", - "0x56002bf72faf92897f58fe2679e3571ca490d6c036f724a80b74aac20970641c", - "0xb207591550eb9be35178a224e6ca46ec82b2a6a019bf961f13e7df2026009b9d", - "0x2b52868f8b17ef786cecd0a9a4fcfcee6d9551d4c9104a5ab8d8eeadb707d2dc", - "0x7c4acd1df61f61cc5e2f4ee9decc296d98f3f3fc89ae66bd07d41c84ff56a288", - "0x30adce03c6c2b1532e07e33a24c7f73d08feccb5497e33910226388032a80812", - "0xc79ae82c871ef39b9558c1339ea365dac86469a1165fa0d36b7775c49d3ac7f1", - "0xe4e52fb5b9f83cce4205f09f720c5a4556d0511e20c5c3e0c63f9a954a010adf", - "0xf53f57bfaa2aad6de5fd3f236bc8a4361e2af82fcc198bc058e5d7a5bccd0a02", - "0x5098a75b4dd1d02507416a6e3b8cf0b0ea6cb15bd68420ebc3b7915eb7839f1f", - "0xf9c0e2cbce9fe64623de15c2f85d7c3928ab0b37275660a242770219e3a96d93", - "0xc5b62e1433192d067cbd106d3c0ca218383ddbf14c00c9a13d56449f2bbb3a08", - "0x80d8820d2078d42c1a38e8d6f9f81d58cee3846aaa899261ee1ed85ff4d42533", - "0xd886a4c921ab8b11a3e855a7893664f09629814ad6df0f3bd36cfc37a42a0bbf", - "0xc1375c4f051bd893b5e8a3d768f398b396efec9c4b0e4c2b0d352bb69c9fb394", - "0x20ae02c26b613b05737e26202e18100c3eeeb84c078bb3d4912be5cd99787a2e", - "0xcfa25f8226fe9e61e35fc2ed63a52f2b2a4c3dee8e192831f7a0cda7b77022e7", - "0xf1506b0bb1dda73bbc12eaf379580952e65880b0aef361231d8686619da83b9b", - "0x0033b129deb9e2591fd3375084de6f00fc3f72d37911eb2d623820de7c03ed9c", - "0x245b2677360776f20b01ae7278b41980a63eb45cf6f7566f5804dbcb7e3ea66c", - "0x73081e452c9aa38f130ad22fa653519888b429d3e1aae6701fa5407ed088872a", - "0xcf8224c7675985b9d8411694d881a452b850c3d41331602c6d2ddc552500d9b6", - "0x8278bf3e350fa2532dba0e7082f64bb1fc08f3d2279525545a62ea488835c756", - "0x134a0e1ae78dd0da790d1dc3b1710caaeb3a6015c82fda8efdbd1e5ceb154767", - "0xa5a77ceb096cbc27b2eae356c942fde9db8d72161e9e559ad6376143d7f4d609", - "0xb34c9ca03d44c2512795c8572527f6285c3a6e954cf17668c51e8f22de24efb0", - "0x7cbf51c29022b4cf1e6203cf1322481a36f510c35bc1d78d972101e9593fcdc9", - "0xc3162682c647172119a2cebd3ce42fab8f20be84b20b3c4a85b4b2196eefb80b", - "0x4c8e78cad3ed836eb63af411b683a3d21d7a854004d026ee928870e7d8c94239", - "0x92a9ccef236e16e8d527f9b4e25861a670763b2845b9e7f2831d83f7411c1bb1", - "0xf82d9c2c67a3a6050a1003dfbcdbc6861ca699d41b2bdd69099196122365e218", - "0xafbe03db4a223222536b6ae7e65a66303bb2c89f978a49db05dcee8ce3eb9bfd", - "0x97db73ba455ac03902bfa5335d1efd1c3a08fdc5fe1bda5c402413a6c6bf6439", - "0xe87c9f587da80c6ebf6416e7851fdbd1a5e44b7bf68b7b5b93cae18f5b71001d", - "0x04977189709d5e8243e2cff4d6e9bebae049fcd78854c414276049c1dd8899a2", - "0x0dfb0bc4588450ba7f992ac46b5e68b740bc2373a944c70a440a25222451f868", - "0x2092f8d8303fdfd369f4a24ef504a9d48acdfdfab2e37115d5778a0adfac0082", - "0x19d81b509c576de5a558f9c8fb929d84fea577428fed5af023a7f7bb502e3643", - "0x935fb703a9a030bdad9db265cb3292c2c9a038f1837e049d1d5045b09047a4f0", - "0xbec9f75266da91b02a2d1b5f5b5449f7e6ba28ae402979af40a83c9b39cb483a", - "0x320c3fb2a136d04495087d27b0a5dc6ce90bf7a1bf15ae65d48146a9661f2aa9", - "0x364c285cabc386ccf0140bd24bbc98e37a88b6f88bdb7d34ff1d4a75f29573fc", - "0xe595476b0844351af48748f788d15b53eed8507c6c45faddc189d602d8de1bcc", - "0x803f52547a1ca56abdca4b4ccc28bff586fb3372d9bf677b3ca3400184d009ba", - "0xb90914aebed7eee12fb7d25e80c2f37f68dbf2a698faf2ac92faf0cffafdaf8f", - "0x129abb430b863be8ccb3e33a3194552ede9eca4bebdf34d6b53748213a734ff8", - "0x9a6dcb68b7b37e705ce7457fb1ca954cb5549eebcc4397ed29083df51362d779", - "0x12bd07e3b6ae0add86cc1467208532430c0c8d7d0e832e9c05134b07e46d1768", - "0x69d228b5d0f85a16596aff9f2b51ffc21497d4331a0c9b6fc5b3b1834654df09", - "0x3cd093afcf1b1588b12da25cdbeab67cf99fbbe9df026f78d3abffbd378eff6b", - "0xecb8e829dae8134f700eec6d11e0157bd761fcf0779bb603cd024d0ee8496717", - "0x0fb6faa0e9b556d1ca1e91f56117d417c29b7368445c18cdd0bc5060ee6c86f4", - "0xf126590823b117b19491aae44cdcfb18a3e130f00371398a254c3c3845ff0592", - "0x5f2432d15b4f94234961ce9e6165e9761accc88999c523315001340b96227519", - "0x60d53f01e91fde0da7f3a05a795a491466a211d6cc91e9e49e42d5bc4bd78606", - "0xf575fd0cb12b72eec6b639210f04b5bbad1a7c806fbc6c2c15ea62f97c2185c3", - "0x3ffe76eb15010487bfd65c38db0425d5df9a14df60dfcf0849bcd540aa1300db", - "0x6dfcea9390145d196db57f5b427d9c5e89f336a5bc81bdc3a4e246370feee2f0", - "0xe3c2e58ff9ff293dd8e2084b333bfefb506382848b1884ad03546f457f0559c2", - "0x807d9d862e2b760628b579b66b206ebcaf247f3d041fd9863fb375dd715b74f6", - "0x11e8e648599d5bbabd99f3693c090d95a7ebb66b82e5ce33ae47f7b570154423", - "0x4b59ea6016b208f2e5bef0606a7e81f05cd679eb7635db9e27e8458980281dbe", - "0x5afe3f29cd36132c4db3fe0d989dac1eb5cd6c7c4fffd22a03691a695df95489", - "0x5fc081154e1402309a9ada4d39f90a083bda62aaf4e643a58b2a1bbff8c030c2", - "0xc8f835e4abfa2f4d3cd3e1f92ed878a78253b828ddb8e89300e3de63cfc01775", - "0xa94346dc4441d16b65996b0b44d1ee7b737f75e6857d22a7a03f5cc9b7156c97", - "0x7a9d66965c11cedc5af224b42d407423d56dc291f9a6903f013e4c2801e28f94", - "0xe1592fdfc80452f70c8372bf59824166ccfed92ca6bbfb0a7f196bfbc11a3d7d", - "0x5800287a2051dc265161d6197ab2f0221dfc918f1b37b685f8d23c66af24412e", - "0x875c7d11313b43a3b2df625bf5f0f816b2743ba44165fda1a34c0d3c9d53c54c", - "0x9d87149d991d4a54cdd689e156c37eccb9c2e3022cef97d91bc04667905f8a7b", - "0xd39a5b4c38441cb4a7dff3a22d8ab37691f21dc3af438f4a1591058c214d1284", - "0x6de58f2f7f2b3f756b6c3683596b11c1b68235f032ff31561f92c6d2e0d31575", - "0x0d4b0e13f898561309b8b4ed0dae1f0698d4433aeb81a4e66a045b69c4356c94", - "0x82e58ed2c7e584e42f9f284a1171461338cdc40661e5457ce86621fb9939e3a5", - "0x0f6af8168a7e2e6f35539a5477d9dc4901af3eca6e3257d7f0ecc0b573bf2c73", - "0xe3eb2cce31d8e65106536c608a154388fa00cc5a481ce635c55eb130f021f218", - "0xf6829b8da3ddc1f71b3b14ca1b06c13e9e454a364899c4ce726d3b9a9b55b1ca", - "0x248b513050ea763394365a1ff6a295b6648fd1af0a5703daa7dac423cf5967ad", - "0xcbbd5076dc646780f3e582343c66090e477e32b56210adb84992e340b74a798d", - "0x6e844d7759a5aff03abb0efcc0cd74285a20521afd06c0ff98b82a2bf17a7224", - "0x116a574a2fd13487716a1e3bf78cbbc998dd5b3604caa567662055de8691a459", - "0xfe36c7f148af1c056b913b4f52c8dc4fa0e6cba42b1e7f5204c1d300f9ae1ab4", - "0x114da06ec0e3d1b14027802c9c3bb80922213786464dd5b6a1ee2a12523761aa", - "0x9c451c4cce3cf45b173cf2abf03ffcd11f5d471db49c5abc66603795c6c55494", - "0xd0dca6ee9e3cf1d9277aa5b9a97acf7a45d63d0f76ea8cd84366e2c787489061", - "0x4f93256e5e4af9d0771ee8cf5cf84b80d2f7298a76c77ddaeccd835d4717864f", - "0x174ab2c74403d9538aa14bb0549c33756095c78e647b18eaa818790876996f8a", - "0x0d62cbeb56e7c3db3c6845badab75d504695b40ae7e8b1e6ad13097f5cf65154", - "0x70c96dd19bca237759ee01a00ae6ec75873e2c1384908c86310e766e8352c299", - "0x2ba3360edd065360b551e07aac2fe6a1b646fae955c29d39c1e981b8b8541a72", - "0x64400f31f7e3deb29c6f22aee609a502db3e9c6c9eebd5a93087b6a1636d44ba", - "0x255c5d43117d4d6e3ee88610b3fa54a679ab1eb358153147188a5fbde1556db1", - "0x290e2c3125591d2f128758525955799fe08eb933dc0e22519810e63a10f0ea69" - ], - "cur_hash": "0x3c869591ac4295afc75154eaaf7a8b59a41af3cdcbad9d8c48fb7ef9853f9ec6" - }, - "withdrawals": [ - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x119204e" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x1193fa3" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x118a669" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x118d295" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x1195db7" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x3c46d9e" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x118b8bb" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x11994d6" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x11822b1" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x118b828" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x118b7e1" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x117492d" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x3c1adb5" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x11713d0" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x1197bef" - ], - [ - "0xf197c6f2ac14d25ee2789a73e4847732c7f16bc9", - "0x1181b16" - ] + "checkpoint_state_trie_root": "0x319da7faf76836d1ca1c48e0540a97c0d7f2515b7fd7be7dfb1aef9ed5dd588a", + "checkpoint_consolidated_hash": [ + 16744453977166140464, + 7017271634138698061, + 14284306277120741581, + 353542841044461191 ] - }, - "checkpoint_state_trie_root": "0x319da7faf76836d1ca1c48e0540a97c0d7f2515b7fd7be7dfb1aef9ed5dd588a" + } } -}] \ No newline at end of file +] \ No newline at end of file diff --git a/trace_decoder/tests/cases/b20240052_main.json b/trace_decoder/tests/cases/b20240052_main.json index 247fd5df0..f3361124f 100644 --- a/trace_decoder/tests/cases/b20240052_main.json +++ b/trace_decoder/tests/cases/b20240052_main.json @@ -9192,7 +9192,13 @@ ] ] }, - "checkpoint_state_trie_root": "0xaeaab1c6af58526a7a36de5210273f9c7ce2dc936293520b2ecb19b1d786976a" + "checkpoint_state_trie_root": "0xaeaab1c6af58526a7a36de5210273f9c7ce2dc936293520b2ecb19b1d786976a", + "checkpoint_consolidated_hash": [ + 15218262125050039685, + 12215100074924195986, + 6375618978774892202, + 661263567094735674 + ] } } -] +] \ No newline at end of file diff --git a/trace_decoder/tests/cases/b20240058_main.json b/trace_decoder/tests/cases/b20240058_main.json index 37f5ba2cb..379bd031f 100644 --- a/trace_decoder/tests/cases/b20240058_main.json +++ b/trace_decoder/tests/cases/b20240058_main.json @@ -10040,7 +10040,13 @@ ] ] }, - "checkpoint_state_trie_root": "0xbe6449b0d590db000103d74f27cd54f4eaf3ed103cdc1c50f7db1ec5dbc26bbc" + "checkpoint_state_trie_root": "0xbe6449b0d590db000103d74f27cd54f4eaf3ed103cdc1c50f7db1ec5dbc26bbc", + "checkpoint_consolidated_hash": [ + 2482638101945590192, + 5595286337531102146, + 7727862006001321369, + 2952748840780947829 + ] } } -] +] \ No newline at end of file diff --git a/trace_decoder/tests/cases/b20472570_main.json b/trace_decoder/tests/cases/b20472570_main.json index 208deb5bf..b07002ba2 100644 --- a/trace_decoder/tests/cases/b20472570_main.json +++ b/trace_decoder/tests/cases/b20472570_main.json @@ -3339,7 +3339,13 @@ ] ] }, - "checkpoint_state_trie_root": "0x349c33a12c9ac7fee19b759a1aff095d5d734fda61db4295bc8f783b345f10fd" + "checkpoint_state_trie_root": "0x349c33a12c9ac7fee19b759a1aff095d5d734fda61db4295bc8f783b345f10fd", + "checkpoint_consolidated_hash": [ + 18077349309026416086, + 5578611654834857686, + 14273102918993724967, + 7855003975346603760 + ] } } ] diff --git a/trace_decoder/tests/cases/b28_dev.json b/trace_decoder/tests/cases/b28_dev.json index a51aac3db..afa4bf38e 100644 --- a/trace_decoder/tests/cases/b28_dev.json +++ b/trace_decoder/tests/cases/b28_dev.json @@ -318,7 +318,13 @@ }, "withdrawals": [] }, - "checkpoint_state_trie_root": "0x106d584f6804109c493182d0bb8ef06380aea582090f4c2927276869a8d1e436" + "checkpoint_state_trie_root": "0x106d584f6804109c493182d0bb8ef06380aea582090f4c2927276869a8d1e436", + "checkpoint_consolidated_hash": [ + 11541128027127827815, + 532546647585733491, + 11042431666052260492, + 18221434420548059701 + ] } } ] diff --git a/trace_decoder/tests/cases/b4_dev.json b/trace_decoder/tests/cases/b4_dev.json index 46ed3e6c9..6ceed019a 100644 --- a/trace_decoder/tests/cases/b4_dev.json +++ b/trace_decoder/tests/cases/b4_dev.json @@ -466,7 +466,13 @@ }, "withdrawals": [] }, - "checkpoint_state_trie_root": "0x765b89dc0bbd05503b9074455cb6b1f65f23147cc2f7e7f6cd56b262569ce02e" + "checkpoint_state_trie_root": "0x765b89dc0bbd05503b9074455cb6b1f65f23147cc2f7e7f6cd56b262569ce02e", + "checkpoint_consolidated_hash": [ + 8754384126569858367, + 13664083137212440471, + 11466794132567065062, + 13220125099178255864 + ] } } ] diff --git a/zero_bin/common/src/prover_state/mod.rs b/zero_bin/common/src/prover_state/mod.rs index ca049268f..793b726f1 100644 --- a/zero_bin/common/src/prover_state/mod.rs +++ b/zero_bin/common/src/prover_state/mod.rs @@ -35,6 +35,7 @@ pub mod circuit; pub mod cli; pub mod persistence; +// TODO(Robin): https://github.com/0xPolygonZero/zk_evm/issues/531 pub(crate) type Config = PoseidonGoldilocksConfig; pub(crate) type Field = GoldilocksField; pub(crate) const SIZE: usize = 2; @@ -195,7 +196,7 @@ impl ProverStateManager { /// and finally aggregating them to a final transaction proof. fn segment_proof_on_demand( &self, - input: TrimmedGenerationInputs, + input: TrimmedGenerationInputs, segment_data: &mut GenerationSegmentData, ) -> anyhow::Result { let config = StarkConfig::standard_fast_config(); @@ -224,7 +225,7 @@ impl ProverStateManager { /// circuit. fn segment_proof_monolithic( &self, - input: TrimmedGenerationInputs, + input: TrimmedGenerationInputs, segment_data: &mut GenerationSegmentData, ) -> anyhow::Result { let p_out = p_state().state.prove_segment( @@ -256,7 +257,7 @@ impl ProverStateManager { /// needed. pub fn generate_segment_proof( &self, - input: (TrimmedGenerationInputs, GenerationSegmentData), + input: (TrimmedGenerationInputs, GenerationSegmentData), ) -> anyhow::Result { let (generation_inputs, mut segment_data) = input; diff --git a/zero_bin/leader/src/client.rs b/zero_bin/leader/src/client.rs index ea4e5e9ae..a0f38727d 100644 --- a/zero_bin/leader/src/client.rs +++ b/zero_bin/leader/src/client.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use alloy::rpc::types::{BlockId, BlockNumberOrTag, BlockTransactionsKind}; +use alloy::rpc::types::{BlockId, BlockNumberOrTag}; use alloy::transports::http::reqwest::Url; use anyhow::{anyhow, Result}; use paladin::runtime::Runtime; @@ -49,15 +49,6 @@ pub(crate) async fn client_main( &leader_config.previous_proof, block_interval.get_start_block()?, )?; - // Grab interval checkpoint block state trie. - let checkpoint_state_trie_root = cached_provider - .get_block( - leader_config.checkpoint_block_number.into(), - BlockTransactionsKind::Hashes, - ) - .await? - .header - .state_root; // Create a channel for block prover input and use it to send prover input to // the proving task. The second element of the tuple is a flag indicating @@ -94,7 +85,7 @@ pub(crate) async fn client_main( let block_prover_input = rpc::block_prover_input( cached_provider.clone(), block_id, - checkpoint_state_trie_root, + leader_config.checkpoint_block_number, rpc_params.rpc_type, ) .await?; diff --git a/zero_bin/ops/src/lib.rs b/zero_bin/ops/src/lib.rs index 4de5e0c30..d8d884d8d 100644 --- a/zero_bin/ops/src/lib.rs +++ b/zero_bin/ops/src/lib.rs @@ -27,7 +27,7 @@ pub struct SegmentProof { } impl Operation for SegmentProof { - type Input = evm_arithmetization::AllData; + type Input = evm_arithmetization::AllData; type Output = proof_gen::proof_types::SegmentAggregatableProof; fn execute(&self, all_data: Self::Input) -> Result { @@ -72,7 +72,7 @@ pub struct SegmentProofTestOnly { } impl Operation for SegmentProofTestOnly { - type Input = (GenerationInputs, usize); + type Input = (GenerationInputs, usize); type Output = (); fn execute(&self, inputs: Self::Input) -> Result { @@ -113,7 +113,7 @@ struct SegmentProofSpan { impl SegmentProofSpan { /// Get a unique id for the transaction proof. - fn get_id(ir: &TrimmedGenerationInputs, segment_index: usize) -> String { + fn get_id(ir: &TrimmedGenerationInputs, segment_index: usize) -> String { if ir.txn_hashes.len() == 1 { format!( "b{} - {} ({})", @@ -134,7 +134,7 @@ impl SegmentProofSpan { /// /// Either the first 8 characters of the hex-encoded hash of the first and /// last transactions, or "Dummy" if there is no transaction. - fn get_descriptor(ir: &TrimmedGenerationInputs) -> String { + fn get_descriptor(ir: &TrimmedGenerationInputs) -> String { if ir.txn_hashes.is_empty() { "Dummy".to_string() } else if ir.txn_hashes.len() == 1 { @@ -157,7 +157,7 @@ impl SegmentProofSpan { /// Create a new transaction proof span. /// /// When dropped, it logs the time taken by the transaction proof. - fn new(ir: &TrimmedGenerationInputs, segment_index: usize) -> Self { + fn new(ir: &TrimmedGenerationInputs, segment_index: usize) -> Self { let id = Self::get_id(ir, segment_index); let span = info_span!("p_gen", id).entered(); let start = Instant::now(); @@ -186,7 +186,7 @@ pub struct SegmentAggProof { pub save_inputs_on_error: bool, } -fn get_seg_agg_proof_public_values(elem: SegmentAggregatableProof) -> PublicValues { +fn get_seg_agg_proof_public_values(elem: SegmentAggregatableProof) -> PublicValues { match elem { SegmentAggregatableProof::Seg(info) => info.p_vals, SegmentAggregatableProof::Agg(info) => info.p_vals, @@ -230,7 +230,7 @@ impl Monoid for SegmentAggProof { pub struct BatchAggProof { pub save_inputs_on_error: bool, } -fn get_agg_proof_public_values(elem: BatchAggregatableProof) -> PublicValues { +fn get_agg_proof_public_values(elem: BatchAggregatableProof) -> PublicValues { match elem { BatchAggregatableProof::Segment(info) => info.p_vals, BatchAggregatableProof::Txn(info) => info.p_vals, diff --git a/zero_bin/rpc/Cargo.toml b/zero_bin/rpc/Cargo.toml index 567064763..f47586cd3 100644 --- a/zero_bin/rpc/Cargo.toml +++ b/zero_bin/rpc/Cargo.toml @@ -30,6 +30,7 @@ url = { workspace = true } compat = { workspace = true } evm_arithmetization = { workspace = true } mpt_trie = { workspace = true } +proof_gen = { workspace = true } prover = { workspace = true } trace_decoder = { workspace = true } zero_bin_common = { workspace = true } @@ -43,12 +44,14 @@ vergen = { workspace = true } default = ["eth_mainnet"] eth_mainnet = [ "evm_arithmetization/eth_mainnet", + "proof_gen/eth_mainnet", "prover/eth_mainnet", "trace_decoder/eth_mainnet", "zero_bin_common/eth_mainnet", ] cdk_erigon = [ "evm_arithmetization/cdk_erigon", + "proof_gen/cdk_erigon", "prover/cdk_erigon", "trace_decoder/cdk_erigon", "zero_bin_common/cdk_erigon", diff --git a/zero_bin/rpc/src/jerigon.rs b/zero_bin/rpc/src/jerigon.rs index f23b804c3..00d56cf48 100644 --- a/zero_bin/rpc/src/jerigon.rs +++ b/zero_bin/rpc/src/jerigon.rs @@ -1,6 +1,4 @@ -use alloy::{ - primitives::B256, providers::Provider, rpc::types::eth::BlockId, transports::Transport, -}; +use alloy::{providers::Provider, rpc::types::eth::BlockId, transports::Transport}; use anyhow::Context as _; use prover::BlockProverInput; use serde::Deserialize; @@ -21,7 +19,7 @@ pub struct ZeroTxResult { pub async fn block_prover_input( cached_provider: std::sync::Arc>, target_block_id: BlockId, - checkpoint_state_trie_root: B256, + checkpoint_block_number: u64, ) -> anyhow::Result where ProviderT: Provider, @@ -46,8 +44,7 @@ where .await?; let other_data = - fetch_other_block_data(cached_provider, target_block_id, checkpoint_state_trie_root) - .await?; + fetch_other_block_data(cached_provider, target_block_id, checkpoint_block_number).await?; // Assemble Ok(BlockProverInput { diff --git a/zero_bin/rpc/src/lib.rs b/zero_bin/rpc/src/lib.rs index 58df5430a..9da6862f3 100644 --- a/zero_bin/rpc/src/lib.rs +++ b/zero_bin/rpc/src/lib.rs @@ -9,8 +9,9 @@ use alloy::{ use anyhow::{anyhow, Context as _}; use clap::ValueEnum; use compat::Compat; -use evm_arithmetization::proof::{BlockHashes, BlockMetadata}; +use evm_arithmetization::proof::{consolidate_hashes, BlockHashes, BlockMetadata}; use futures::{StreamExt as _, TryStreamExt as _}; +use proof_gen::types::{Field, Hasher}; use prover::BlockProverInput; use serde_json::json; use trace_decoder::{BlockLevelData, OtherBlockData}; @@ -37,7 +38,7 @@ pub enum RpcType { pub async fn block_prover_input( cached_provider: Arc>, block_id: BlockId, - checkpoint_state_trie_root: B256, + checkpoint_block_number: u64, rpc_type: RpcType, ) -> Result where @@ -46,10 +47,10 @@ where { match rpc_type { RpcType::Jerigon => { - jerigon::block_prover_input(cached_provider, block_id, checkpoint_state_trie_root).await + jerigon::block_prover_input(cached_provider, block_id, checkpoint_block_number).await } RpcType::Native => { - native::block_prover_input(cached_provider, block_id, checkpoint_state_trie_root).await + native::block_prover_input(cached_provider, block_id, checkpoint_block_number).await } } } @@ -63,7 +64,6 @@ where TransportT: Transport + Clone, { use itertools::Itertools; - // For one block, we will fetch 128 previous blocks to get hashes instead of // 256. But for two consecutive blocks (odd and even) we would fetch 256 // previous blocks in total. To overcome this, we add an offset so that we @@ -198,7 +198,7 @@ where async fn fetch_other_block_data( cached_provider: Arc>, target_block_id: BlockId, - checkpoint_state_trie_root: B256, + checkpoint_block_number: u64, ) -> anyhow::Result where ProviderT: Provider, @@ -209,7 +209,23 @@ where .await?; let target_block_number = target_block.header.number; let chain_id = cached_provider.get_provider().await?.get_chain_id().await?; - let prev_hashes = fetch_previous_block_hashes(cached_provider, target_block_number).await?; + + // Grab interval checkpoint block state trie + let checkpoint_state_trie_root = cached_provider + .get_block( + checkpoint_block_number.into(), + BlockTransactionsKind::Hashes, + ) + .await? + .header + .state_root; + + let prev_hashes = + fetch_previous_block_hashes(cached_provider.clone(), target_block_number).await?; + let checkpoint_prev_hashes = + fetch_previous_block_hashes(cached_provider, checkpoint_block_number + 1) // include the checkpoint block + .await? + .map(|it| it.compat()); let other_data = OtherBlockData { b_data: BlockLevelData { @@ -264,6 +280,7 @@ where .collect(), }, checkpoint_state_trie_root: checkpoint_state_trie_root.compat(), + checkpoint_consolidated_hash: consolidate_hashes::(&checkpoint_prev_hashes), }; Ok(other_data) } diff --git a/zero_bin/rpc/src/main.rs b/zero_bin/rpc/src/main.rs index 8f860689f..a88c8256c 100644 --- a/zero_bin/rpc/src/main.rs +++ b/zero_bin/rpc/src/main.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use alloy::primitives::B256; use alloy::providers::Provider; use alloy::rpc::types::eth::BlockId; -use alloy::rpc::types::{BlockNumberOrTag, BlockTransactionsKind}; +use alloy::rpc::types::BlockNumberOrTag; use alloy::transports::Transport; use anyhow::anyhow; use clap::{Args, Parser, Subcommand, ValueHint}; @@ -90,16 +90,6 @@ where .unwrap_or(params.start_block - 1); check_previous_proof_and_checkpoint(checkpoint_block_number, &None, params.start_block)?; - // Grab interval checkpoint block state trie - let checkpoint_state_trie_root = cached_provider - .get_block( - BlockId::Number(checkpoint_block_number.into()), - BlockTransactionsKind::Hashes, - ) - .await? - .header - .state_root; - let block_interval = BlockInterval::Range(params.start_block..params.end_block + 1); let mut block_prover_inputs = Vec::new(); let mut block_interval: BlockIntervalStream = block_interval.into_bounded_stream()?; @@ -110,7 +100,7 @@ where let result = rpc::block_prover_input( cached_provider.clone(), block_id, - checkpoint_state_trie_root, + checkpoint_block_number, params.rpc_type, ) .await?; diff --git a/zero_bin/rpc/src/native/mod.rs b/zero_bin/rpc/src/native/mod.rs index 728a4f209..2e9527274 100644 --- a/zero_bin/rpc/src/native/mod.rs +++ b/zero_bin/rpc/src/native/mod.rs @@ -3,7 +3,6 @@ use std::ops::Deref; use std::sync::Arc; use alloy::{ - primitives::B256, providers::Provider, rpc::types::eth::{BlockId, BlockTransactionsKind}, transports::Transport, @@ -22,7 +21,7 @@ type CodeDb = BTreeSet>; pub async fn block_prover_input( provider: Arc>, block_number: BlockId, - checkpoint_state_trie_root: B256, + checkpoint_block_number: u64, ) -> anyhow::Result where ProviderT: Provider, @@ -30,7 +29,7 @@ where { let (block_trace, other_data) = try_join!( process_block_trace(provider.clone(), block_number), - crate::fetch_other_block_data(provider.clone(), block_number, checkpoint_state_trie_root,) + crate::fetch_other_block_data(provider.clone(), block_number, checkpoint_block_number) )?; Ok(BlockProverInput { diff --git a/zero_bin/tools/artifacts/witness_b19807080.json b/zero_bin/tools/artifacts/witness_b19807080.json index aa653083a..cb84f56e1 100644 --- a/zero_bin/tools/artifacts/witness_b19807080.json +++ b/zero_bin/tools/artifacts/witness_b19807080.json @@ -1010,7 +1010,13 @@ ] ] }, - "checkpoint_state_trie_root": "0xbbd66174555d27c88e285ff4797de401470d8d2486d15513ab36e491e864bca2" + "checkpoint_state_trie_root": "0xbbd66174555d27c88e285ff4797de401470d8d2486d15513ab36e491e864bca2", + "checkpoint_consolidated_hash": [ + 7715853179812774584, + 12908177954576181071, + 11068935829000177885, + 16446535885506885907 + ] } } -] +] \ No newline at end of file diff --git a/zero_bin/tools/artifacts/witness_b3_b6.json b/zero_bin/tools/artifacts/witness_b3_b6.json index a40735b22..65f2e69de 100644 --- a/zero_bin/tools/artifacts/witness_b3_b6.json +++ b/zero_bin/tools/artifacts/witness_b3_b6.json @@ -297,7 +297,13 @@ }, "withdrawals": [] }, - "checkpoint_state_trie_root": "0xfa446f2a9bf579b0ea805b88e3ee2acf601573f6ff48baaa8880915613aec508" + "checkpoint_state_trie_root": "0xfa446f2a9bf579b0ea805b88e3ee2acf601573f6ff48baaa8880915613aec508", + "checkpoint_consolidated_hash": [ + 11109195215272999485, + 17437738218251795093, + 11926305777431453557, + 9928709665788626500 + ] } }, { @@ -612,7 +618,13 @@ }, "withdrawals": [] }, - "checkpoint_state_trie_root": "0xfa446f2a9bf579b0ea805b88e3ee2acf601573f6ff48baaa8880915613aec508" + "checkpoint_state_trie_root": "0xfa446f2a9bf579b0ea805b88e3ee2acf601573f6ff48baaa8880915613aec508", + "checkpoint_consolidated_hash": [ + 11109195215272999485, + 17437738218251795093, + 11926305777431453557, + 9928709665788626500 + ] } }, { @@ -927,7 +939,13 @@ }, "withdrawals": [] }, - "checkpoint_state_trie_root": "0xfa446f2a9bf579b0ea805b88e3ee2acf601573f6ff48baaa8880915613aec508" + "checkpoint_state_trie_root": "0xfa446f2a9bf579b0ea805b88e3ee2acf601573f6ff48baaa8880915613aec508", + "checkpoint_consolidated_hash": [ + 11109195215272999485, + 17437738218251795093, + 11926305777431453557, + 9928709665788626500 + ] } }, { @@ -1284,7 +1302,13 @@ }, "withdrawals": [] }, - "checkpoint_state_trie_root": "0xfa446f2a9bf579b0ea805b88e3ee2acf601573f6ff48baaa8880915613aec508" + "checkpoint_state_trie_root": "0xfa446f2a9bf579b0ea805b88e3ee2acf601573f6ff48baaa8880915613aec508", + "checkpoint_consolidated_hash": [ + 11109195215272999485, + 17437738218251795093, + 11926305777431453557, + 9928709665788626500 + ] } } -] +] \ No newline at end of file