Skip to content

Commit

Permalink
feat: calculate commitments within the block
Browse files Browse the repository at this point in the history
  • Loading branch information
yoavGrs committed May 15, 2024
1 parent 77ff5a3 commit f87a1b5
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 74 deletions.
3 changes: 3 additions & 0 deletions src/block_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ pub mod event_commitment;
pub mod receipt_commitment;
pub mod state_diff_hash;
pub mod transaction_commitment;

#[cfg(test)]
pub mod test_utils;
66 changes: 65 additions & 1 deletion src/block_hash/block_hash_calculator.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,74 @@
use super::event_commitment::{calculate_events_commitment, EventLeafElement};
use super::receipt_commitment::{calculate_receipt_commitment, ReceiptElement};
use super::transaction_commitment::{calculate_transactions_commitment, TransactionLeafElement};
use crate::core::{EventCommitment, ReceiptCommitment, TransactionCommitment};
use crate::data_availability::L1DataAvailabilityMode;
use crate::hash::StarkFelt;
use crate::hash::{PoseidonHashCalculator, StarkFelt};
use crate::transaction::{TransactionHash, TransactionOutput, TransactionSignature};

#[cfg(test)]
#[path = "block_hash_calculator_test.rs"]
mod block_hash_calculator_test;

pub struct TransactionHashingData {
pub transaction_signature: Option<TransactionSignature>,
pub transaction_output: TransactionOutput,
pub transaction_hash: TransactionHash,
}

#[allow(dead_code)]
struct BlockHeaderCommitments {
pub n_transactions: usize,
pub transactions_commitment: TransactionCommitment,
pub n_events: usize,
pub events_commitment: EventCommitment,
pub receipts_commitment: ReceiptCommitment,
}

// Calculates the commitments of the transactions data for the block hash.
#[allow(dead_code)]
fn calculate_block_commitments(
transactions_data: &[TransactionHashingData],
) -> BlockHeaderCommitments {
let transaction_leaf_elements: Vec<TransactionLeafElement> = transactions_data
.iter()
.map(|transaction_data| TransactionLeafElement {
transaction_hash: transaction_data.transaction_hash,
transaction_signature: transaction_data.transaction_signature.clone(),
})
.collect();
let transactions_commitment =
calculate_transactions_commitment::<PoseidonHashCalculator>(&transaction_leaf_elements);

let mut event_leaf_elements: Vec<EventLeafElement> = Vec::new();
for transaction in transactions_data {
let transaction_hash = transaction.transaction_hash;
for event in transaction.transaction_output.events() {
let event_leaf_element = EventLeafElement { event: event.clone(), transaction_hash };
event_leaf_elements.push(event_leaf_element);
}
}
let events_commitment =
calculate_events_commitment::<PoseidonHashCalculator>(&event_leaf_elements);

let receipt_elements: Vec<ReceiptElement> = transactions_data
.iter()
.map(|transaction_data| ReceiptElement {
transaction_hash: transaction_data.transaction_hash,
transaction_output: transaction_data.transaction_output.clone(),
})
.collect();
let receipts_commitment =
calculate_receipt_commitment::<PoseidonHashCalculator>(&receipt_elements);
BlockHeaderCommitments {
n_transactions: transactions_data.len(),
transactions_commitment,
n_events: event_leaf_elements.len(),
events_commitment,
receipts_commitment,
}
}

// A single felt: [
// transaction_count (64 bits) | event_count (64 bits) | state_diff_length (64 bits)
// | L1 data availability mode: 0 for calldata, 1 for blob (1 bit) | 0 ...
Expand Down
4 changes: 2 additions & 2 deletions src/block_hash/event_commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ mod event_commitment_test;
/// The elements used to calculate a leaf in the transactions Patricia tree.
#[derive(Clone)]
pub struct EventLeafElement {
event: Event,
transaction_hash: TransactionHash,
pub event: Event,
pub transaction_hash: TransactionHash,
}

