Skip to content

Commit

Permalink
Merge branch 'leo/verifier-data' into leo/get_storage_recursive
Browse files Browse the repository at this point in the history
  • Loading branch information
LogvinovLeon committed May 24, 2024
2 parents d4f1f8c + 08fb57a commit fda3145
Show file tree
Hide file tree
Showing 17 changed files with 124 additions and 3,399 deletions.
7 changes: 2 additions & 5 deletions ethereum/circuits/get_transaction/src/main.nr
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
use dep::ethereum::transaction::{get_transaction, TransactionWithinBlock, MAX_TREE_DEPTH};
use dep::ethereum::verifiers::transaction::MAX_ENCODED_TX_LENGTH;
use dep::proof::const::MAX_TRIE_NODE_LENGTH;
use dep::ethereum::transaction::{get_transaction, TransactionWithinBlock};

global MAX_DATA_LEN_M = 1000;
global PROOF_LEN = MAX_TREE_DEPTH * MAX_TRIE_NODE_LENGTH;

fn main(
chain_id: pub Field,
block_number: pub u64,
tx_idx: pub Field
) -> pub TransactionWithinBlock<MAX_DATA_LEN_M> {
let transaction_within_block: TransactionWithinBlock<MAX_DATA_LEN_M> = get_transaction::<MAX_DATA_LEN_M, PROOF_LEN, MAX_ENCODED_TX_LENGTH>(chain_id, block_number, tx_idx);
let transaction_within_block: TransactionWithinBlock<MAX_DATA_LEN_M> = get_transaction(chain_id, block_number, tx_idx);
transaction_within_block
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ global proof_input = ProofInput {
depth: 3
}
};

global proof_input_serialized = proof_input.serialize();
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ global proof_input = ProofInput {
depth: 3
}
};

global proof_input_serialized = proof_input.serialize();
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ global proof_input = ProofInput {
depth: 3
}
};

global proof_input_serialized = proof_input.serialize();
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ global proof_input = ProofInput {
depth: 2
}
};

global proof_input_serialized = proof_input.serialize();
7 changes: 3 additions & 4 deletions ethereum/circuits/lib/src/receipt.nr
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ use crate::header::get_header;
use crate::verifiers::receipt::verify_receipt;
use crate::merkle_patricia_proofs::proof::{Proof, ProofInput};
use dep::std::unsafe::zeroed;
use dep::proof::receipt_proof::ReceiptProof;

global BLOOM_FILTER_LEN: u64 = 256;

global MAX_KEY_LEN = 3;
global MAX_DEPTH_NO_LEAF = 6;
global MAX_PREFIXED_KEY_NIBBLE_LEN = 8; // (MAX_KEY_LEN + 1) * 2

global MAX_VALUE_LEN_M = 1000;
global MAX_VALUE_LEN_M = 1000; // Values taken from receiptProofConfigM in receipt.ts.
global MAX_LEAF_LEN_M = 1011;

global LEGACY_MAX_RECEIPT_ENCODED_LEN = 525;
Expand Down Expand Up @@ -77,14 +76,14 @@ struct TxReceiptWithinBlock {
}

pub fn get_receipt(chain_id: Field, block_number: u64, tx_idx: Field) -> TxReceiptWithinBlock {
let (tx_type, receipt, proof) = get_receipt_unconstrained_M(chain_id, block_number, tx_idx);
let (tx_type, receipt, proof_input) = get_receipt_unconstrained_M(chain_id, block_number, tx_idx);
let header = get_header(chain_id, block_number);
verify_receipt(
block_number,
tx_idx,
tx_type,
receipt,
proof,
proof_input,
header.receipts_root
);
TxReceiptWithinBlock { receipt, block_hash: header.hash }
Expand Down
1 change: 1 addition & 0 deletions ethereum/circuits/lib/src/serde.nr
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ impl Serde<RECEIPT_PROOF_LEN_M> for Proof<RECEIPT_MAX_DEPTH_NO_LEAF, RECEIPT_MAX
}

