Write trie roots to memory before kernel bootstrapping (#1172)

* Write trie roots

* Remove CPU trace length

* Update hash_initial/final_tries

* Fix tests

* Minor

* PR feedback
This commit is contained in:
wborgeaud 2023-08-09 10:15:13 +02:00 committed by GitHub
parent c9eed2bbf9
commit df07ae093a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 203 additions and 255 deletions

View File

@ -7,9 +7,9 @@ global main:
%jump(load_all_mpts)
global hash_initial_tries:
%mpt_hash_state_trie %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_DIGEST_BEFORE)
%mpt_hash_txn_trie %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_BEFORE)
%mpt_hash_receipt_trie %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_BEFORE)
%mpt_hash_state_trie %mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_DIGEST_BEFORE) %assert_eq
%mpt_hash_txn_trie %mload_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_BEFORE) %assert_eq
%mpt_hash_receipt_trie %mload_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_BEFORE) %assert_eq
global txn_loop:
// If the prover has no more txns for us to process, halt.
@ -21,7 +21,7 @@ global txn_loop:
%jump(route_txn)
global hash_final_tries:
%mpt_hash_state_trie %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_DIGEST_AFTER)
%mpt_hash_txn_trie %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_AFTER)
%mpt_hash_receipt_trie %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_AFTER)
%mpt_hash_state_trie %mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_DIGEST_AFTER) %assert_eq
%mpt_hash_txn_trie %mload_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_AFTER) %assert_eq
%mpt_hash_receipt_trie %mload_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_AFTER) %assert_eq
%jump(halt)

View File

