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

Full Receipt Integration Test (Part 3) #423

Open
wants to merge 6 commits into
base: zyouell/it-receipt-row-updates
Choose a base branch
from
Open
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
38 changes: 38 additions & 0 deletions mp2-common/src/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,44 @@ pub fn extract_child_hashes(rlp_data: &[u8]) -> Vec<Vec<u8>> {
hashes
}

/// Enum used to distinguish between different types of node in an MPT.
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum NodeType {
Branch,
Extension,
Leaf,
}

/// Function that returns the [`NodeType`] of an RLP encoded MPT node
pub fn node_type(rlp_data: &[u8]) -> Result<NodeType> {
let rlp = Rlp::new(rlp_data);

let item_count = rlp.item_count()?;

if item_count == 17 {
Ok(NodeType::Branch)
} else if item_count == 2 {
// The first item is the encoded path, if it begins with a 2 or 3 it is a leaf, else it is an extension node
let first_item = rlp.at(0)?;

// We want the first byte
let first_byte = first_item.as_raw()[0];

// The we divide by 16 to get the first nibble
match first_byte / 16 {
0 | 1 => Ok(NodeType::Extension),
2 | 3 => Ok(NodeType::Leaf),
_ => Err(anyhow!(
"Expected compact encoding beginning with 0,1,2 or 3"
)),
}
} else {
Err(anyhow!(
"RLP encoded Node item count was {item_count}, expected either 17 or 2"
))
}
}

pub fn left_pad32(slice: &[u8]) -> [u8; 32] {
left_pad::<32>(slice)
}
Expand Down
4 changes: 4 additions & 0 deletions mp2-v1/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ impl PublicParameters {
pub fn get_params_info(&self) -> Result<Vec<u8>> {
self.tree_creation.get_params_info()
}

pub fn get_value_extraction_params(&self) -> &values_extraction::PublicParameters {
&self.values_extraction
}
}

