Skip to content

Commit

Permalink
merge with main
Browse files Browse the repository at this point in the history
  • Loading branch information
maciejka committed Jun 3, 2024
2 parents 245b2cf + 450a32d commit a0e35f2
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 42 deletions.
16 changes: 16 additions & 0 deletions src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ use crate::transaction::{Transaction, TransactionHash, TransactionOutput};
/// A block.
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
pub struct Block {
// TODO: Consider renaming to BlockWithCommitments, for the header use BlockHeaderWithoutHash
// instead of BlockHeader, and add BlockHeaderCommitments and BlockHash fields.
pub header: BlockHeader,
pub body: BlockBody,
}
Expand Down Expand Up @@ -76,6 +78,20 @@ pub struct BlockHeader {
pub starknet_version: StarknetVersion,
}

/// The header of a [Block](`crate::block::Block`) without hashing.
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)]
pub struct BlockHeaderWithoutHash {
pub parent_hash: BlockHash,
pub block_number: BlockNumber,
pub l1_gas_price: GasPricePerToken,
pub l1_data_gas_price: GasPricePerToken,
pub state_root: GlobalRoot,
pub sequencer: SequencerContractAddress,
pub timestamp: BlockTimestamp,
pub l1_da_mode: L1DataAvailabilityMode,
pub starknet_version: StarknetVersion,
}

/// The [transactions](`crate::transaction::Transaction`) and their
/// [outputs](`crate::transaction::TransactionOutput`) in a [block](`crate::block::Block`).
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
Expand Down
43 changes: 41 additions & 2 deletions src/block_hash/block_hash_calculator.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
use once_cell::sync::Lazy;
use starknet_types_core::felt::Felt;
use starknet_types_core::hash::Poseidon;

use super::event_commitment::{calculate_events_commitment, EventLeafElement};
use super::receipt_commitment::{calculate_receipt_commitment, ReceiptElement};
use super::state_diff_hash::calculate_state_diff_hash;
use super::transaction_commitment::{calculate_transactions_commitment, TransactionLeafElement};
use crate::block::GasPricePerToken;
use crate::block::{BlockHash, BlockHeaderWithoutHash, GasPricePerToken};
use crate::core::{EventCommitment, ReceiptCommitment, StateDiffCommitment, TransactionCommitment};
use crate::crypto::utils::HashChain;
use crate::data_availability::L1DataAvailabilityMode;
use crate::state::ThinStateDiff;
use crate::transaction::{
TransactionHash, TransactionOutputCommon, TransactionSignature, TransactionVersion,
};
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<Felt> = Lazy::new(|| {
ascii_as_felt("STARKNET_BLOCK_HASH0").expect("ascii_as_felt failed for 'STARKNET_BLOCK_HASH0'")
});

pub struct TransactionHashingData {
pub transaction_signature: Option<TransactionSignature>,
pub transaction_output: TransactionOutputCommon,
Expand All @@ -33,6 +40,39 @@ pub struct BlockHeaderCommitments {
pub concatenated_counts: Felt,
}

/// 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(
header: BlockHeaderWithoutHash,
block_commitments: BlockHeaderCommitments,
) -> BlockHash {
BlockHash(
HashChain::new()
.chain(&STARKNET_BLOCK_HASH0)
.chain(&header.block_number.0.into())
.chain(&header.state_root.0)
.chain(&header.sequencer.0)
.chain(&header.timestamp.0.into())
.chain(&block_commitments.concatenated_counts)
.chain(&block_commitments.state_diff_commitment.0.0)
.chain(&block_commitments.transactions_commitment.0)
.chain(&block_commitments.events_commitment.0)
.chain(&block_commitments.receipts_commitment.0)
.chain(&header.l1_gas_price.price_in_wei.0.into())
.chain(&header.l1_gas_price.price_in_fri.0.into())
.chain(&header.l1_data_gas_price.price_in_wei.0.into())
.chain(&header.l1_data_gas_price.price_in_fri.0.into())
.chain(&ascii_as_felt(&header.starknet_version.0).expect("Expect ASCII version"))
.chain(&Felt::ZERO)
.chain(&header.parent_hash.0)
.get_poseidon_hash(),
)
}