@ -38,7 +38,7 @@ use crate::keccak_sponge::keccak_sponge_stark::KeccakSpongeStark;
use crate::logic::LogicStark;
use crate::memory::memory_stark::MemoryStark;
use crate::memory::segments::Segment;
use crate::memory::{NUM_CHANNELS, VALUE_LIMBS};
use crate::memory::VALUE_LIMBS;
use crate::permutation::{
get_grand_product_challenge_set_target, GrandProductChallenge, GrandProductChallengeSet,
};
@ -647,7 +647,7 @@ where
prod = builder.mul(prod, combined);
});
// Add public values reads.
// Add trie roots writes.
let trie_fields = [
(
GlobalMetadata::StateTrieRootDigestBefore,
@ -675,15 +675,10 @@ where
),
];
let mut timestamp_target = builder.mul_const(
F::from_canonical_usize(NUM_CHANNELS),
public_values.cpu_trace_len,
);
timestamp_target = builder.add_const(timestamp_target, F::ONE);
trie_fields.map(|(field, targets)| {
let row = builder.add_virtual_targets(13);
// is_read
builder.connect(row[0], one);
builder.connect(row[0], zero);
// context
builder.connect(row[1], zero);
// segment
@ -696,7 +691,7 @@ where
builder.connect(row[4 + j], targets[j]);
}
// timestamp
builder.connect(row[12], timestamp_target);
builder.connect(row[12], one);
let combined = challenge.combine_base_circuit(builder, &row);
prod = builder.mul(prod, combined);
@ -909,10 +904,6 @@ where
&public_values.block_metadata,
);
agg_inputs.set_target(
self.aggregation.public_values.cpu_trace_len,
F::from_canonical_usize(public_values.cpu_trace_len),
);
set_trie_roots_target(
&mut agg_inputs,
&self.aggregation.public_values.trie_roots_before,
@ -977,10 +968,6 @@ where
&public_values.block_metadata,
);
block_inputs.set_target(
self.block.public_values.cpu_trace_len,
F::from_canonical_usize(public_values.cpu_trace_len),
);
set_trie_roots_target(
&mut block_inputs,
&self.block.public_values.trie_roots_before,

View File

@ -1,6 +1,6 @@
use std::collections::HashMap;
use eth_trie_utils::partial_trie::HashedPartialTrie;
use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie};
use ethereum_types::{Address, BigEndianHash, H256, U256};
use plonky2::field::extension::Extendable;
use plonky2::field::polynomial::PolynomialValues;
@ -22,7 +22,8 @@ use crate::generation::outputs::{get_outputs, GenerationOutputs};
use crate::generation::state::GenerationState;
use crate::memory::segments::Segment;
use crate::proof::{BlockMetadata, PublicValues, TrieRoots};
use crate::witness::memory::{MemoryAddress, MemoryChannel, MemoryOp, MemoryOpKind};
use crate::util::h2u;
use crate::witness::memory::{MemoryAddress, MemoryChannel};
use crate::witness::transition::transition;
pub mod mpt;
@ -39,6 +40,8 @@ use crate::witness::util::mem_write_log;
pub struct GenerationInputs {
pub signed_txns: Vec<Vec<u8>>,
pub tries: TrieInputs,
/// Expected trie roots after the transactions are executed.
pub trie_roots_after: TrieRoots,
/// Mapping between smart contract code hashes and the contract byte code.
/// All account smart contracts that are invoked will have an entry present.
@ -73,10 +76,13 @@ pub struct TrieInputs {
pub storage_tries: Vec<(H256, HashedPartialTrie)>,
}
fn apply_metadata_memops<F: RichField + Extendable<D>, const D: usize>(
fn apply_metadata_and_tries_memops<F: RichField + Extendable<D>, const D: usize>(
state: &mut GenerationState<F>,
metadata: &BlockMetadata,
inputs: &GenerationInputs,
) {
let metadata = &inputs.block_metadata;
let tries = &inputs.tries;
let trie_roots_after = &inputs.trie_roots_after;
let fields = [
(
GlobalMetadata::BlockBeneficiary,
@ -88,6 +94,30 @@ fn apply_metadata_memops<F: RichField + Extendable<D>, const D: usize>(
(GlobalMetadata::BlockGasLimit, metadata.block_gaslimit),
(GlobalMetadata::BlockChainId, metadata.block_chain_id),
(GlobalMetadata::BlockBaseFee, metadata.block_base_fee),
(
GlobalMetadata::StateTrieRootDigestBefore,
h2u(tries.state_trie.hash()),
),
(
GlobalMetadata::TransactionTrieRootDigestBefore,
h2u(tries.transactions_trie.hash()),
),
(
GlobalMetadata::ReceiptTrieRootDigestBefore,
h2u(tries.receipts_trie.hash()),
),
(
GlobalMetadata::StateTrieRootDigestAfter,
h2u(trie_roots_after.state_root),
),
(
GlobalMetadata::TransactionTrieRootDigestAfter,
h2u(trie_roots_after.transactions_root),
),
(
GlobalMetadata::ReceiptTrieRootDigestAfter,
h2u(trie_roots_after.receipts_root),
),
];
let channel = MemoryChannel::GeneralPurpose(0);
@ -104,54 +134,6 @@ fn apply_metadata_memops<F: RichField + Extendable<D>, const D: usize>(
state.traces.memory_ops.extend(ops);
}
fn apply_trie_memops<F: RichField + Extendable<D>, const D: usize>(
state: &mut GenerationState<F>,
trie_roots_before: &TrieRoots,
trie_roots_after: &TrieRoots,
) {
let fields = [
(
GlobalMetadata::StateTrieRootDigestBefore,
trie_roots_before.state_root,
),
(
GlobalMetadata::TransactionTrieRootDigestBefore,
trie_roots_before.transactions_root,
),
(
GlobalMetadata::ReceiptTrieRootDigestBefore,
trie_roots_before.receipts_root,
),
(
GlobalMetadata::StateTrieRootDigestAfter,
trie_roots_after.state_root,
),
(
GlobalMetadata::TransactionTrieRootDigestAfter,
trie_roots_after.transactions_root,
),
(
GlobalMetadata::ReceiptTrieRootDigestAfter,
trie_roots_after.receipts_root,
),
];
let channel = MemoryChannel::GeneralPurpose(0);
let ops = fields.map(|(field, hash)| {
let val = hash.into_uint();
MemoryOp::new(
channel,
state.traces.cpu.len(),
MemoryAddress::new(0, Segment::GlobalMetadata, field as usize),
MemoryOpKind::Read,
val,
)
});
state.traces.memory_ops.extend(ops);
}
pub fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
all_stark: &AllStark<F, D>,
inputs: GenerationInputs,
@ -164,7 +146,7 @@ pub fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
)> {
let mut state = GenerationState::<F>::new(inputs.clone(), &KERNEL.code);
apply_metadata_memops(&mut state, &inputs.block_metadata);
apply_metadata_and_tries_memops(&mut state, &inputs);
generate_bootstrap_kernel::<F>(&mut state);
@ -194,13 +176,10 @@ pub fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
receipts_root: H256::from_uint(&read_metadata(ReceiptTrieRootDigestAfter)),
};
apply_trie_memops(&mut state, &trie_roots_before, &trie_roots_after);
let public_values = PublicValues {
trie_roots_before,
trie_roots_after,
block_metadata: inputs.block_metadata,
cpu_trace_len: state.traces.clock(),
};
let tables = timed!(

View File

@ -53,7 +53,6 @@ pub struct PublicValues {
pub trie_roots_before: TrieRoots,
pub trie_roots_after: TrieRoots,
pub block_metadata: BlockMetadata,
pub cpu_trace_len: usize,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
@ -81,7 +80,6 @@ pub struct PublicValuesTarget {
pub trie_roots_before: TrieRootsTarget,
pub trie_roots_after: TrieRootsTarget,
pub block_metadata: BlockMetadataTarget,
pub cpu_trace_len: Target,
}
impl PublicValuesTarget {
@ -124,8 +122,6 @@ impl PublicValuesTarget {
buffer.write_target(block_chain_id)?;
buffer.write_target(block_base_fee)?;
buffer.write_target(self.cpu_trace_len)?;
Ok(())
}
@ -152,18 +148,15 @@ impl PublicValuesTarget {
block_base_fee: buffer.read_target()?,
};
let cpu_trace_len = buffer.read_target()?;
Ok(Self {
trie_roots_before,
trie_roots_after,
block_metadata,
cpu_trace_len,
})
}
pub fn from_public_inputs(pis: &[Target]) -> Self {
assert!(pis.len() > TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE);
assert!(pis.len() > TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE - 1);
Self {
trie_roots_before: TrieRootsTarget::from_public_inputs(&pis[0..TrieRootsTarget::SIZE]),
trie_roots_after: TrieRootsTarget::from_public_inputs(
@ -173,7 +166,6 @@ impl PublicValuesTarget {
&pis[TrieRootsTarget::SIZE * 2
..TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE],
),
cpu_trace_len: pis[TrieRootsTarget::SIZE * 2 + BlockMetadataTarget::SIZE],
}
}
@ -202,7 +194,6 @@ impl PublicValuesTarget {
pv0.block_metadata,
pv1.block_metadata,
),
cpu_trace_len: builder.select(condition, pv0.cpu_trace_len, pv1.cpu_trace_len),
}
}
}

View File

@ -516,12 +516,10 @@ pub(crate) fn add_virtual_public_values<F: RichField + Extendable<D>, const D: u
let trie_roots_before = add_virtual_trie_roots(builder);
let trie_roots_after = add_virtual_trie_roots(builder);
let block_metadata = add_virtual_block_metadata(builder);
let cpu_trace_len = builder.add_virtual_public_input();
PublicValuesTarget {
trie_roots_before,
trie_roots_after,
block_metadata,
cpu_trace_len,
}
}
@ -659,10 +657,6 @@ pub(crate) fn set_public_value_targets<F, W, const D: usize>(
&public_values_target.block_metadata,
&public_values.block_metadata,
);
witness.set_target(
public_values_target.cpu_trace_len,
F::from_canonical_usize(public_values.cpu_trace_len),
);
}
pub(crate) fn set_trie_roots_target<F, W, const D: usize>(

View File

@ -175,3 +175,7 @@ pub(crate) fn biguint_to_mem_vec(x: BigUint) -> Vec<U256> {
}
mem_vec
}
pub(crate) fn h2u(h: H256) -> U256 {
U256::from_big_endian(&h.0)
}

View File

@ -1,7 +1,7 @@
use std::any::type_name;
use anyhow::{ensure, Result};
use ethereum_types::{BigEndianHash, U256};
use ethereum_types::U256;
use plonky2::field::extension::{Extendable, FieldExtension};
use plonky2::field::types::Field;
use plonky2::fri::verifier::verify_fri_proof;
@ -21,12 +21,13 @@ use crate::keccak_sponge::keccak_sponge_stark::KeccakSpongeStark;
use crate::logic::LogicStark;
use crate::memory::memory_stark::MemoryStark;
use crate::memory::segments::Segment;
use crate::memory::{NUM_CHANNELS, VALUE_LIMBS};
use crate::memory::VALUE_LIMBS;
use crate::permutation::{GrandProductChallenge, PermutationCheckVars};
use crate::proof::{
AllProof, AllProofChallenges, PublicValues, StarkOpeningSet, StarkProof, StarkProofChallenges,
};
use crate::stark::Stark;
use crate::util::h2u;
use crate::vanishing_poly::eval_vanishing_poly;
use crate::vars::StarkEvaluationVars;
@ -118,11 +119,9 @@ where
// Memory
extra_looking_products.push(Vec::new());
let cpu_trace_len = 1 << all_proof.stark_proofs[1].proof.recover_degree_bits(config);
for c in 0..config.num_challenges {
extra_looking_products[Table::Memory as usize].push(get_memory_extra_looking_products(
&public_values,
cpu_trace_len,
ctl_challenges.challenges[c],
));
}
@ -137,10 +136,9 @@ where
/// Computes the extra product to multiply to the looked value. It contains memory operations not in the CPU trace:
/// - block metadata writes before kernel bootstrapping,
/// - public values reads at the end of the execution.
/// - trie roots writes before kernel bootstrapping.
pub(crate) fn get_memory_extra_looking_products<F, const D: usize>(
public_values: &PublicValues,
cpu_trace_len: usize,
challenge: GrandProductChallenge<F>,
) -> F
where
@ -148,8 +146,8 @@ where
{
let mut prod = F::ONE;
// Add metadata writes.
let block_fields = [
// Add metadata and tries writes.
let fields = [
(
GlobalMetadata::BlockBeneficiary,
U256::from_big_endian(&public_values.block_metadata.block_beneficiary.0),
@ -178,13 +176,37 @@ where
GlobalMetadata::BlockBaseFee,
public_values.block_metadata.block_base_fee,
),
(
GlobalMetadata::StateTrieRootDigestBefore,
h2u(public_values.trie_roots_before.state_root),
),
(
GlobalMetadata::TransactionTrieRootDigestBefore,
h2u(public_values.trie_roots_before.transactions_root),
),
(
GlobalMetadata::ReceiptTrieRootDigestBefore,
h2u(public_values.trie_roots_before.receipts_root),
),
(
GlobalMetadata::StateTrieRootDigestAfter,
h2u(public_values.trie_roots_after.state_root),
),
(
GlobalMetadata::TransactionTrieRootDigestAfter,
h2u(public_values.trie_roots_after.transactions_root),
),
(
GlobalMetadata::ReceiptTrieRootDigestAfter,
h2u(public_values.trie_roots_after.receipts_root),
),
];
let is_read = F::ZERO;
let context = F::ZERO;
let segment = F::from_canonical_u32(Segment::GlobalMetadata as u32);
let timestamp = F::ONE;
block_fields.map(|(field, val)| {
fields.map(|(field, val)| {
let mut row = vec![F::ZERO; 13];
row[0] = is_read;
row[1] = context;
@ -198,51 +220,6 @@ where
prod *= challenge.combine(row.iter());
});
// Add public values reads.
let trie_fields = [
(
GlobalMetadata::StateTrieRootDigestBefore,
public_values.trie_roots_before.state_root,
),
(
GlobalMetadata::TransactionTrieRootDigestBefore,
public_values.trie_roots_before.transactions_root,
),
(
GlobalMetadata::ReceiptTrieRootDigestBefore,
public_values.trie_roots_before.receipts_root,
),
(
GlobalMetadata::StateTrieRootDigestAfter,
public_values.trie_roots_after.state_root,
),
(
GlobalMetadata::TransactionTrieRootDigestAfter,
public_values.trie_roots_after.transactions_root,
),
(
GlobalMetadata::ReceiptTrieRootDigestAfter,
public_values.trie_roots_after.receipts_root,
),
];
let is_read = F::ONE;
let timestamp = F::from_canonical_usize(cpu_trace_len * NUM_CHANNELS + 1);
trie_fields.map(|(field, hash)| {
let mut row = vec![F::ZERO; 13];
row[0] = is_read;
row[1] = context;
row[2] = segment;
row[3] = F::from_canonical_usize(field as usize);
let val = hash.into_uint();
for j in 0..VALUE_LIMBS {
row[j + 4] = F::from_canonical_u32((val >> (j * 32)).low_u32());
}
row[12] = timestamp;
prod *= challenge.combine(row.iter());
});
prod
}

View File

@ -14,7 +14,7 @@ use plonky2_evm::all_stark::AllStark;
use plonky2_evm::config::StarkConfig;
use plonky2_evm::generation::mpt::AccountRlp;
use plonky2_evm::generation::{GenerationInputs, TrieInputs};
use plonky2_evm::proof::BlockMetadata;
use plonky2_evm::proof::{BlockMetadata, TrieRoots};
use plonky2_evm::prover::prove;
use plonky2_evm::verifier::verify_proof;
use plonky2_evm::Node;
@ -91,9 +91,47 @@ fn add11_yml() -> anyhow::Result<()> {
contract_code.insert(keccak(vec![]), vec![]);
contract_code.insert(code_hash, code.to_vec());
let expected_state_trie_after = {
let beneficiary_account_after = AccountRlp {
nonce: 1.into(),
..AccountRlp::default()
};
let sender_account_after = AccountRlp {
balance: 0xde0b6b3a75be550u64.into(),
nonce: 1.into(),
..AccountRlp::default()
};
let to_account_after = AccountRlp {
balance: 0xde0b6b3a76586a0u64.into(),
code_hash,
// Storage map: { 0 => 2 }
storage_root: HashedPartialTrie::from(Node::Leaf {
nibbles: Nibbles::from_h256_be(keccak([0u8; 32])),
value: vec![2],
})
.hash(),
..AccountRlp::default()
};
let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty);
expected_state_trie_after.insert(
beneficiary_nibbles,
rlp::encode(&beneficiary_account_after).to_vec(),
);
expected_state_trie_after
.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec());
expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec());
expected_state_trie_after
};
let trie_roots_after = TrieRoots {
state_root: expected_state_trie_after.hash(),
transactions_root: tries_before.transactions_trie.hash(), // TODO: Fix this when we have transactions trie.
receipts_root: tries_before.receipts_trie.hash(), // TODO: Fix this when we have receipts trie.
};
let inputs = GenerationInputs {
signed_txns: vec![txn.to_vec()],
tries: tries_before,
trie_roots_after,
contract_code,
block_metadata,
addresses: vec![],
@ -103,40 +141,6 @@ fn add11_yml() -> anyhow::Result<()> {
let proof = prove::<F, C, D>(&all_stark, &config, inputs, &mut timing)?;
timing.filter(Duration::from_millis(100)).print();
let beneficiary_account_after = AccountRlp {
nonce: 1.into(),
..AccountRlp::default()
};
let sender_account_after = AccountRlp {
balance: 0xde0b6b3a75be550u64.into(),
nonce: 1.into(),
..AccountRlp::default()
};
let to_account_after = AccountRlp {
balance: 0xde0b6b3a76586a0u64.into(),
code_hash,
// Storage map: { 0 => 2 }
storage_root: HashedPartialTrie::from(Node::Leaf {
nibbles: Nibbles::from_h256_be(keccak([0u8; 32])),
value: vec![2],
})
.hash(),
..AccountRlp::default()
};
let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty);
expected_state_trie_after.insert(
beneficiary_nibbles,
rlp::encode(&beneficiary_account_after).to_vec(),
);
expected_state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec());
expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec());
assert_eq!(
proof.public_values.trie_roots_after.state_root,
expected_state_trie_after.hash()
);
verify_proof(&all_stark, proof, &config)
}

View File

@ -15,7 +15,7 @@ use plonky2_evm::config::StarkConfig;
use plonky2_evm::cpu::kernel::opcodes::{get_opcode, get_push_opcode};
use plonky2_evm::generation::mpt::AccountRlp;
use plonky2_evm::generation::{GenerationInputs, TrieInputs};
use plonky2_evm::proof::BlockMetadata;
use plonky2_evm::proof::{BlockMetadata, TrieRoots};
use plonky2_evm::prover::prove;
use plonky2_evm::verifier::verify_proof;
use plonky2_evm::Node;
@ -102,18 +102,6 @@ fn test_basic_smart_contract() -> anyhow::Result<()> {
contract_code.insert(keccak(vec![]), vec![]);
contract_code.insert(code_hash, code.to_vec());
let inputs = GenerationInputs {
signed_txns: vec![txn.to_vec()],
tries: tries_before,
contract_code,
block_metadata,
addresses: vec![],
};
let mut timing = TimingTree::new("prove", log::Level::Debug);
let proof = prove::<F, C, D>(&all_stark, &config, inputs, &mut timing)?;
timing.filter(Duration::from_millis(100)).print();
let expected_state_trie_after: HashedPartialTrie = {
let txdata_gas = 2 * 16;
let gas_used = 21_000 + code_gas + txdata_gas;
@ -154,11 +142,23 @@ fn test_basic_smart_contract() -> anyhow::Result<()> {
}
}
.into();
let trie_roots_after = TrieRoots {
state_root: expected_state_trie_after.hash(),
transactions_root: tries_before.transactions_trie.hash(), // TODO: Fix this when we have transactions trie.
receipts_root: tries_before.receipts_trie.hash(), // TODO: Fix this when we have receipts trie.
};
let inputs = GenerationInputs {
signed_txns: vec![txn.to_vec()],
tries: tries_before,
trie_roots_after,
contract_code,
block_metadata,
addresses: vec![],
};
assert_eq!(
proof.public_values.trie_roots_after.state_root,
expected_state_trie_after.hash()
);
let mut timing = TimingTree::new("prove", log::Level::Debug);
let proof = prove::<F, C, D>(&all_stark, &config, inputs, &mut timing)?;
timing.filter(Duration::from_millis(100)).print();
verify_proof(&all_stark, proof, &config)
}

View File

@ -3,7 +3,7 @@ use std::marker::PhantomData;
use std::time::Duration;
use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV};
use eth_trie_utils::partial_trie::HashedPartialTrie;
use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie};
use keccak_hash::keccak;
use log::info;
use plonky2::field::goldilocks_field::GoldilocksField;
@ -14,7 +14,7 @@ use plonky2_evm::all_stark::AllStark;
use plonky2_evm::config::StarkConfig;
use plonky2_evm::fixed_recursive_verifier::AllRecursiveCircuits;
use plonky2_evm::generation::{GenerationInputs, TrieInputs};
use plonky2_evm::proof::BlockMetadata;
use plonky2_evm::proof::{BlockMetadata, TrieRoots};
use plonky2_evm::Node;
type F = GoldilocksField;
@ -40,6 +40,12 @@ fn test_empty_txn_list() -> anyhow::Result<()> {
let mut contract_code = HashMap::new();
contract_code.insert(keccak(vec![]), vec![]);
// No transactions, so no trie roots change.
let trie_roots_after = TrieRoots {
state_root: state_trie.hash(),
transactions_root: transactions_trie.hash(),
receipts_root: receipts_trie.hash(),
};
let inputs = GenerationInputs {
signed_txns: vec![],
tries: TrieInputs {
@ -48,6 +54,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> {
receipts_trie,
storage_tries,
},
trie_roots_after,
contract_code,
block_metadata,
addresses: vec![],

View File

@ -15,7 +15,7 @@ use plonky2_evm::all_stark::AllStark;
use plonky2_evm::config::StarkConfig;
use plonky2_evm::generation::mpt::AccountRlp;
use plonky2_evm::generation::{GenerationInputs, TrieInputs};
use plonky2_evm::proof::BlockMetadata;
use plonky2_evm::proof::{BlockMetadata, TrieRoots};
use plonky2_evm::prover::prove;
use plonky2_evm::verifier::verify_proof;
use plonky2_evm::Node;
@ -87,9 +87,48 @@ fn self_balance_gas_cost() -> anyhow::Result<()> {
contract_code.insert(keccak(vec![]), vec![]);
contract_code.insert(code_hash, code.to_vec());
let expected_state_trie_after = {
let beneficiary_account_after = AccountRlp::default();
let sender_account_after = AccountRlp {
balance: 999999999999999568680u128.into(),
nonce: 1.into(),
..AccountRlp::default()
};
let to_account_after = AccountRlp {
code_hash,
// Storage map: { 1 => 5 }
storage_root: HashedPartialTrie::from(Node::Leaf {
// TODO: Could do keccak(pad32(1))
nibbles: Nibbles::from_str(
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6",
)
.unwrap(),
value: vec![5],
})
.hash(),
..AccountRlp::default()
};
let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty);
expected_state_trie_after.insert(
beneficiary_nibbles,
rlp::encode(&beneficiary_account_after).to_vec(),
);
expected_state_trie_after
.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec());
expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec());
expected_state_trie_after
};
let trie_roots_after = TrieRoots {
state_root: expected_state_trie_after.hash(),
transactions_root: tries_before.transactions_trie.hash(), // TODO: Fix this when we have transactions trie.
receipts_root: tries_before.receipts_trie.hash(), // TODO: Fix this when we have receipts trie.
};
let inputs = GenerationInputs {
signed_txns: vec![txn.to_vec()],
tries: tries_before,
trie_roots_after,
contract_code,
block_metadata,
addresses: vec![],
@ -99,40 +138,6 @@ fn self_balance_gas_cost() -> anyhow::Result<()> {
let proof = prove::<F, C, D>(&all_stark, &config, inputs, &mut timing)?;
timing.filter(Duration::from_millis(100)).print();
let beneficiary_account_after = AccountRlp::default();
let sender_account_after = AccountRlp {
balance: 999999999999999568680u128.into(),
nonce: 1.into(),
..AccountRlp::default()
};
let to_account_after = AccountRlp {
code_hash,
// Storage map: { 1 => 5 }
storage_root: HashedPartialTrie::from(Node::Leaf {
// TODO: Could do keccak(pad32(1))
nibbles: Nibbles::from_str(
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6",
)
.unwrap(),
value: vec![5],
})
.hash(),
..AccountRlp::default()
};
let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty);
expected_state_trie_after.insert(
beneficiary_nibbles,
rlp::encode(&beneficiary_account_after).to_vec(),
);
expected_state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec());
expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec());
assert_eq!(
proof.public_values.trie_roots_after.state_root,
expected_state_trie_after.hash()
);
verify_proof(&all_stark, proof, &config)
}

