Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constrain genesis block's state trie. #1228

Merged
merged 5 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 64 additions & 6 deletions evm/src/fixed_recursive_verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,14 @@ where
lhs: &ExtraBlockDataTarget,
rhs: &ExtraBlockDataTarget,
) {
// Connect genesis state root values.
for (&limb0, &limb1) in pvs.genesis_state_root.iter().zip(&rhs.genesis_state_root) {
builder.connect(limb0, limb1);
}
Comment on lines +644 to +647
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need to also connect lhs.genesis_state_root and pvs.genesis_state_root?

for (&limb0, &limb1) in pvs.genesis_state_root.iter().zip(&lhs.genesis_state_root) {
builder.connect(limb0, limb1);
}

// Connect the transaction number in public values to the lhs and rhs values correctly.
builder.connect(pvs.txn_number_before, lhs.txn_number_before);
builder.connect(pvs.txn_number_after, rhs.txn_number_after);
Expand Down Expand Up @@ -777,6 +785,16 @@ where
builder.connect(limb0, limb1);
}

// Between blocks, the genesis state trie remains unchanged.
for (&limb0, limb1) in lhs
.extra_block_data
.genesis_state_root
.iter()
.zip(rhs.extra_block_data.genesis_state_root)
{
builder.connect(limb0, limb1);
}

// Connect block numbers.
let one = builder.one();
let prev_block_nb = builder.sub(rhs.block_metadata.block_number, one);
Expand All @@ -788,13 +806,35 @@ where
// Connect intermediary values for gas_used and bloom filters to the block's final values. We only plug on the right, so there is no need to check the left-handside block.
Self::connect_final_block_values_to_intermediary(builder, rhs);

// Chack that the genesis block number is 0.
let zero = builder.zero();
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, rhs.block_metadata.block_number);
builder.connect(gen_block_constr, zero);

// TODO: Check that the genesis block has a predetermined state trie root.
// Check that the genesis block has the predetermined state trie root in `ExtraBlockData`.
Self::connect_genesis_block(builder, rhs, has_not_parent_block);
}

fn connect_genesis_block(
builder: &mut CircuitBuilder<F, D>,
x: &PublicValuesTarget,
has_not_parent_block: Target,
) where
F: RichField + Extendable<D>,
{
let zero = builder.zero();
for (&limb0, limb1) in x
.trie_roots_before
.state_root
.iter()
.zip(x.extra_block_data.genesis_state_root)
{
let mut constr = builder.sub(limb0, limb1);
constr = builder.mul(has_not_parent_block, constr);
builder.connect(constr, zero);
}
}

