Skip to content

Commit

Permalink
feat: calculate block hash
Browse files Browse the repository at this point in the history
  • Loading branch information
yoavGrs committed May 9, 2024
1 parent 77ff5a3 commit f1d217b
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 10 deletions.
81 changes: 79 additions & 2 deletions src/block_hash/block_hash_calculator.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,92 @@
use once_cell::sync::Lazy;

use super::event_commitment::{calculate_events_commitment, EventLeafElement};
use super::receipt_commitment::calculate_receipt_commitment;
use super::state_diff_hash::calculate_state_diff_hash;
use super::transaction_commitment::{calculate_transactions_commitment, TransactionLeafElement};
use crate::block::{BlockHash, BlockNumber, BlockTimestamp, GasPricePerToken, StarknetVersion};
use crate::core::{GlobalRoot, SequencerContractAddress};
use crate::crypto::utils::HashChain;
use crate::data_availability::L1DataAvailabilityMode;
use crate::hash::StarkFelt;
use crate::hash::{PoseidonHashCalculator, StarkFelt};
use crate::state::ThinStateDiff;
use crate::transaction::TransactionReceipt;
use crate::transaction_hash::ascii_as_felt;

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

static STARKNET_BLOCK_HASH0: Lazy<StarkFelt> = Lazy::new(|| {
ascii_as_felt("STARKNET_BLOCK_HASH0").expect("ascii_as_felt failed for 'STARKNET_BLOCK_HASH0'")
});

pub struct BlockHashInput<'a, 'b, 'c, 'd> {
block_number: BlockNumber,
state_root: GlobalRoot,
sequencer_contract_address: SequencerContractAddress,
timestamp: BlockTimestamp,
transaction_leaf_elements: &'a [TransactionLeafElement],
event_leaf_elements: &'b [EventLeafElement],
state_diff: &'c ThinStateDiff,
l1_da_mode: L1DataAvailabilityMode,
transaction_receipts: &'d [TransactionReceipt],
l1_gas_price: GasPricePerToken,
l1_data_gas_price: GasPricePerToken,
starknet_version: StarknetVersion,
parent_hash: BlockHash,
}

/// Poseidon (
/// “STARKNET_BLOCK_HASH0”, block_number, global_state_root, sequencer_address,
/// block_timestamp, concat_counts, state_diff_hash, transaction_commitment,
/// event_commitment, receipt_commitment, gas_price_wei, gas_price_fri,
/// data_gas_price_wei, data_gas_price_fri, starknet_version, 0, parent_block_hash
/// ).
pub fn calculate_block_hash(block_hash_input: &BlockHashInput<'_, '_, '_, '_>) -> BlockHash {
let transactions_commitment = calculate_transactions_commitment::<PoseidonHashCalculator>(
block_hash_input.transaction_leaf_elements,
);
let events_commitment =
calculate_events_commitment::<PoseidonHashCalculator>(block_hash_input.event_leaf_elements);
let receipt_commitment = calculate_receipt_commitment::<PoseidonHashCalculator>(
block_hash_input.transaction_receipts,
);

BlockHash(
HashChain::new()
.chain(&STARKNET_BLOCK_HASH0)
.chain(&block_hash_input.block_number.0.into())
.chain(&block_hash_input.state_root.0)
.chain(&block_hash_input.sequencer_contract_address.0)
.chain(&block_hash_input.timestamp.0.into())
.chain(&concat_counts(
block_hash_input.transaction_leaf_elements.len(),
block_hash_input.event_leaf_elements.len(),
block_hash_input.state_diff.len(),
block_hash_input.l1_da_mode,
))
.chain(&calculate_state_diff_hash(block_hash_input.state_diff).0.0)
.chain(&transactions_commitment.0)
.chain(&events_commitment.0)
.chain(&receipt_commitment.0)
.chain(&block_hash_input.l1_gas_price.price_in_wei.0.into())
.chain(&block_hash_input.l1_gas_price.price_in_fri.0.into())
.chain(&block_hash_input.l1_data_gas_price.price_in_wei.0.into())
.chain(&block_hash_input.l1_data_gas_price.price_in_fri.0.into())
.chain(
&ascii_as_felt(&block_hash_input.starknet_version.0).expect("Expect ASCII version"),
)
.chain(&StarkFelt::ZERO)
.chain(&block_hash_input.parent_hash.0)
.get_poseidon_hash(),
)
}

// 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 ...
// ].
#[allow(dead_code)]
fn concat_counts(
transaction_count: usize,
event_count: usize,
Expand Down
10 changes: 5 additions & 5 deletions src/block_hash/transaction_commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ 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: TransactionSignature,
}

/// Returns the root of a Patricia tree where each leaf is
/// Poseidon(transaction_hash, transaction_signature).
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())
Expand Down
6 changes: 3 additions & 3 deletions src/block_hash/transaction_commitment_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::block_hash::transaction_commitment::{
calculate_transaction_leaf, calculate_transactions_commitment, TransactionLeafElements,
calculate_transaction_leaf, calculate_transactions_commitment, TransactionLeafElement,
};
use crate::core::TransactionCommitment;
use crate::hash::{PoseidonHashCalculator, StarkFelt};
Expand All @@ -10,7 +10,7 @@ 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 };
TransactionLeafElement { transaction_hash, transaction_signature };

let expected_leaf =
StarkFelt::try_from("0x2f0d8840bcf3bc629598d8a6cc80cb7c0d9e52d93dab244bbf9cd0dca0ad082")
Expand All @@ -24,7 +24,7 @@ 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 };
TransactionLeafElement { transaction_hash, transaction_signature };

let expected_root =
StarkFelt::try_from("0x0282b635972328bd1cfa86496fe920d20bd9440cd78ee8dc90ae2b383d664dcf")
Expand Down

0 comments on commit f1d217b

Please sign in to comment.