global RECEIPT_PROOF_INPUT_LEN_M = RECEIPT_MAX_PREFIXED_KEY_NIBBLE_LEN + RECEIPT_MAX_VALUE_LEN_M + RECEIPT_PROOF_LEN_M;
global TX_PROOF_INPUT_LEN_M = RECEIPT_PROOF_INPUT_LEN_M;

impl Serde<RECEIPT_PROOF_INPUT_LEN_M> for ProofInput<RECEIPT_MAX_PREFIXED_KEY_NIBBLE_LEN, RECEIPT_MAX_VALUE_LEN_M, RECEIPT_MAX_DEPTH_NO_LEAF, RECEIPT_MAX_LEAF_LEN_M> {
fn serialize(self) -> [Field; RECEIPT_PROOF_INPUT_LEN_M] {
Expand Down
37 changes: 26 additions & 11 deletions ethereum/circuits/lib/src/transaction.nr
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
use crate::misc::{types::{Bytes32, Address}, option::make_option};
use dep::std::unsafe::zeroed;
use dep::proof::transaction_proof::TransactionProof;
use crate::header::get_header;
use crate::verifiers::transaction::verify_tx;
use crate::merkle_patricia_proofs::proof::{Proof, ProofInput};
use crate::serde::TX_PROOF_INPUT_LEN_M;

global MAX_TREE_DEPTH = 7;
global MAX_KEY_LEN = 3;
global MAX_DEPTH_NO_LEAF = 6;
global MAX_PREFIXED_KEY_NIBBLE_LEN = 8; // (MAX_KEY_LEN + 1) * 2

global MAX_VALUE_LEN_M = 1000; // Values taken from txProofConfigM in tx.ts.
global MAX_LEAF_LEN_M = 1011;

global LEGACY_MAX_TX_ENCODED_LEN = 525;

Expand Down Expand Up @@ -91,36 +96,46 @@ impl<MAX_DATA_LEN> From<ForeignCallTransaction> for TxPartial<MAX_DATA_LEN> {
}
}

type ProofInputSerialized<LEN> = [Field; LEN];

struct TransactionWithinBlock<MAX_DATA_LEN> {
transaction: TxPartial<MAX_DATA_LEN>,
block_hash: Bytes32
}

pub fn get_transaction<MAX_DATA_LEN, MAX_PROOF_LEN, MAX_RLP_LEN>(
pub fn get_transaction<MAX_DATA_LEN>(
chain_id: Field,
block_number: u64,
tx_idx: Field
) -> TransactionWithinBlock<MAX_DATA_LEN> {
let (tx_type, transaction, proof): (TxType, TxPartial<MAX_DATA_LEN>, TransactionProof<MAX_PROOF_LEN, MAX_RLP_LEN>) = get_transaction_unconstrained(chain_id, block_number, tx_idx);
let (tx_type, transaction, proof_input) = get_transaction_unconstrained_M(chain_id, block_number, tx_idx);
let header = get_header(chain_id, block_number);
verify_tx(tx_idx, tx_type, transaction, proof, header.transactions_root);
verify_tx(
tx_idx,
tx_type,
transaction,
proof_input,
header.transactions_root
);

TransactionWithinBlock { transaction, block_hash: header.hash }
}

#[oracle(get_transaction)]
unconstrained fn get_transaction_oracle<MAX_DATA_LEN, MAX_PROOF_LEN, MAX_RLP_LEN>(
unconstrained fn get_transaction_oracle<MAX_DATA_LEN, PROOF_INPUT_LEN>(
_chain_id: Field,
_block_number: u64,
_tx_idx: Field
) -> (TxType, ForeignCallTransaction<MAX_DATA_LEN>, TransactionProof<MAX_PROOF_LEN, MAX_RLP_LEN>) {}
) -> (TxType, ForeignCallTransaction<MAX_DATA_LEN>, ProofInputSerialized<PROOF_INPUT_LEN>) {}

unconstrained fn get_transaction_unconstrained<MAX_DATA_LEN, MAX_PROOF_LEN, MAX_RLP_LEN>(
unconstrained fn get_transaction_unconstrained_M<MAX_DATA_LEN>(
chain_id: Field,
block_number: u64,
tx_idx: Field
) -> (TxType, TxPartial<MAX_DATA_LEN>, TransactionProof<MAX_PROOF_LEN, MAX_RLP_LEN>) {
let (tx_type, transaction, proof): (TxType, ForeignCallTransaction<MAX_DATA_LEN>, TransactionProof<MAX_PROOF_LEN, MAX_RLP_LEN>) = get_transaction_oracle(chain_id, block_number, tx_idx);
) -> (TxType, TxPartial<MAX_DATA_LEN>, ProofInput<MAX_PREFIXED_KEY_NIBBLE_LEN, MAX_VALUE_LEN_M, MAX_DEPTH_NO_LEAF, MAX_LEAF_LEN_M>) {
let (tx_type, transaction, proof_input): (TxType, ForeignCallTransaction<MAX_DATA_LEN>, ProofInputSerialized<TX_PROOF_INPUT_LEN_M>) = get_transaction_oracle(chain_id, block_number, tx_idx);
let transaction: TxPartial<MAX_DATA_LEN> = transaction.into();
(tx_type, transaction, proof)
let proof_input = ProofInput::deserialize(proof_input);

(tx_type, transaction, proof_input)
}
31 changes: 15 additions & 16 deletions ethereum/circuits/lib/src/transaction_int_test.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use crate::transaction::{get_transaction, TransactionWithinBlock};
use crate::fixtures::mainnet::{
cancun::small_block::{
header::{number, block_header_partial, block_header_rlp},
transaction::{tx_idx, tx_type, transaction, foreign_call_transaction}, transaction_proof::proof
transaction::{tx_idx, tx_type, transaction, foreign_call_transaction},
transaction_proof_new::proof_input_serialized
},
homestead::fork::{
header::{
Expand All @@ -13,22 +14,20 @@ use crate::fixtures::mainnet::{
tx_idx as another_tx_idx, tx_type as another_tx_type,
foreign_call_transaction as another_foreign_call_transaction
},
transaction_proof::proof as another_proof
transaction_proof_new::proof_input_serialized as another_proof_input_serialized
}
};
use dep::std::test::OracleMock;
use crate::chain::ETHEREUM_MAINNET_ID;

global MAX_DATA_LEN = 1000;
global PROOF_LEN = 3724;
global MAX_RLP_LEN = 525;

#[test]
fn get_transaction_success() {
let _ = OracleMock::mock("get_header").returns((block_header_partial, block_header_rlp));
let _ = OracleMock::mock("get_transaction").returns((tx_type, foreign_call_transaction, proof));
let _ = OracleMock::mock("get_transaction").returns((tx_type, foreign_call_transaction, proof_input_serialized));

let transaction_within_block: TransactionWithinBlock<MAX_DATA_LEN> = get_transaction::<MAX_DATA_LEN, PROOF_LEN, MAX_RLP_LEN>(ETHEREUM_MAINNET_ID, number, tx_idx);
let transaction_within_block: TransactionWithinBlock<MAX_DATA_LEN> = get_transaction(ETHEREUM_MAINNET_ID, number, tx_idx);

assert_eq(transaction_within_block.block_hash, block_header_partial.hash);
assert_eq(transaction_within_block.transaction, foreign_call_transaction.into());
Expand All @@ -37,33 +36,33 @@ fn get_transaction_success() {
#[test(should_fail_with = "Block number does not match the argument")]
fn get_transaction_wrong_block_number() {
let _ = OracleMock::mock("get_header").returns((block_header_partial, block_header_rlp));
let _ = OracleMock::mock("get_transaction").returns((tx_type, foreign_call_transaction, proof));
let _ = OracleMock::mock("get_transaction").returns((tx_type, foreign_call_transaction, proof_input_serialized));

let wrong_number = number + 1;
let _: TransactionWithinBlock<MAX_DATA_LEN> = get_transaction::<MAX_DATA_LEN, PROOF_LEN, MAX_RLP_LEN>(ETHEREUM_MAINNET_ID, wrong_number, tx_idx);
let _: TransactionWithinBlock<MAX_DATA_LEN> = get_transaction(ETHEREUM_MAINNET_ID, wrong_number, tx_idx);
}

#[test(should_fail_with = "Key does not match rlp-encoded transaction index")]
fn get_transaction_wrong_tx_idx() {
let _ = OracleMock::mock("get_header").returns((block_header_partial, block_header_rlp));
let _ = OracleMock::mock("get_transaction").returns((tx_type, foreign_call_transaction, proof));
let _ = OracleMock::mock("get_transaction").returns((tx_type, foreign_call_transaction, proof_input_serialized));

let wrong_tx_idx = tx_idx + 1;
let _: TransactionWithinBlock<MAX_DATA_LEN> = get_transaction::<MAX_DATA_LEN, PROOF_LEN, MAX_RLP_LEN>(ETHEREUM_MAINNET_ID, number, wrong_tx_idx);
let _: TransactionWithinBlock<MAX_DATA_LEN> = get_transaction(ETHEREUM_MAINNET_ID, number, wrong_tx_idx);
}

#[test(should_fail_with = "Internal node hash does not match the hash extracted from the preceding node")]
#[test(should_fail_with = "Invalid node hash")]
fn get_transaction_wrong_transaction() {
let _ = OracleMock::mock("get_header").returns((block_header_partial, block_header_rlp));
let _ = OracleMock::mock("get_transaction").returns((another_tx_type, another_foreign_call_transaction, another_proof));
let _ = OracleMock::mock("get_transaction").returns((another_tx_type, another_foreign_call_transaction, another_proof_input_serialized));

let _: TransactionWithinBlock<MAX_DATA_LEN> = get_transaction::<MAX_DATA_LEN, PROOF_LEN, MAX_RLP_LEN>(ETHEREUM_MAINNET_ID, number, another_tx_idx);
let _: TransactionWithinBlock<MAX_DATA_LEN> = get_transaction(ETHEREUM_MAINNET_ID, number, another_tx_idx);
}

#[test(should_fail_with = "Internal node hash does not match the hash extracted from the preceding node")]
#[test(should_fail_with = "Invalid node hash")]
fn get_transaction_wrong_header() {
let _ = OracleMock::mock("get_header").returns((another_block_header_partial, another_block_header_rlp));
let _ = OracleMock::mock("get_transaction").returns((tx_type, foreign_call_transaction, proof));
let _ = OracleMock::mock("get_transaction").returns((tx_type, foreign_call_transaction, proof_input_serialized));

let _: TransactionWithinBlock<MAX_DATA_LEN> = get_transaction::<MAX_DATA_LEN, PROOF_LEN, MAX_RLP_LEN>(ETHEREUM_MAINNET_ID, another_number, tx_idx);
let _: TransactionWithinBlock<MAX_DATA_LEN> = get_transaction(ETHEREUM_MAINNET_ID, another_number, tx_idx);
}
5 changes: 2 additions & 3 deletions ethereum/circuits/lib/src/verifiers/receipt.nr
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
mod rlp;
mod rlp_test;

use dep::proof::{const::HASH_LENGTH, receipt_proof::ReceiptProof, node::key_as_nibbles};
use crate::receipt::{TxReceiptPartial, TxType, MAX_PREFIXED_KEY_NIBBLE_LEN, MAX_DEPTH_NO_LEAF};
use crate::verifiers::{
receipt::rlp::assert_receipt_rlp_equals,
tx_helpers::{split::split_into_tx_type_and_rlp, idx::assert_tx_idx_equals}
};
use crate::misc::{bytes::right_pad, fragment::Fragment};
use crate::misc::{types::HASH_LEN, bytes::right_pad, fragment::Fragment};
use crate::merkle_patricia_proofs::proof::{ProofInput, verify_merkle_proof};

global BYZANTIUM_BLOCK_NUM = 4_370_000;
Expand Down Expand Up @@ -36,7 +35,7 @@ pub fn verify_receipt<MAX_ENCODED_LEN, MAX_LEAF_LEN>(
tx_type: TxType,
receipt: TxReceiptPartial,
receipt_proof_input: ProofInput<MAX_PREFIXED_KEY_NIBBLE_LEN, MAX_ENCODED_LEN, MAX_DEPTH_NO_LEAF, MAX_LEAF_LEN>,
receipt_root: [u8; HASH_LENGTH]
receipt_root: [u8; HASH_LEN]
) {
let key = Fragment::from_vec(right_pad(receipt_proof_input.key));
assert_tx_idx_equals(key, tx_idx);
Expand Down
31 changes: 14 additions & 17 deletions ethereum/circuits/lib/src/verifiers/transaction.nr
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
mod rlp;
mod rlp_test;

use dep::proof::{transaction_proof::TransactionProof, node::key_as_nibbles, const::HASH_LENGTH};

use crate::transaction::{TxPartial, TxType};
use crate::transaction::{TxPartial, TxType, MAX_PREFIXED_KEY_NIBBLE_LEN, MAX_DEPTH_NO_LEAF};
use crate::verifiers::{
transaction::rlp::assert_tx_rlp_equals,
tx_helpers::{idx::assert_tx_idx_equals, split::split_into_tx_type_and_rlp}
};
use crate::misc::{bytes::right_pad, fragment::Fragment};
use crate::misc::{types::HASH_LEN, bytes::right_pad, fragment::Fragment};
use crate::merkle_patricia_proofs::proof::{ProofInput, verify_merkle_proof};

global MAX_ENCODED_TX_LENGTH: u64 = 525;
global MAX_TX_RLP_LENGTH: u64 = MAX_ENCODED_TX_LENGTH - 1;

pub(crate) fn assert_tx_proof<MAX_PROOF_LEN, MAX_RLP_LEN>(
proof: TransactionProof<MAX_PROOF_LEN, MAX_RLP_LEN>,
root: [u8; HASH_LENGTH]
) {
assert(proof.verify_transaction_root(root), "TrieProof: Invalid tx root");
}

pub(crate) fn assert_tx_equals<MAX_DATA_LEN, MAX_ENCODED_LEN>(
tx_type: TxType,
encoded_tx: Fragment<MAX_ENCODED_LEN, u8>,
Expand All @@ -32,17 +24,22 @@ pub(crate) fn assert_tx_equals<MAX_DATA_LEN, MAX_ENCODED_LEN>(
assert_tx_rlp_equals(tx_rlp, tx_type, tx);
}

pub fn verify_tx<MAX_DATA_LEN, MAX_PROOF_LEN, MAX_ENCODED_TX_LEN>(
pub fn verify_tx<MAX_DATA_LEN, MAX_ENCODED_LEN, MAX_LEAF_LEN>(
tx_idx: Field,
tx_type: TxType,
tx: TxPartial<MAX_DATA_LEN>,
tx_proof: TransactionProof<MAX_PROOF_LEN, MAX_ENCODED_TX_LEN>,
tx_root: [u8; HASH_LENGTH]
tx_proof_input: ProofInput<MAX_PREFIXED_KEY_NIBBLE_LEN, MAX_ENCODED_LEN, MAX_DEPTH_NO_LEAF, MAX_LEAF_LEN>,
tx_root: [u8; HASH_LEN]
) {
let key = Fragment::from_vec(right_pad(tx_proof.key));
let key = Fragment::from_vec(right_pad(tx_proof_input.key));
assert_tx_idx_equals(key, tx_idx);

let value = right_pad(tx_proof.value).storage;
let value = right_pad(tx_proof_input.value).storage;
assert_tx_equals(tx_type, Fragment::from_array(value), tx);
assert_tx_proof(tx_proof, tx_root);
verify_merkle_proof(
tx_proof_input.key,
tx_proof_input.value,
tx_root,
tx_proof_input.proof
)
}
Loading

0 comments on commit fda3145

Please sign in to comment.