fn connect_final_block_values_to_intermediary(
Expand Down Expand Up @@ -968,16 +1008,34 @@ where
block_inputs
.set_proof_with_pis_target(&self.block.parent_block_proof, parent_block_proof);
} else {
// Initialize state_root_after and the block number for correct connection between blocks.
let state_trie_root_keys = 24..32;
let block_number_key = TrieRootsTarget::SIZE * 2 + 6;
// Initialize genesis_state_trie, state_root_after and the block number for correct connection between blocks.
// Initialize `state_root_after`.
let state_trie_root_after_keys = 24..32;
let mut nonzero_pis = HashMap::new();
for (key, &value) in state_trie_root_keys
for (key, &value) in state_trie_root_after_keys
.zip_eq(&h256_limbs::<F>(public_values.trie_roots_before.state_root))
{
nonzero_pis.insert(key, value);
}

// Initialize the genesis state trie digest.
let genesis_state_trie_keys = TrieRootsTarget::SIZE * 2
+ BlockMetadataTarget::SIZE
+ BlockHashesTarget::BLOCK_HASHES_SIZE
..TrieRootsTarget::SIZE * 2
+ BlockMetadataTarget::SIZE
+ BlockHashesTarget::BLOCK_HASHES_SIZE
+ 8;
for (key, &value) in genesis_state_trie_keys.zip_eq(&h256_limbs::<F>(
public_values.extra_block_data.genesis_state_root,
)) {
nonzero_pis.insert(key, value);
}

// Initialize the block number.
let block_number_key = TrieRootsTarget::SIZE * 2 + 6;
nonzero_pis.insert(block_number_key, F::NEG_ONE);

block_inputs.set_proof_with_pis_target(
&self.block.parent_block_proof,
&cyclic_base_proof(
Expand Down
3 changes: 3 additions & 0 deletions evm/src/generation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ 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,

/// Mapping between smart contract code hashes and the contract byte code.
/// All account smart contracts that are invoked will have an entry present.
Expand Down Expand Up @@ -259,6 +261,7 @@ pub fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
let txn_number_after = read_metadata(GlobalMetadata::TxnNumberAfter);

let extra_block_data = ExtraBlockData {
genesis_state_root: inputs.genesis_state_trie_root,
txn_number_before: inputs.txn_number_before,
txn_number_after,
gas_used_before: inputs.gas_used_before,
Expand Down
2 changes: 2 additions & 0 deletions evm/src/get_challenges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ fn observe_extra_block_data<
challenger: &mut Challenger<F, C::Hasher>,
extra_data: &ExtraBlockData,
) -> Result<(), ProgramError> {
challenger.observe_elements(&h256_limbs(extra_data.genesis_state_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)?);
Expand All @@ -132,6 +133,7 @@ fn observe_extra_block_data_target<
) where
C::Hasher: AlgebraicHasher<F>,
{
challenger.observe_elements(&extra_data.genesis_state_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);
Expand Down
36 changes: 27 additions & 9 deletions evm/src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ pub struct BlockMetadata {
/// unlike `BlockMetadata`.
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct ExtraBlockData {
/// The state trie digest of the genesis block.
pub genesis_state_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,
Expand Down Expand Up @@ -203,13 +205,15 @@ impl PublicValuesTarget {
buffer.write_target_array(&cur_hash)?;

let ExtraBlockDataTarget {
genesis_state_root,
txn_number_before,
txn_number_after,
gas_used_before,
gas_used_after,
block_bloom_before,
block_bloom_after,
} = self.extra_block_data;
buffer.write_target_array(&genesis_state_root)?;
buffer.write_target(txn_number_before)?;
buffer.write_target(txn_number_after)?;
buffer.write_target(gas_used_before)?;
Expand Down Expand Up @@ -252,6 +256,7 @@ impl PublicValuesTarget {
};

let extra_block_data = ExtraBlockDataTarget {
genesis_state_root: buffer.read_target_array()?,
txn_number_before: buffer.read_target()?,
txn_number_after: buffer.read_target()?,
gas_used_before: buffer.read_target()?,
Expand Down Expand Up @@ -420,7 +425,7 @@ pub struct BlockMetadataTarget {
}

impl BlockMetadataTarget {
const SIZE: usize = 85;
pub const SIZE: usize = 85;

pub fn from_public_inputs(pis: &[Target]) -> Self {
let block_beneficiary = pis[0..5].try_into().unwrap();
Expand Down Expand Up @@ -513,7 +518,7 @@ pub struct BlockHashesTarget {
}

impl BlockHashesTarget {
const BLOCK_HASHES_SIZE: usize = 2056;
pub const BLOCK_HASHES_SIZE: usize = 2056;
pub fn from_public_inputs(pis: &[Target]) -> Self {
Self {
prev_hashes: pis[0..2048].try_into().unwrap(),
Expand Down Expand Up @@ -553,6 +558,7 @@ impl BlockHashesTarget {

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct ExtraBlockDataTarget {
pub genesis_state_root: [Target; 8],
pub txn_number_before: Target,
pub txn_number_after: Target,
pub gas_used_before: Target,
Expand All @@ -562,17 +568,19 @@ pub struct ExtraBlockDataTarget {
}

impl ExtraBlockDataTarget {
const SIZE: usize = 132;
const SIZE: usize = 140;

pub fn from_public_inputs(pis: &[Target]) -> Self {
let txn_number_before = pis[0];
let txn_number_after = pis[1];
let gas_used_before = pis[2];
let gas_used_after = pis[3];
let block_bloom_before = pis[4..68].try_into().unwrap();
let block_bloom_after = pis[68..132].try_into().unwrap();
let genesis_state_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 block_bloom_before = pis[12..76].try_into().unwrap();
let block_bloom_after = pis[76..140].try_into().unwrap();

Self {
genesis_state_root,
txn_number_before,
txn_number_after,
gas_used_before,
Expand All @@ -589,6 +597,13 @@ impl ExtraBlockDataTarget {
ed1: Self,
) -> Self {
Self {
genesis_state_root: core::array::from_fn(|i| {
builder.select(
condition,
ed0.genesis_state_root[i],
ed1.genesis_state_root[i],
)
}),
txn_number_before: builder.select(
condition,
ed0.txn_number_before,
Expand Down Expand Up @@ -619,6 +634,9 @@ impl ExtraBlockDataTarget {
ed0: Self,
ed1: Self,
) {
for i in 0..8 {
builder.connect(ed0.genesis_state_root[i], ed1.genesis_state_root[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);
Expand Down
6 changes: 6 additions & 0 deletions evm/src/recursive_verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,13 +809,15 @@ pub(crate) fn add_virtual_block_hashes<F: RichField + Extendable<D>, const D: us
pub(crate) fn add_virtual_extra_block_data<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
) -> ExtraBlockDataTarget {
let genesis_state_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();
let block_bloom_before: [Target; 64] = builder.add_virtual_public_input_arr();
let block_bloom_after: [Target; 64] = builder.add_virtual_public_input_arr();
ExtraBlockDataTarget {
genesis_state_root,
txn_number_before,
txn_number_after,
gas_used_before,
Expand Down Expand Up @@ -1077,6 +1079,10 @@ where
F: RichField + Extendable<D>,
W: Witness<F>,
{
witness.set_target_arr(
&ed_target.genesis_state_root,
&h256_limbs::<F>(ed.genesis_state_root),
);
witness.set_target(
ed_target.txn_number_before,
u256_to_u32(ed.txn_number_before)?,
Expand Down
1 change: 1 addition & 0 deletions evm/tests/add11_yml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ fn add11_yml() -> anyhow::Result<()> {
trie_roots_after,
contract_code,
block_metadata,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
txn_number_before: 0.into(),
gas_used_before: 0.into(),
gas_used_after: 0xa868u64.into(),
Expand Down
1 change: 1 addition & 0 deletions evm/tests/basic_smart_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,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(),
block_metadata,
txn_number_before: 0.into(),
gas_used_before: 0.into(),
Expand Down
1 change: 1 addition & 0 deletions evm/tests/empty_txn_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> {
},
trie_roots_after,
contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata,
txn_number_before: 0.into(),
gas_used_before: 0.into(),
Expand Down
5 changes: 5 additions & 0 deletions evm/tests/log_opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ fn test_log_opcodes() -> anyhow::Result<()> {
tries: tries_before,
trie_roots_after,
contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata,
txn_number_before: 0.into(),
gas_used_before: 0.into(),
Expand Down Expand Up @@ -425,6 +426,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> {
tries: tries_before,
trie_roots_after: tries_after,
contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata: block_metadata.clone(),
txn_number_before: 0.into(),
gas_used_before: 0.into(),
Expand Down Expand Up @@ -566,6 +568,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> {
tries: tries_before,
trie_roots_after,
contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata,
txn_number_before: 1.into(),
gas_used_before: gas_used_second,
Expand All @@ -591,6 +594,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> {
trie_roots_before: first_public_values.trie_roots_before,
trie_roots_after: public_values.trie_roots_after,
extra_block_data: ExtraBlockData {
genesis_state_root: first_public_values.extra_block_data.genesis_state_root,
txn_number_before: first_public_values.extra_block_data.txn_number_before,
txn_number_after: public_values.extra_block_data.txn_number_after,
gas_used_before: first_public_values.extra_block_data.gas_used_before,
Expand Down Expand Up @@ -867,6 +871,7 @@ fn test_two_txn() -> anyhow::Result<()> {
tries: tries_before,
trie_roots_after,
contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata,
txn_number_before: 0.into(),
gas_used_before: 0.into(),
Expand Down
1 change: 1 addition & 0 deletions evm/tests/self_balance_gas_cost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,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(),
block_metadata,
txn_number_before: 0.into(),
gas_used_before: 0.into(),
Expand Down
1 change: 1 addition & 0 deletions evm/tests/simple_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ fn test_simple_transfer() -> anyhow::Result<()> {
tries: tries_before,
trie_roots_after,
contract_code,
genesis_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(),
block_metadata,
txn_number_before: 0.into(),
gas_used_before: 0.into(),
Expand Down