/// Instantiate the circuits employed for the pre-processing stage of LPN,
Expand Down
20 changes: 15 additions & 5 deletions mp2-v1/src/values_extraction/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use anyhow::{bail, ensure, Result};
use log::debug;
use mp2_common::{
default_config,
eth::{EventLogInfo, ReceiptProofInfo},
eth::EventLogInfo,
mpt_sequential::PAD_LEN,
proof::{ProofInputSerialized, ProofWithVK},
storage_key::{MappingSlot, SimpleSlot},
Expand Down Expand Up @@ -79,11 +79,13 @@ impl CircuitInput {

/// Create a circuit input for proving a leaf MPT node of a transaction receipt.
pub fn new_receipt_leaf<const NO_TOPICS: usize, const MAX_DATA: usize>(
info: &ReceiptProofInfo,
last_node: &[u8],
tx_index: u64,
event: &EventLogInfo<NO_TOPICS, MAX_DATA>,
) -> Self {
CircuitInput::LeafReceipt(
ReceiptLeafCircuit::new(info, event).expect("Could not construct Receipt Leaf Circuit"),
ReceiptLeafCircuit::new(last_node, tx_index, event)
.expect("Could not construct Receipt Leaf Circuit"),
)
}

Expand Down Expand Up @@ -750,7 +752,11 @@ mod tests {
let params = build_circuits_params();

println!("Proving leaf 1...");
let leaf_input_1 = CircuitInput::new_receipt_leaf(info_one, &query.event);
let leaf_input_1 = CircuitInput::new_receipt_leaf(
info_one.mpt_proof.last().unwrap(),
info_one.tx_index,
&query.event,
);
let now = std::time::Instant::now();
let leaf_proof1 = generate_proof(&params, leaf_input_1).unwrap();
{
Expand All @@ -765,7 +771,11 @@ mod tests {
);

println!("Proving leaf 2...");
let leaf_input_2 = CircuitInput::new_receipt_leaf(info_two, &query.event);
let leaf_input_2 = CircuitInput::new_receipt_leaf(
info_two.mpt_proof.last().unwrap(),
info_two.tx_index,
&query.event,
);
let now = std::time::Instant::now();
let leaf_proof2 = generate_proof(&params, leaf_input_2).unwrap();
println!(
Expand Down
52 changes: 33 additions & 19 deletions mp2-v1/src/values_extraction/leaf_receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@ use alloy::{
primitives::{Address, Log, B256},
rlp::Decodable,
};
use anyhow::{anyhow, Result};
use anyhow::Result;
use mp2_common::{
array::{Array, Vector, VectorWire},
eth::{EventLogInfo, ReceiptProofInfo},
eth::EventLogInfo,
group_hashing::CircuitBuilderGroupHashing,
keccak::{InputData, KeccakCircuit, KeccakWires, HASH_LEN},
mpt_sequential::{MPTKeyWire, MPTReceiptLeafNode, PAD_LEN},
poseidon::H,
public_inputs::PublicInputCommon,
rlp::MAX_KEY_NIBBLE_LEN,
types::{CBuilder, GFp},
u256::UInt256Target,
utils::{less_than, less_than_or_equal_to_unsafe, Endianness, PackerTarget, ToTargets},
D, F,
};
Expand Down Expand Up @@ -205,9 +206,20 @@ impl EventWires {
b.mul(tmp, scalar)
});

// Map the gas used to a curve point for the value digest, gas used is the first column so use one as its column id.
let gas_digest = b.map_to_curve_point(&[gas_used_column_id, gas_used]);
let tx_index_digest = b.map_to_curve_point(&[tx_index_column_id, tx_index]);
// Convert gas into a UInt256Target as we know it fits into a u32 (We summed 3 bytes, there are 4 bytes in a u32)
let gas_used_u256 = UInt256Target::new_from_target_unsafe(b, gas_used);

let gas_values = iter::once(gas_used_column_id)
.chain(gas_used_u256.to_targets())
.collect::<Vec<Target>>();
let gas_digest = b.map_to_curve_point(&gas_values);

// For transaction index digest we know the transaction index will always fit in a u32
let tx_index_uint256 = UInt256Target::new_from_target_unsafe(b, tx_index);
let tx_index_values = iter::once(tx_index_column_id)
.chain(tx_index_uint256.to_targets())
.collect::<Vec<Target>>();
let tx_index_digest = b.map_to_curve_point(&tx_index_values);

let initial_row_digest = b.add_curve_point(&[gas_digest, tx_index_digest]);
// We also keep track of the number of real logs we process as each log forms a row in our table
Expand Down Expand Up @@ -263,7 +275,12 @@ impl EventWires {
// We also keep track of which log this is in the receipt to avoid having identical rows in the table in the case
// that the event we are tracking can be emitted multiple times in the same transaction but has no topics or data.
let log_number = b.constant(F::from_canonical_usize(index + 1));
let log_no_digest = b.map_to_curve_point(&[log_number_column_id, log_number]);
// This number will always fit into a u32 so we can directly call `UInt256Target::from_target_unsafe`
let log_number_uint256 = UInt256Target::new_from_target_unsafe(b, log_number);
let log_no_values = iter::once(log_number_column_id)
.chain(log_number_uint256.to_targets())
.collect::<Vec<Target>>();
let log_no_digest = b.map_to_curve_point(&log_no_values);
points.push(log_no_digest);

let increment = b.select(dummy, zero, one);
Expand Down Expand Up @@ -321,17 +338,10 @@ where
{
/// Create a new [`ReceiptLeafCircuit`] from a [`ReceiptProofInfo`] and a [`EventLogInfo`]
pub fn new<const NO_TOPICS: usize, const MAX_DATA: usize>(
proof_info: &ReceiptProofInfo,
last_node: &[u8],
tx_index: u64,
event: &EventLogInfo<NO_TOPICS, MAX_DATA>,
) -> Result<Self> {
// Since the compact encoding of the key is stored first plus an additional list header and
// then the first element in the receipt body is the transaction type we calculate the offset to that point

let last_node = proof_info
.mpt_proof
.last()
.ok_or(anyhow!("Could not get last node in receipt trie proof"))?;

// Convert to Rlp form so we can use provided methods.
let node_rlp = rlp::Rlp::new(last_node);

Expand Down Expand Up @@ -429,8 +439,8 @@ where
});

Ok(Self {
node: last_node.clone(),
tx_index: proof_info.tx_index,
node: last_node.to_vec(),
tx_index,
size,
address,
rel_add_offset: add_rel_offset,
Expand Down Expand Up @@ -760,8 +770,12 @@ mod tests {
let info = proofs.first().unwrap();
let query = receipt_proof_infos.query();

let c =
ReceiptLeafCircuit::<NODE_LEN>::new::<NO_TOPICS, MAX_DATA>(info, &query.event).unwrap();
let c = ReceiptLeafCircuit::<NODE_LEN>::new::<NO_TOPICS, MAX_DATA>(
info.mpt_proof.last().unwrap(),
info.tx_index,
&query.event,
)
.unwrap();
let test_circuit = TestReceiptLeafCircuit { c };

let node = info.mpt_proof.last().unwrap().clone();
Expand Down
43 changes: 32 additions & 11 deletions mp2-v1/src/values_extraction/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use alloy::{
consensus::TxReceipt,
primitives::{Address, IntoLogData},
primitives::{Address, IntoLogData, B256, U256},
};
use mp2_common::{
eth::{left_pad32, EventLogInfo, ReceiptProofInfo},
Expand Down Expand Up @@ -297,7 +297,7 @@ pub fn compute_receipt_leaf_value_digest<const NO_TOPICS: usize, const MAX_DATA:
) -> Digest {
let receipt = receipt_proof_info.to_receipt().unwrap();
let gas_used = receipt.cumulative_gas_used();

let gas_used_u256: B256 = U256::from(gas_used).into();
// Only use events that we are indexing
let address = event.address;
let sig = event.event_signature;
Expand Down Expand Up @@ -336,13 +336,26 @@ pub fn compute_receipt_leaf_value_digest<const NO_TOPICS: usize, const MAX_DATA:
.collect::<Vec<GFp>>();
let gas_used_column_id = H::hash_no_pad(&gas_used_input).elements[0];

let index_digest = map_to_curve_point(&[
tx_index_column_id,
GFp::from_canonical_u64(receipt_proof_info.tx_index),
]);

let gas_digest =
map_to_curve_point(&[gas_used_column_id, GFp::from_noncanonical_u128(gas_used)]);
let index_256: B256 = U256::from(receipt_proof_info.tx_index).into();
let index_values = iter::once(tx_index_column_id)
.chain(
index_256
.0
.pack(mp2_common::utils::Endianness::Big)
.to_fields(),
)
.collect::<Vec<GFp>>();
let index_digest = map_to_curve_point(&index_values);

let gas_used_values = iter::once(gas_used_column_id)
.chain(
gas_used_u256
.0
.pack(mp2_common::utils::Endianness::Big)
.to_fields(),
)
.collect::<Vec<GFp>>();
let gas_digest = map_to_curve_point(&gas_used_values);
let mut n = 0;
receipt
.logs()
Expand Down Expand Up @@ -396,8 +409,16 @@ pub fn compute_receipt_leaf_value_digest<const NO_TOPICS: usize, const MAX_DATA:
map_to_curve_point(&values)
})
.collect::<Vec<_>>();
let log_no_digest =
map_to_curve_point(&[log_number_column_id, GFp::from_canonical_usize(n)]);
let log_no_256: B256 = U256::from(n).into();
let log_no_values = iter::once(log_number_column_id)
.chain(
log_no_256
.0
.pack(mp2_common::utils::Endianness::Big)
.to_fields(),
)
.collect::<Vec<GFp>>();
let log_no_digest = map_to_curve_point(&log_no_values);
let initial_digest = index_digest + gas_digest + log_no_digest;

let row_value = iter::once(initial_digest)
Expand Down
Loading
Loading