/// Returns the root of a Patricia tree where each leaf is an event hash.
Expand Down
12 changes: 6 additions & 6 deletions src/block_hash/event_commitment_test.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use super::calculate_event_hash;
use crate::block_hash::event_commitment::{calculate_events_commitment, EventLeafElement};
use crate::core::{ContractAddress, EventCommitment, PatriciaKey};
use crate::hash::{PoseidonHashCalculator, StarkFelt, StarkHash};
use super::{calculate_event_hash, EventLeafElement};
use crate::block_hash::event_commitment::calculate_events_commitment;
use crate::core::{ContractAddress, EventCommitment};
use crate::hash::{PoseidonHashCalculator, StarkFelt};
use crate::stark_felt;
use crate::transaction::{Event, EventContent, EventData, EventKey, TransactionHash};
use crate::{contract_address, patricia_key, stark_felt};

#[test]
fn test_events_commitment_regression() {
Expand Down Expand Up @@ -34,7 +34,7 @@ fn test_event_hash_regression() {
fn get_event_leaf_element(seed: u8) -> EventLeafElement {
EventLeafElement {
event: Event {
from_address: contract_address!(seed + 8),
from_address: ContractAddress::from(seed + 8),
content: EventContent {
keys: [seed, seed + 1].iter().map(|key| EventKey(stark_felt!(*key))).collect(),
data: EventData(
Expand Down
25 changes: 16 additions & 9 deletions src/block_hash/receipt_commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::crypto::patricia_hash::calculate_root;
use crate::crypto::utils::HashChain;
use crate::hash::{starknet_keccak_hash, HashFunction, StarkFelt};
use crate::transaction::{
ExecutionResources, MessageToL1, TransactionExecutionStatus, TransactionReceipt,
ExecutionResources, MessageToL1, TransactionExecutionStatus, TransactionHash, TransactionOutput,
};

#[cfg(test)]
Expand All @@ -14,26 +14,33 @@ mod receipt_commitment_test;
const L1_GAS_PER_STEP: u64 = 1;
const L1_GAS_PER_BUILTIN_INSTANCE: u64 = 1;

// The elements used to calculate a leaf in the transactions Patricia tree.
#[derive(Clone)]
pub struct ReceiptElement {
pub transaction_hash: TransactionHash,
pub transaction_output: TransactionOutput,
}

/// Returns the root of a Patricia tree where each leaf is a receipt hash.
pub fn calculate_receipt_commitment<H: HashFunction>(
transactions_receipt: &[TransactionReceipt],
receipt_elements: &[ReceiptElement],
) -> ReceiptCommitment {
ReceiptCommitment(calculate_root::<H>(
transactions_receipt.iter().map(calculate_receipt_hash).collect(),
receipt_elements.iter().map(calculate_receipt_hash).collect(),
))
}

// Poseidon(
// transaction hash, amount of fee paid, hash of messages sent, revert reason,
// execution resources
// ).
fn calculate_receipt_hash(transaction_receipt: &TransactionReceipt) -> StarkFelt {
fn calculate_receipt_hash(receipt_element: &ReceiptElement) -> StarkFelt {
let hash_chain = HashChain::new()
.chain(&transaction_receipt.transaction_hash)
.chain(&transaction_receipt.output.actual_fee().0.into())
.chain(&calculate_messages_sent_hash(transaction_receipt.output.messages_sent()))
.chain(&get_revert_reason_hash(transaction_receipt.output.execution_status()));
chain_execution_resources(hash_chain, transaction_receipt.output.execution_resources())
.chain(&receipt_element.transaction_hash)
.chain(&receipt_element.transaction_output.actual_fee().0.into())
.chain(&calculate_messages_sent_hash(receipt_element.transaction_output.messages_sent()))
.chain(&get_revert_reason_hash(receipt_element.transaction_output.execution_status()));
chain_execution_resources(hash_chain, receipt_element.transaction_output.execution_resources())
.get_poseidon_hash()
}

Expand Down
44 changes: 5 additions & 39 deletions src/block_hash/receipt_commitment_test.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,19 @@
use std::collections::HashMap;

use primitive_types::H160;

use super::calculate_messages_sent_hash;
use crate::block::{BlockHash, BlockNumber};
use crate::block_hash::receipt_commitment::{
calculate_receipt_commitment, calculate_receipt_hash, get_revert_reason_hash,
calculate_receipt_commitment, calculate_receipt_hash, get_revert_reason_hash, ReceiptElement,
};
use crate::core::{ContractAddress, EthAddress, ReceiptCommitment};
use crate::block_hash::test_utils::{generate_message_to_l1, get_transaction_output};
use crate::core::ReceiptCommitment;
use crate::hash::{PoseidonHashCalculator, StarkFelt};
use crate::transaction::{
Builtin, ExecutionResources, Fee, InvokeTransactionOutput, L2ToL1Payload, MessageToL1,
RevertedTransactionExecutionStatus, TransactionExecutionStatus, TransactionHash,
TransactionOutput, TransactionReceipt,
};

#[test]
fn test_receipt_hash_regression() {
let execution_status =
TransactionExecutionStatus::Reverted(RevertedTransactionExecutionStatus {
revert_reason: "aborted".to_string(),
});
let execution_resources = ExecutionResources {
steps: 98,
builtin_instance_counter: HashMap::from([(Builtin::Bitwise, 11), (Builtin::EcOp, 22)]),
memory_holes: 76,
da_l1_gas_consumed: 54,
da_l1_data_gas_consumed: 32,
};
let invoke_output = TransactionOutput::Invoke(InvokeTransactionOutput {
actual_fee: Fee(12),
messages_sent: vec![generate_message_to_l1(34), generate_message_to_l1(56)],
events: vec![],
execution_status,
execution_resources,
});
let transaction_receipt = TransactionReceipt {
let transaction_receipt = ReceiptElement {
transaction_hash: TransactionHash(StarkFelt::from(1234_u16)),
block_hash: BlockHash(StarkFelt::from(5678_u16)),
block_number: BlockNumber(99),
output: invoke_output,
transaction_output: get_transaction_output(),
};

let expected_hash =
Expand Down Expand Up @@ -67,14 +41,6 @@ fn test_messages_sent_regression() {
assert_eq!(messages_hash, expected_hash);
}

fn generate_message_to_l1(seed: u64) -> MessageToL1 {
MessageToL1 {
from_address: ContractAddress::from(seed),
to_address: EthAddress(H160::from_low_u64_be(seed + 1)),
payload: L2ToL1Payload(vec![StarkFelt::from(seed + 2), StarkFelt::from(seed + 3)]),
}
}

#[test]
fn test_revert_reason_hash_regression() {
let execution_succeeded = TransactionExecutionStatus::Succeeded;
Expand Down
39 changes: 39 additions & 0 deletions src/block_hash/test_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::collections::HashMap;

use primitive_types::H160;

use crate::core::{ContractAddress, EthAddress};
use crate::hash::StarkFelt;
use crate::transaction::{
Builtin, ExecutionResources, Fee, InvokeTransactionOutput, L2ToL1Payload, MessageToL1,
RevertedTransactionExecutionStatus, TransactionExecutionStatus, TransactionOutput,
};

pub(crate) fn get_transaction_output() -> TransactionOutput {
let execution_status =
TransactionExecutionStatus::Reverted(RevertedTransactionExecutionStatus {
revert_reason: "aborted".to_string(),
});
let execution_resources = ExecutionResources {
steps: 98,
builtin_instance_counter: HashMap::from([(Builtin::Bitwise, 11), (Builtin::EcOp, 22)]),
memory_holes: 76,
da_l1_gas_consumed: 54,
da_l1_data_gas_consumed: 32,
};
TransactionOutput::Invoke(InvokeTransactionOutput {
actual_fee: Fee(12),
messages_sent: vec![generate_message_to_l1(34), generate_message_to_l1(56)],
events: vec![],
execution_status,
execution_resources,
})
}

pub(crate) fn generate_message_to_l1(seed: u64) -> MessageToL1 {
MessageToL1 {
from_address: ContractAddress::from(seed),
to_address: EthAddress(H160::from_low_u64_be(seed + 1)),
payload: L2ToL1Payload(vec![StarkFelt::from(seed + 2), StarkFelt::from(seed + 3)]),
}
}
20 changes: 14 additions & 6 deletions src/block_hash/transaction_commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,32 @@ mod transaction_commitment_test;

/// The elements used to calculate a leaf in the transactions Patricia tree.
#[derive(Clone)]
pub struct TransactionLeafElements {
transaction_hash: TransactionHash,
transaction_signature: TransactionSignature,
pub struct TransactionLeafElement {
pub transaction_hash: TransactionHash,
pub transaction_signature: Option<TransactionSignature>,
}

/// Returns the root of a Patricia tree where each leaf is
/// Poseidon(transaction_hash, transaction_signature).
/// The leaf of a transaction types without a signature field is: Poseidon(transaction_hash, 0).
pub fn calculate_transactions_commitment<H: HashFunction>(
transaction_leaf_elements: &[TransactionLeafElements],
transaction_leaf_elements: &[TransactionLeafElement],
) -> TransactionCommitment {
let transaction_leaves =
transaction_leaf_elements.iter().map(calculate_transaction_leaf).collect();
TransactionCommitment(calculate_root::<H>(transaction_leaves))
}

fn calculate_transaction_leaf(transaction_leaf_elements: &TransactionLeafElements) -> StarkFelt {
fn calculate_transaction_leaf(transaction_leaf_elements: &TransactionLeafElement) -> StarkFelt {
HashChain::new()
.chain(&transaction_leaf_elements.transaction_hash.0)
.chain_iter(transaction_leaf_elements.transaction_signature.0.iter())
.chain_iter(
transaction_leaf_elements
.transaction_signature
.as_ref()
.unwrap_or(&TransactionSignature(vec![StarkFelt::ZERO]))
.0
.iter(),
)
.get_poseidon_hash()
}
34 changes: 23 additions & 11 deletions src/block_hash/transaction_commitment_test.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
use super::TransactionLeafElement;
use crate::block_hash::transaction_commitment::{
calculate_transaction_leaf, calculate_transactions_commitment, TransactionLeafElements,
calculate_transaction_leaf, calculate_transactions_commitment,
};
use crate::core::TransactionCommitment;
use crate::hash::{PoseidonHashCalculator, StarkFelt};
use crate::transaction::{TransactionHash, TransactionSignature};

#[test]
fn test_transaction_leaf_regression() {
let transaction_hash = TransactionHash(StarkFelt::ONE);
let transaction_signature = TransactionSignature(vec![StarkFelt::TWO, StarkFelt::THREE]);
let transaction_leaf_elements =
TransactionLeafElements { transaction_hash, transaction_signature };

let transaction_leaf_elements = get_transaction_leaf_element();
let expected_leaf =
StarkFelt::try_from("0x2f0d8840bcf3bc629598d8a6cc80cb7c0d9e52d93dab244bbf9cd0dca0ad082")
.unwrap();
Expand All @@ -20,12 +17,21 @@ fn test_transaction_leaf_regression() {
}

#[test]
fn test_transactions_commitment_regression() {
let transaction_hash = TransactionHash(StarkFelt::ONE);
let transaction_signature = TransactionSignature(vec![StarkFelt::TWO, StarkFelt::THREE]);
let transaction_leaf_elements =
TransactionLeafElements { transaction_hash, transaction_signature };
fn test_transaction_leaf_without_signature_regression() {
let transaction_leaf_elements = TransactionLeafElement {
transaction_hash: TransactionHash(StarkFelt::ONE),
transaction_signature: None,
};
let expected_leaf =
StarkFelt::try_from("0x00a93bf5e58b9378d093aa86ddc2f61a3295a1d1e665bd0ef3384dd07b30e033")
.unwrap();

assert_eq!(expected_leaf, calculate_transaction_leaf(&transaction_leaf_elements));
}

#[test]
fn test_transactions_commitment_regression() {
let transaction_leaf_elements = get_transaction_leaf_element();
let expected_root =
StarkFelt::try_from("0x0282b635972328bd1cfa86496fe920d20bd9440cd78ee8dc90ae2b383d664dcf")
.unwrap();
Expand All @@ -38,3 +44,9 @@ fn test_transactions_commitment_regression() {
],)
);
}

fn get_transaction_leaf_element() -> TransactionLeafElement {
let transaction_hash = TransactionHash(StarkFelt::ONE);
let transaction_signature = TransactionSignature(vec![StarkFelt::TWO, StarkFelt::THREE]);
TransactionLeafElement { transaction_hash, transaction_signature: Some(transaction_signature) }
}

0 comments on commit f87a1b5

Please sign in to comment.