View File

@ -14,7 +14,7 @@ use plonky2_evm::all_stark::AllStark;
use plonky2_evm::config::StarkConfig;
use plonky2_evm::generation::mpt::AccountRlp;
use plonky2_evm::generation::{GenerationInputs, TrieInputs};
use plonky2_evm::proof::BlockMetadata;
use plonky2_evm::proof::{BlockMetadata, TrieRoots};
use plonky2_evm::prover::prove;
use plonky2_evm::verifier::verify_proof;
use plonky2_evm::Node;
@ -78,18 +78,6 @@ fn test_simple_transfer() -> anyhow::Result<()> {
let mut contract_code = HashMap::new();
contract_code.insert(keccak(vec![]), vec![]);
let inputs = GenerationInputs {
signed_txns: vec![txn.to_vec()],
tries: tries_before,
contract_code,
block_metadata,
addresses: vec![],
};
let mut timing = TimingTree::new("prove", log::Level::Debug);
let proof = prove::<F, C, D>(&all_stark, &config, inputs, &mut timing)?;
timing.filter(Duration::from_millis(100)).print();
let expected_state_trie_after: HashedPartialTrie = {
let txdata_gas = 2 * 16;
let gas_used = 21_000 + txdata_gas;
@ -121,11 +109,23 @@ fn test_simple_transfer() -> anyhow::Result<()> {
}
.into()
};
let trie_roots_after = TrieRoots {
state_root: expected_state_trie_after.hash(),
transactions_root: tries_before.transactions_trie.hash(), // TODO: Fix this when we have transactions trie.
receipts_root: tries_before.receipts_trie.hash(), // TODO: Fix this when we have receipts trie.
};
let inputs = GenerationInputs {
signed_txns: vec![txn.to_vec()],
tries: tries_before,
trie_roots_after,
contract_code,
block_metadata,
addresses: vec![],
};
assert_eq!(
proof.public_values.trie_roots_after.state_root,
expected_state_trie_after.hash()
);
let mut timing = TimingTree::new("prove", log::Level::Debug);
let proof = prove::<F, C, D>(&all_stark, &config, inputs, &mut timing)?;
timing.filter(Duration::from_millis(100)).print();
verify_proof(&all_stark, proof, &config)
}