From bfcfcdb498d253ff33121dba03a130be89fcc96c Mon Sep 17 00:00:00 2001 From: Robin Salen <30937548+Nashtare@users.noreply.github.com> Date: Sat, 9 Dec 2023 06:26:55 +0100 Subject: [PATCH] Add `Checkpoint` heights (#1418) --- evm/src/fixed_recursive_verifier.rs | 143 +++++++++++++++++++++------- evm/src/generation/mod.rs | 9 +- evm/src/get_challenges.rs | 4 +- evm/src/proof.rs | 32 +++---- evm/src/recursive_verifier.rs | 8 +- evm/tests/add11_yml.rs | 2 +- evm/tests/basic_smart_contract.rs | 2 +- evm/tests/empty_txn_list.rs | 2 +- evm/tests/erc20.rs | 2 +- evm/tests/log_opcode.rs | 106 +++++++++++++++++---- evm/tests/self_balance_gas_cost.rs | 2 +- evm/tests/selfdestruct.rs | 2 +- evm/tests/simple_transfer.rs | 2 +- evm/tests/withdrawals.rs | 2 +- 14 files changed, 233 insertions(+), 85 deletions(-) diff --git a/evm/src/fixed_recursive_verifier.rs b/evm/src/fixed_recursive_verifier.rs index 53de19f805..87f076c1b5 100644 --- a/evm/src/fixed_recursive_verifier.rs +++ b/evm/src/fixed_recursive_verifier.rs @@ -37,7 +37,7 @@ use crate::generation::GenerationInputs; use crate::get_challenges::observe_public_values_target; use crate::proof::{ BlockHashesTarget, BlockMetadataTarget, ExtraBlockData, ExtraBlockDataTarget, PublicValues, - PublicValuesTarget, StarkProofWithMetadata, TrieRootsTarget, + PublicValuesTarget, StarkProofWithMetadata, TrieRoots, TrieRootsTarget, }; use crate::prover::prove; use crate::recursive_verifier::{ @@ -715,18 +715,18 @@ where lhs: &ExtraBlockDataTarget, rhs: &ExtraBlockDataTarget, ) { - // Connect genesis state root values. + // Connect checkpoint state root values. for (&limb0, &limb1) in pvs - .genesis_state_trie_root + .checkpoint_state_trie_root .iter() - .zip(&rhs.genesis_state_trie_root) + .zip(&rhs.checkpoint_state_trie_root) { builder.connect(limb0, limb1); } for (&limb0, &limb1) in pvs - .genesis_state_trie_root + .checkpoint_state_trie_root .iter() - .zip(&lhs.genesis_state_trie_root) + .zip(&lhs.checkpoint_state_trie_root) { builder.connect(limb0, limb1); } @@ -790,6 +790,34 @@ where let parent_pv = PublicValuesTarget::from_public_inputs(&parent_block_proof.public_inputs); let agg_pv = PublicValuesTarget::from_public_inputs(&agg_root_proof.public_inputs); + // Connect block `trie_roots_before` with parent_pv `trie_roots_before`. + TrieRootsTarget::connect( + &mut builder, + public_values.trie_roots_before, + parent_pv.trie_roots_before, + ); + // Connect the rest of block `public_values` with agg_pv. + TrieRootsTarget::connect( + &mut builder, + public_values.trie_roots_after, + agg_pv.trie_roots_after, + ); + BlockMetadataTarget::connect( + &mut builder, + public_values.block_metadata, + agg_pv.block_metadata, + ); + BlockHashesTarget::connect( + &mut builder, + public_values.block_hashes, + agg_pv.block_hashes, + ); + ExtraBlockDataTarget::connect( + &mut builder, + public_values.extra_block_data, + agg_pv.extra_block_data, + ); + // Make connections between block proofs, and check initial and final block values. Self::connect_block_proof(&mut builder, has_parent_block, &parent_pv, &agg_pv); @@ -855,12 +883,12 @@ where builder.connect(limb0, limb1); } - // Between blocks, the genesis state trie remains unchanged. + // Between blocks, the checkpoint state trie remains unchanged. for (&limb0, limb1) in lhs .extra_block_data - .genesis_state_trie_root + .checkpoint_state_trie_root .iter() - .zip(rhs.extra_block_data.genesis_state_trie_root) + .zip(rhs.extra_block_data.checkpoint_state_trie_root) { builder.connect(limb0, limb1); } @@ -878,15 +906,11 @@ where let has_not_parent_block = builder.sub(one, has_parent_block.target); - // Check that the genesis block number is 0. - let gen_block_constr = builder.mul(has_not_parent_block, lhs.block_metadata.block_number); - builder.assert_zero(gen_block_constr); - - // Check that the genesis block has the predetermined state trie root in `ExtraBlockData`. - Self::connect_genesis_block(builder, rhs, has_not_parent_block); + // Check that the checkpoint block has the predetermined state trie root in `ExtraBlockData`. + Self::connect_checkpoint_block(builder, rhs, has_not_parent_block); } - fn connect_genesis_block( + fn connect_checkpoint_block( builder: &mut CircuitBuilder, x: &PublicValuesTarget, has_not_parent_block: Target, @@ -897,7 +921,7 @@ where .trie_roots_before .state_root .iter() - .zip(x.extra_block_data.genesis_state_trie_root) + .zip(x.extra_block_data.checkpoint_state_trie_root) { let mut constr = builder.sub(limb0, limb1); constr = builder.mul(has_not_parent_block, constr); @@ -1026,7 +1050,9 @@ where trie_roots_before: lhs_public_values.trie_roots_before, trie_roots_after: rhs_public_values.trie_roots_after, extra_block_data: ExtraBlockData { - genesis_state_trie_root: lhs_public_values.extra_block_data.genesis_state_trie_root, + checkpoint_state_trie_root: lhs_public_values + .extra_block_data + .checkpoint_state_trie_root, txn_number_before: lhs_public_values.extra_block_data.txn_number_before, txn_number_after: rhs_public_values.extra_block_data.txn_number_after, gas_used_before: lhs_public_values.extra_block_data.gas_used_before, @@ -1077,42 +1103,66 @@ where block_inputs .set_proof_with_pis_target(&self.block.parent_block_proof, parent_block_proof); } else { - // Initialize genesis_state_trie, state_root_after, and the previous block hashes for correct connection between blocks. - // Block number does not need to be initialized as genesis block is constrained to have number 0. - if public_values.trie_roots_before.state_root - != public_values.extra_block_data.genesis_state_trie_root + != public_values.extra_block_data.checkpoint_state_trie_root { return Err(anyhow::Error::msg(format!( - "Inconsistent pre-state for first block {:?} with genesis state {:?}.", + "Inconsistent pre-state for first block {:?} with checkpoint state {:?}.", public_values.trie_roots_before.state_root, - public_values.extra_block_data.genesis_state_trie_root, + public_values.extra_block_data.checkpoint_state_trie_root, ))); } - // Initialize `state_root_after`. + + // Initialize some public inputs for correct connection between the checkpoint block and the current one. + let mut nonzero_pis = HashMap::new(); + + // Initialize the checkpoint block roots before, and state root after. + let state_trie_root_before_keys = 0..TrieRootsTarget::HASH_SIZE; + for (key, &value) in state_trie_root_before_keys + .zip_eq(&h256_limbs::(public_values.trie_roots_before.state_root)) + { + nonzero_pis.insert(key, value); + } + let txn_trie_root_before_keys = + TrieRootsTarget::HASH_SIZE..TrieRootsTarget::HASH_SIZE * 2; + for (key, &value) in txn_trie_root_before_keys.clone().zip_eq(&h256_limbs::( + public_values.trie_roots_before.transactions_root, + )) { + nonzero_pis.insert(key, value); + } + let receipts_trie_root_before_keys = + TrieRootsTarget::HASH_SIZE * 2..TrieRootsTarget::HASH_SIZE * 3; + for (key, &value) in receipts_trie_root_before_keys + .clone() + .zip_eq(&h256_limbs::( + public_values.trie_roots_before.receipts_root, + )) + { + nonzero_pis.insert(key, value); + } let state_trie_root_after_keys = TrieRootsTarget::SIZE..TrieRootsTarget::SIZE + TrieRootsTarget::HASH_SIZE; - let mut nonzero_pis = HashMap::new(); for (key, &value) in state_trie_root_after_keys .zip_eq(&h256_limbs::(public_values.trie_roots_before.state_root)) { nonzero_pis.insert(key, value); } - // Initialize the genesis state trie digest. - let genesis_state_trie_keys = + // Initialize the checkpoint state root extra data. + let checkpoint_state_trie_keys = TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE + BlockHashesTarget::SIZE ..TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE + BlockHashesTarget::SIZE + 8; - for (key, &value) in genesis_state_trie_keys.zip_eq(&h256_limbs::( - public_values.extra_block_data.genesis_state_trie_root, + for (key, &value) in checkpoint_state_trie_keys.zip_eq(&h256_limbs::( + public_values.extra_block_data.checkpoint_state_trie_root, )) { nonzero_pis.insert(key, value); } - // Initialize block hashes. + // Initialize checkpoint block hashes. + // These will be all zeros the initial genesis checkpoint. let block_hashes_keys = TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE ..TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE + BlockHashesTarget::SIZE - 8; @@ -1130,6 +1180,14 @@ where nonzero_pis.insert(block_hashes_current_start + i, cur_targets[i]); } + // Initialize the checkpoint block number. + // Subtraction would result in an invalid proof for genesis, but we shouldn't try proving this block anyway. + let block_number_key = TrieRootsTarget::SIZE * 2 + 6; + nonzero_pis.insert( + block_number_key, + F::from_canonical_u64(public_values.block_metadata.block_number.low_u64() - 1), + ); + block_inputs.set_proof_with_pis_target( &self.block.parent_block_proof, &cyclic_base_proof( @@ -1145,13 +1203,26 @@ where block_inputs .set_verifier_data_target(&self.block.cyclic_vk, &self.block.circuit.verifier_only); - set_public_value_targets(&mut block_inputs, &self.block.public_values, &public_values) - .map_err(|_| { - anyhow::Error::msg("Invalid conversion when setting public values targets.") - })?; + // This is basically identical to this block public values, apart from the `trie_roots_before` + // that may come from the previous proof, if any. + let block_public_values = PublicValues { + trie_roots_before: opt_parent_block_proof + .map(|p| TrieRoots::from_public_inputs(&p.public_inputs[0..TrieRootsTarget::SIZE])) + .unwrap_or(public_values.trie_roots_before), + ..public_values + }; + + set_public_value_targets( + &mut block_inputs, + &self.block.public_values, + &block_public_values, + ) + .map_err(|_| { + anyhow::Error::msg("Invalid conversion when setting public values targets.") + })?; let block_proof = self.block.circuit.prove(block_inputs)?; - Ok((block_proof, public_values)) + Ok((block_proof, block_public_values)) } pub fn verify_block(&self, block_proof: &ProofWithPublicInputs) -> anyhow::Result<()> { diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index db4a40476b..77b6fd36d7 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -50,8 +50,11 @@ pub struct GenerationInputs { pub tries: TrieInputs, /// Expected trie roots after the transactions are executed. pub trie_roots_after: TrieRoots, - /// State trie root of the genesis block. - pub genesis_state_trie_root: H256, + + /// State trie root of the checkpoint block. + /// This could always be the genesis block of the chain, but it allows a prover to continue proving blocks + /// from certain checkpoint heights without requiring proofs for blocks past this checkpoint. + pub checkpoint_state_trie_root: H256, /// Mapping between smart contract code hashes and the contract byte code. /// All account smart contracts that are invoked will have an entry present. @@ -218,7 +221,7 @@ pub fn generate_traces, const D: usize>( let trie_root_ptrs = state.trie_root_ptrs; let extra_block_data = ExtraBlockData { - genesis_state_trie_root: inputs.genesis_state_trie_root, + checkpoint_state_trie_root: inputs.checkpoint_state_trie_root, txn_number_before: inputs.txn_number_before, txn_number_after, gas_used_before: inputs.gas_used_before, diff --git a/evm/src/get_challenges.rs b/evm/src/get_challenges.rs index ae23679900..756b0650da 100644 --- a/evm/src/get_challenges.rs +++ b/evm/src/get_challenges.rs @@ -104,7 +104,7 @@ fn observe_extra_block_data< challenger: &mut Challenger, extra_data: &ExtraBlockData, ) -> Result<(), ProgramError> { - challenger.observe_elements(&h256_limbs(extra_data.genesis_state_trie_root)); + challenger.observe_elements(&h256_limbs(extra_data.checkpoint_state_trie_root)); 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)?); @@ -123,7 +123,7 @@ fn observe_extra_block_data_target< ) where C::Hasher: AlgebraicHasher, { - challenger.observe_elements(&extra_data.genesis_state_trie_root); + challenger.observe_elements(&extra_data.checkpoint_state_trie_root); challenger.observe_element(extra_data.txn_number_before); challenger.observe_element(extra_data.txn_number_after); challenger.observe_element(extra_data.gas_used_before); diff --git a/evm/src/proof.rs b/evm/src/proof.rs index 6901f2c876..a5bf57566e 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -232,8 +232,8 @@ impl BlockMetadata { /// unlike `BlockMetadata`. #[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)] pub struct ExtraBlockData { - /// The state trie digest of the genesis block. - pub genesis_state_trie_root: H256, + /// The state trie digest of the checkpoint block. + pub checkpoint_state_trie_root: H256, /// 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, @@ -251,14 +251,14 @@ impl ExtraBlockData { pub fn from_public_inputs(pis: &[F]) -> Self { assert!(pis.len() == ExtraBlockDataTarget::SIZE); - let genesis_state_trie_root = get_h256(&pis[0..8]); + 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(); Self { - genesis_state_trie_root, + checkpoint_state_trie_root, txn_number_before, txn_number_after, gas_used_before, @@ -338,13 +338,13 @@ impl PublicValuesTarget { buffer.write_target_array(&cur_hash)?; let ExtraBlockDataTarget { - genesis_state_trie_root: genesis_state_root, + checkpoint_state_trie_root, txn_number_before, txn_number_after, gas_used_before, gas_used_after, } = self.extra_block_data; - buffer.write_target_array(&genesis_state_root)?; + buffer.write_target_array(&checkpoint_state_trie_root)?; buffer.write_target(txn_number_before)?; buffer.write_target(txn_number_after)?; buffer.write_target(gas_used_before)?; @@ -386,7 +386,7 @@ impl PublicValuesTarget { }; let extra_block_data = ExtraBlockDataTarget { - genesis_state_trie_root: buffer.read_target_array()?, + checkpoint_state_trie_root: buffer.read_target_array()?, txn_number_before: buffer.read_target()?, txn_number_after: buffer.read_target()?, gas_used_before: buffer.read_target()?, @@ -740,8 +740,8 @@ impl BlockHashesTarget { /// unlike `BlockMetadata`. #[derive(Eq, PartialEq, Debug, Copy, Clone)] pub(crate) struct ExtraBlockDataTarget { - /// `Target`s for the state trie digest of the genesis block. - pub genesis_state_trie_root: [Target; 8], + /// `Target`s for the state trie digest of the checkpoint block. + pub checkpoint_state_trie_root: [Target; 8], /// `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, @@ -762,14 +762,14 @@ impl ExtraBlockDataTarget { /// 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 genesis_state_trie_root = pis[0..8].try_into().unwrap(); + 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]; Self { - genesis_state_trie_root, + checkpoint_state_trie_root, txn_number_before, txn_number_after, gas_used_before, @@ -786,11 +786,11 @@ impl ExtraBlockDataTarget { ed1: Self, ) -> Self { Self { - genesis_state_trie_root: core::array::from_fn(|i| { + checkpoint_state_trie_root: core::array::from_fn(|i| { builder.select( condition, - ed0.genesis_state_trie_root[i], - ed1.genesis_state_trie_root[i], + ed0.checkpoint_state_trie_root[i], + ed1.checkpoint_state_trie_root[i], ) }), txn_number_before: builder.select( @@ -812,8 +812,8 @@ impl ExtraBlockDataTarget { ) { for i in 0..8 { builder.connect( - ed0.genesis_state_trie_root[i], - ed1.genesis_state_trie_root[i], + ed0.checkpoint_state_trie_root[i], + ed1.checkpoint_state_trie_root[i], ); } builder.connect(ed0.txn_number_before, ed1.txn_number_before); diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 9732ba639a..3103dd49b9 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -712,13 +712,13 @@ pub(crate) fn add_virtual_block_hashes, const D: us pub(crate) fn add_virtual_extra_block_data, const D: usize>( builder: &mut CircuitBuilder, ) -> ExtraBlockDataTarget { - let genesis_state_trie_root = builder.add_virtual_public_input_arr(); + let checkpoint_state_trie_root = 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(); let gas_used_after = builder.add_virtual_public_input(); ExtraBlockDataTarget { - genesis_state_trie_root, + checkpoint_state_trie_root, txn_number_before, txn_number_after, gas_used_before, @@ -979,8 +979,8 @@ where W: Witness, { witness.set_target_arr( - &ed_target.genesis_state_trie_root, - &h256_limbs::(ed.genesis_state_trie_root), + &ed_target.checkpoint_state_trie_root, + &h256_limbs::(ed.checkpoint_state_trie_root), ); witness.set_target( ed_target.txn_number_before, diff --git a/evm/tests/add11_yml.rs b/evm/tests/add11_yml.rs index ab08fd0295..040750fa58 100644 --- a/evm/tests/add11_yml.rs +++ b/evm/tests/add11_yml.rs @@ -157,7 +157,7 @@ fn add11_yml() -> anyhow::Result<()> { trie_roots_after, contract_code, block_metadata, - genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), txn_number_before: 0.into(), gas_used_before: 0.into(), gas_used_after: 0xa868u64.into(), diff --git a/evm/tests/basic_smart_contract.rs b/evm/tests/basic_smart_contract.rs index c520793f15..28db58ed54 100644 --- a/evm/tests/basic_smart_contract.rs +++ b/evm/tests/basic_smart_contract.rs @@ -188,7 +188,7 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { tries: tries_before, trie_roots_after, contract_code, - genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm/tests/empty_txn_list.rs b/evm/tests/empty_txn_list.rs index 17e9b7bfd0..684a8f3625 100644 --- a/evm/tests/empty_txn_list.rs +++ b/evm/tests/empty_txn_list.rs @@ -63,7 +63,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> { }, trie_roots_after, contract_code, - genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm/tests/erc20.rs b/evm/tests/erc20.rs index a71049f74a..9c4bfa8353 100644 --- a/evm/tests/erc20.rs +++ b/evm/tests/erc20.rs @@ -164,7 +164,7 @@ fn test_erc20() -> anyhow::Result<()> { tries: tries_before, trie_roots_after, contract_code, - genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm/tests/log_opcode.rs b/evm/tests/log_opcode.rs index bc50c4cd9d..b00fe36f9e 100644 --- a/evm/tests/log_opcode.rs +++ b/evm/tests/log_opcode.rs @@ -221,7 +221,7 @@ fn test_log_opcodes() -> anyhow::Result<()> { tries: tries_before, trie_roots_after, contract_code, - genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), @@ -324,7 +324,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { to_second_nibbles, rlp::encode(&to_account_second_before).to_vec(), ); - let genesis_state_trie_root = state_trie_before.hash(); + let checkpoint_state_trie_root = state_trie_before.hash(); let tries_before = TrieInputs { state_trie: state_trie_before, @@ -335,7 +335,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { let txn = hex!("f85f800a82520894095e7baea6a6c7c4c2dfeb977efac326af552d870a8026a0122f370ed4023a6c253350c6bfb87d7d7eb2cd86447befee99e0a26b70baec20a07100ab1b3977f2b4571202b9f4b68850858caf5469222794600b5ce1cfb348ad"); - let block_metadata = BlockMetadata { + let block_1_metadata = BlockMetadata { block_beneficiary: Address::from(beneficiary), block_timestamp: 0x03e8.into(), block_number: 1.into(), @@ -420,27 +420,31 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { receipts_root: receipts_trie.clone().hash(), }; + let block_1_hash = + H256::from_str("0x0101010101010101010101010101010101010101010101010101010101010101")?; + let mut block_hashes = vec![H256::default(); 256]; + let inputs_first = GenerationInputs { signed_txn: Some(txn.to_vec()), withdrawals: vec![], tries: tries_before, trie_roots_after: tries_after, contract_code, - genesis_state_trie_root, - block_metadata: block_metadata.clone(), + checkpoint_state_trie_root, + block_metadata: block_1_metadata.clone(), txn_number_before: 0.into(), gas_used_before: 0.into(), gas_used_after: 21000u64.into(), block_hashes: BlockHashes { - prev_hashes: vec![H256::default(); 256], - cur_hash: H256::default(), + prev_hashes: block_hashes.clone(), + cur_hash: block_1_hash, }, }; // Preprocess all circuits. let all_circuits = AllRecursiveCircuits::::new( &all_stark, - &[16..17, 14..16, 16..18, 14..15, 9..10, 12..13, 19..20], + &[16..17, 13..16, 15..18, 14..15, 9..10, 12..13, 17..20], &config, ); @@ -539,8 +543,10 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { transactions_trie.insert(Nibbles::from_str("0x01").unwrap(), txn_2.to_vec()); + let block_1_state_root = expected_state_trie_after.hash(); + let trie_roots_after = TrieRoots { - state_root: expected_state_trie_after.hash(), + state_root: block_1_state_root, transactions_root: transactions_trie.hash(), receipts_root: receipts_trie.hash(), }; @@ -549,16 +555,16 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { signed_txn: Some(txn_2.to_vec()), withdrawals: vec![], tries: tries_before, - trie_roots_after, + trie_roots_after: trie_roots_after.clone(), contract_code, - genesis_state_trie_root, - block_metadata, + checkpoint_state_trie_root, + block_metadata: block_1_metadata, txn_number_before: 1.into(), gas_used_before: gas_used_second, gas_used_after: receipt.cum_gas_used, block_hashes: BlockHashes { - prev_hashes: vec![H256::default(); 256], - cur_hash: H256::default(), + prev_hashes: block_hashes.clone(), + cur_hash: block_1_hash, }, }; @@ -578,9 +584,77 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { public_values_second, )?; all_circuits.verify_aggregation(&agg_proof)?; - let (block_proof, _block_public_values) = + let (first_block_proof, _block_public_values) = all_circuits.prove_block(None, &agg_proof, updated_agg_public_values)?; - all_circuits.verify_block(&block_proof) + all_circuits.verify_block(&first_block_proof)?; + + // Prove the next, empty block. + + let block_2_hash = + H256::from_str("0x0123456789101112131415161718192021222324252627282930313233343536")?; + block_hashes[255] = block_1_hash; + + let block_2_metadata = BlockMetadata { + block_beneficiary: Address::from(beneficiary), + block_timestamp: 0x03e8.into(), + block_number: 2.into(), + block_difficulty: 0x020000.into(), + block_gaslimit: 0x445566u32.into(), + block_chain_id: 1.into(), + block_base_fee: 0xa.into(), + ..Default::default() + }; + + let mut contract_code = HashMap::new(); + contract_code.insert(keccak(vec![]), vec![]); + + let inputs = GenerationInputs { + signed_txn: None, + withdrawals: vec![], + tries: TrieInputs { + state_trie: expected_state_trie_after, + transactions_trie: Node::Empty.into(), + receipts_trie: Node::Empty.into(), + storage_tries: vec![], + }, + trie_roots_after: TrieRoots { + state_root: trie_roots_after.state_root, + transactions_root: HashedPartialTrie::from(Node::Empty).hash(), + receipts_root: HashedPartialTrie::from(Node::Empty).hash(), + }, + contract_code, + checkpoint_state_trie_root: block_1_state_root, // We use block 1 as new checkpoint. + block_metadata: block_2_metadata, + txn_number_before: 0.into(), + gas_used_before: 0.into(), + gas_used_after: 0.into(), + block_hashes: BlockHashes { + prev_hashes: block_hashes, + cur_hash: block_2_hash, + }, + }; + + let (root_proof, public_values) = + all_circuits.prove_root(&all_stark, &config, inputs, &mut timing)?; + all_circuits.verify_root(root_proof.clone())?; + + // We can just duplicate the initial proof as the state didn't change. + let (agg_proof, updated_agg_public_values) = all_circuits.prove_aggregation( + false, + &root_proof, + public_values.clone(), + false, + &root_proof, + public_values, + )?; + all_circuits.verify_aggregation(&agg_proof)?; + + let (second_block_proof, _block_public_values) = all_circuits.prove_block( + None, // We don't specify a previous proof, considering block 1 as the new checkpoint. + &agg_proof, + updated_agg_public_values, + )?; + all_circuits.verify_block(&second_block_proof) } /// Values taken from the block 1000000 of Goerli: https://goerli.etherscan.io/txs?block=1000000 diff --git a/evm/tests/self_balance_gas_cost.rs b/evm/tests/self_balance_gas_cost.rs index 2ddb01030e..7346dc2487 100644 --- a/evm/tests/self_balance_gas_cost.rs +++ b/evm/tests/self_balance_gas_cost.rs @@ -175,7 +175,7 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { tries: tries_before, trie_roots_after, contract_code, - genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm/tests/selfdestruct.rs b/evm/tests/selfdestruct.rs index 03879de12f..fb33b18fb2 100644 --- a/evm/tests/selfdestruct.rs +++ b/evm/tests/selfdestruct.rs @@ -127,7 +127,7 @@ fn test_selfdestruct() -> anyhow::Result<()> { tries: tries_before, trie_roots_after, contract_code, - genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm/tests/simple_transfer.rs b/evm/tests/simple_transfer.rs index 7ef1d61a7e..ede18bf809 100644 --- a/evm/tests/simple_transfer.rs +++ b/evm/tests/simple_transfer.rs @@ -143,7 +143,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { tries: tries_before, trie_roots_after, contract_code, - genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(), diff --git a/evm/tests/withdrawals.rs b/evm/tests/withdrawals.rs index 50d490f6e6..29c958170a 100644 --- a/evm/tests/withdrawals.rs +++ b/evm/tests/withdrawals.rs @@ -73,7 +73,7 @@ fn test_withdrawals() -> anyhow::Result<()> { }, trie_roots_after, contract_code, - genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), + checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), block_metadata, txn_number_before: 0.into(), gas_used_before: 0.into(),