/// Calculates the commitments of the transactions data for the block hash.
pub fn calculate_block_commitments(
transactions_data: &[TransactionHashingData],
Expand Down Expand Up @@ -84,7 +124,6 @@ pub fn calculate_block_commitments(
// 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
49 changes: 49 additions & 0 deletions src/block_hash/block_hash_calculator_test.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,56 @@
use starknet_types_core::felt::Felt;

use super::concat_counts;
use crate::block::{
BlockHash, BlockHeaderWithoutHash, BlockNumber, BlockTimestamp, GasPrice, GasPricePerToken,
StarknetVersion,
};
use crate::block_hash::block_hash_calculator::{
calculate_block_commitments, calculate_block_hash, TransactionHashingData,
};
use crate::block_hash::test_utils::{get_state_diff, get_transaction_output};
use crate::core::{ContractAddress, GlobalRoot, PatriciaKey, SequencerContractAddress};
use crate::data_availability::L1DataAvailabilityMode;
use crate::felt;
use crate::hash::{FeltConverter, TryIntoFelt};
use crate::transaction::{TransactionHash, TransactionSignature, TransactionVersion};

#[test]
fn test_block_hash_regression() {
let block_header = BlockHeaderWithoutHash {
block_number: BlockNumber(1_u64),
state_root: GlobalRoot(Felt::from(2_u8)),
sequencer: SequencerContractAddress(ContractAddress(PatriciaKey::from(3_u8))),
timestamp: BlockTimestamp(4),
l1_da_mode: L1DataAvailabilityMode::Blob,
l1_gas_price: GasPricePerToken { price_in_fri: GasPrice(6), price_in_wei: GasPrice(7) },
l1_data_gas_price: GasPricePerToken {
price_in_fri: GasPrice(10),
price_in_wei: GasPrice(9),
},
starknet_version: StarknetVersion("10".to_owned()),
parent_hash: BlockHash(Felt::from(11_u8)),
};
let transactions_data = vec![TransactionHashingData {
transaction_signature: Some(TransactionSignature(vec![Felt::TWO, Felt::THREE])),
transaction_output: get_transaction_output(),
transaction_hash: TransactionHash(Felt::ONE),
transaction_version: TransactionVersion::THREE,
}];

let state_diff = get_state_diff();
let block_commitments = calculate_block_commitments(
&transactions_data,
&state_diff,
block_header.l1_data_gas_price,
block_header.l1_gas_price,
block_header.l1_da_mode,
);

let expected_hash = felt!("0x061e4998d51a248f1d0288d7e17f6287757b0e5e6c5e1e58ddf740616e312134");

assert_eq!(BlockHash(expected_hash), calculate_block_hash(block_header, block_commitments),);
}

#[test]
fn concat_counts_test() {
Expand Down
19 changes: 13 additions & 6 deletions src/block_hash/state_diff_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ static STARKNET_STATE_DIFF0: Lazy<Felt> = Lazy::new(|| {
pub fn calculate_state_diff_hash(state_diff: &ThinStateDiff) -> StateDiffCommitment {
let mut hash_chain = HashChain::new();
hash_chain = hash_chain.chain(&STARKNET_STATE_DIFF0);
hash_chain = chain_deployed_contracts(&state_diff.deployed_contracts, hash_chain);
hash_chain = chain_updated_contracts(
&state_diff.deployed_contracts,
&state_diff.replaced_classes,
hash_chain,
);
hash_chain = chain_declared_classes(&state_diff.declared_classes, hash_chain);
hash_chain =
chain_deprecated_declared_classes(&state_diff.deprecated_declared_classes, hash_chain);
Expand All @@ -34,14 +38,17 @@ pub fn calculate_state_diff_hash(state_diff: &ThinStateDiff) -> StateDiffCommitm
StateDiffCommitment(PoseidonHash(hash_chain.get_poseidon_hash()))
}

// Chains: [number_of_deployed_contracts, address_0, class_hash_0, address_1, class_hash_1, ...].
fn chain_deployed_contracts(
// Chains: [number_of_updated_contracts, address_0, class_hash_0, address_1, class_hash_1, ...].
// The updated contracts includes deployed contracts and replaced classes.
fn chain_updated_contracts(
deployed_contracts: &IndexMap<ContractAddress, ClassHash>,
replaced_classes: &IndexMap<ContractAddress, ClassHash>,
mut hash_chain: HashChain,
) -> HashChain {
hash_chain = hash_chain.chain(&deployed_contracts.len().into());
for (address, class_hash) in sorted_index_map(deployed_contracts) {
hash_chain = hash_chain.chain(&address.0).chain(&class_hash);
let updated_contracts = deployed_contracts.iter().chain(replaced_classes.iter());
hash_chain = hash_chain.chain(&(deployed_contracts.len() + replaced_classes.len()).into());
for (address, class_hash) in sorted_index_map(&updated_contracts.collect()) {
hash_chain = hash_chain.chain(&address.0).chain(class_hash);
}
hash_chain
}
Expand Down
49 changes: 16 additions & 33 deletions src/block_hash/state_diff_hash_test.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,21 @@
use indexmap::indexmap;

use crate::block_hash::state_diff_hash::{
calculate_state_diff_hash, chain_declared_classes, chain_deployed_contracts,
chain_deprecated_declared_classes, chain_nonces, chain_storage_diffs,
calculate_state_diff_hash, chain_declared_classes, chain_deprecated_declared_classes,
chain_nonces, chain_storage_diffs, chain_updated_contracts,
};
use crate::block_hash::test_utils::get_state_diff;
use crate::core::{ClassHash, CompiledClassHash, Nonce, StateDiffCommitment};
use crate::crypto::utils::HashChain;
use crate::felt;
use crate::hash::{FeltConverter, PoseidonHash, TryIntoFelt};
use crate::state::ThinStateDiff;

#[test]
fn test_state_diff_hash_regression() {
let state_diff = ThinStateDiff {
deployed_contracts: indexmap! {
0u64.into() => ClassHash(1u64.into()),
2u64.into() => ClassHash(3u64.into()),
},
storage_diffs: indexmap! {
4u64.into() => indexmap! {
5u64.into() => 6u64.into(),
7u64.into() => 8u64.into(),
},
9u64.into() => indexmap! {
10u64.into() => 11u64.into(),
},
},
declared_classes: indexmap! {
ClassHash(12u64.into()) => CompiledClassHash(13u64.into()),
ClassHash(14u64.into()) => CompiledClassHash(15u64.into()),
},
deprecated_declared_classes: vec![ClassHash(16u64.into())],
nonces: indexmap! {
17u64.into() => Nonce(18u64.into()),
},
replaced_classes: indexmap! {
19u64.into() => ClassHash(20u64.into()),
},
};
let state_diff = get_state_diff();

let expected_hash = StateDiffCommitment(PoseidonHash(felt!(
"0x05b8241020c186585f4273cf991d35ad703e808bd9b40242cec584e7f2d86495"
"0x0281f5966e49ad7dad9323826d53d1d27c0c4e6ebe5525e2e2fbca549bfa0a67"
)));

assert_eq!(expected_hash, calculate_state_diff_hash(&state_diff));
Expand All @@ -52,13 +27,21 @@ fn test_sorting_deployed_contracts() {
0u64.into() => ClassHash(3u64.into()),
1u64.into() => ClassHash(2u64.into()),
};
let replaced_classes_0 = indexmap! {
2u64.into() => ClassHash(1u64.into()),
};
let deployed_contracts_1 = indexmap! {
1u64.into() => ClassHash(2u64.into()),
2u64.into() => ClassHash(1u64.into()),
0u64.into() => ClassHash(3u64.into()),
};
let replaced_classes_1 = indexmap! {
1u64.into() => ClassHash(2u64.into()),
};
assert_eq!(
chain_deployed_contracts(&deployed_contracts_0, HashChain::new()).get_poseidon_hash(),
chain_deployed_contracts(&deployed_contracts_1, HashChain::new()).get_poseidon_hash(),
chain_updated_contracts(&deployed_contracts_0, &replaced_classes_0, HashChain::new())
.get_poseidon_hash(),
chain_updated_contracts(&deployed_contracts_1, &replaced_classes_1, HashChain::new())
.get_poseidon_hash(),
);
}

Expand Down
33 changes: 32 additions & 1 deletion src/block_hash/test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::collections::HashMap;

use indexmap::indexmap;
use primitive_types::H160;
use starknet_types_core::felt::Felt;

use crate::core::{ContractAddress, EthAddress};
use crate::core::{ClassHash, CompiledClassHash, ContractAddress, EthAddress, Nonce};
use crate::state::ThinStateDiff;
use crate::transaction::{
Builtin, ExecutionResources, Fee, L2ToL1Payload, MessageToL1,
RevertedTransactionExecutionStatus, TransactionExecutionStatus, TransactionOutputCommon,
Expand Down Expand Up @@ -37,3 +39,32 @@ pub(crate) fn generate_message_to_l1(seed: u64) -> MessageToL1 {
payload: L2ToL1Payload(vec![Felt::from(seed + 2), Felt::from(seed + 3)]),
}
}

pub(crate) fn get_state_diff() -> ThinStateDiff {
ThinStateDiff {
deployed_contracts: indexmap! {
0u64.into() => ClassHash(1u64.into()),
2u64.into() => ClassHash(3u64.into()),
},
storage_diffs: indexmap! {
4u64.into() => indexmap! {
5u64.into() => 6u64.into(),
7u64.into() => 8u64.into(),
},
9u64.into() => indexmap! {
10u64.into() => 11u64.into(),
},
},
declared_classes: indexmap! {
ClassHash(12u64.into()) => CompiledClassHash(13u64.into()),
ClassHash(14u64.into()) => CompiledClassHash(15u64.into()),
},
deprecated_declared_classes: vec![ClassHash(16u64.into())],
nonces: indexmap! {
17u64.into() => Nonce(18u64.into()),
},
replaced_classes: indexmap! {
19u64.into() => ClassHash(20u64.into()),
},
}
}

0 comments on commit a0e35f2

Please sign in to comment.