Skip to content

Commit

Permalink
feat(starknet_api): bump block hash constant prefix (#1244)
Browse files Browse the repository at this point in the history
  • Loading branch information
yoavGrs authored Oct 8, 2024
1 parent 2c9e09a commit 1b7252f
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 20 deletions.
3 changes: 2 additions & 1 deletion crates/committer_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ async fn main() {
let block_hash_input: BlockHashInput = load_from_stdin();
info!("Successfully loaded block hash input.");
let block_hash =
calculate_block_hash(block_hash_input.header, block_hash_input.block_commitments);
calculate_block_hash(block_hash_input.header, block_hash_input.block_commitments)
.unwrap_or_else(|error| panic!("Failed to calculate block hash: {}", error));
write_to_file(&output_path, &block_hash);
info!("Successfully computed block hash {:?}.", block_hash);
}
Expand Down
53 changes: 42 additions & 11 deletions crates/starknet_api/src/block_hash/block_hash_calculator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::transaction::{
TransactionHash,
TransactionSignature,
};
use crate::{StarknetApiError, StarknetApiResult};

#[cfg(test)]
#[path = "block_hash_calculator_test.rs"]
Expand All @@ -36,12 +37,15 @@ mod block_hash_calculator_test;
static STARKNET_BLOCK_HASH0: LazyLock<Felt> = LazyLock::new(|| {
ascii_as_felt("STARKNET_BLOCK_HASH0").expect("ascii_as_felt failed for 'STARKNET_BLOCK_HASH0'")
});
static STARKNET_BLOCK_HASH1: LazyLock<Felt> = LazyLock::new(|| {
ascii_as_felt("STARKNET_BLOCK_HASH1").expect("ascii_as_felt failed for 'STARKNET_BLOCK_HASH1'")
});
static STARKNET_GAS_PRICES0: LazyLock<Felt> = LazyLock::new(|| {
ascii_as_felt("STARKNET_GAS_PRICES0").expect("ascii_as_felt failed for 'STARKNET_GAS_PRICES0'")
});

#[allow(non_camel_case_types)]
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd)]
pub enum BlockHashVersion {
VO_13_2,
VO_13_3,
Expand All @@ -50,8 +54,34 @@ pub enum BlockHashVersion {
impl From<BlockHashVersion> for StarknetVersion {
fn from(value: BlockHashVersion) -> Self {
match value {
BlockHashVersion::VO_13_2 => Self(vec![0, 13, 2]),
BlockHashVersion::VO_13_3 => Self(vec![0, 13, 3]),
BlockHashVersion::VO_13_2 => StarknetVersion(vec![0, 13, 2]),
BlockHashVersion::VO_13_3 => StarknetVersion(vec![0, 13, 3]),
}
}
}

impl TryFrom<StarknetVersion> for BlockHashVersion {
type Error = StarknetApiError;

fn try_from(value: StarknetVersion) -> StarknetApiResult<Self> {
if value < Self::VO_13_2.into() {
Err(StarknetApiError::BlockHashVersion { version: value.to_string() })
} else if value < Self::VO_13_3.into() {
Ok(Self::VO_13_2)
} else {
Ok(Self::VO_13_3)
}
}
}

// The prefix constant for the block hash calculation.
type BlockHashConstant = Felt;

impl From<BlockHashVersion> for BlockHashConstant {
fn from(block_hash_version: BlockHashVersion) -> Self {
match block_hash_version {
BlockHashVersion::VO_13_2 => *STARKNET_BLOCK_HASH0,
BlockHashVersion::VO_13_3 => *STARKNET_BLOCK_HASH1,
}
}
}
Expand Down Expand Up @@ -84,17 +114,18 @@ pub struct BlockHeaderCommitments {
}

/// Poseidon (
/// “STARKNET_BLOCK_HASH0”, block_number, global_state_root, sequencer_address,
/// block_hash_constant, block_number, global_state_root, sequencer_address,
/// block_timestamp, concat_counts, state_diff_hash, transaction_commitment,
/// event_commitment, receipt_commitment, gas_prices, starknet_version, 0, parent_block_hash
/// ).
pub fn calculate_block_hash(
header: BlockHeaderWithoutHash,
block_commitments: BlockHeaderCommitments,
) -> BlockHash {
BlockHash(
) -> StarknetApiResult<BlockHash> {
let block_hash_version: BlockHashVersion = header.starknet_version.clone().try_into()?;
Ok(BlockHash(
HashChain::new()
.chain(&STARKNET_BLOCK_HASH0)
.chain(&block_hash_version.clone().into())
.chain(&header.block_number.0.into())
.chain(&header.state_root.0)
.chain(&header.sequencer.0)
Expand All @@ -109,7 +140,7 @@ pub fn calculate_block_hash(
&header.l1_gas_price,
&header.l1_data_gas_price,
&header.l2_gas_price,
&header.starknet_version,
&block_hash_version,
)
.iter(),
)
Expand All @@ -119,7 +150,7 @@ pub fn calculate_block_hash(
.chain(&Felt::ZERO)
.chain(&header.parent_hash.0)
.get_poseidon_hash(),
)
))
}

/// Calculates the commitments of the transactions data for the block hash.
Expand Down Expand Up @@ -215,9 +246,9 @@ fn gas_prices_to_hash(
l1_gas_price: &GasPricePerToken,
l1_data_gas_price: &GasPricePerToken,
l2_gas_price: &GasPricePerToken,
starknet_version: &StarknetVersion,
block_hash_version: &BlockHashVersion,
) -> Vec<Felt> {
if *starknet_version >= BlockHashVersion::VO_13_3.into() {
if block_hash_version >= &BlockHashVersion::VO_13_3 {
vec![
HashChain::new()
.chain(&STARKNET_GAS_PRICES0)
Expand Down
19 changes: 11 additions & 8 deletions crates/starknet_api/src/block_hash/block_hash_calculator_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,26 +44,27 @@ macro_rules! test_hash_changes {
{
let header = BlockHeaderWithoutHash {
l1_da_mode: L1DataAvailabilityMode::Blob,
starknet_version: BlockHashVersion::VO_13_3.into(),
$($header_field: $header_value),*
};
let commitments = BlockHeaderCommitments {
$($commitments_field: $commitments_value),*
};
let original_hash = calculate_block_hash(header.clone(), commitments.clone());
let original_hash = calculate_block_hash(header.clone(), commitments.clone()).unwrap();

$(
// Test changing the field in the header.
let mut modified_header = header.clone();
modified_header.$header_field = Default::default();
let new_hash = calculate_block_hash(modified_header, commitments.clone());
let new_hash = calculate_block_hash(modified_header, commitments.clone()).unwrap();
assert_ne!(original_hash, new_hash, concat!("Hash should change when ", stringify!($header_field), " is modified"));
)*

$(
// Test changing the field in the commitments.
let mut modified_commitments = commitments.clone();
modified_commitments.$commitments_field = Default::default();
let new_hash = calculate_block_hash(header.clone(), modified_commitments);
let new_hash = calculate_block_hash(header.clone(), modified_commitments).unwrap();
assert_ne!(original_hash, new_hash, concat!("Hash should change when ", stringify!($commitments_field), " is modified"));
)*
}
Expand All @@ -87,7 +88,7 @@ fn test_block_hash_regression(
price_in_wei: 9_u8.into(),
},
l2_gas_price: GasPricePerToken { price_in_fri: 11_u8.into(), price_in_wei: 12_u8.into() },
starknet_version: block_hash_version.to_owned().into(),
starknet_version: block_hash_version.clone().into(),
parent_hash: BlockHash(Felt::from(11_u8)),
};
let transactions_data = vec![TransactionHashingData {
Expand All @@ -109,11 +110,14 @@ fn test_block_hash_regression(
felt!("0xe248d6ce583f8fa48d1d401d4beb9ceced3733e38d8eacb0d8d3669a7d901c")
}
BlockHashVersion::VO_13_3 => {
felt!("0x65b653f5bc0939cdc39f98230affc8fbd1a01ea801e025271a4cfba912ba59a")
felt!("0x566c0aaa2bb5fbd7957224108f089100d58f1d8767dd2b53698e27efbf2a28b")
}
};

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

#[test]
Expand Down Expand Up @@ -159,8 +163,7 @@ fn change_field_of_hash_input() {
l2_gas_price: GasPricePerToken { price_in_fri: 1_u8.into(), price_in_wei: 1_u8.into() },
state_root: GlobalRoot(Felt::ONE),
sequencer: SequencerContractAddress(ContractAddress::from(1_u128)),
timestamp: BlockTimestamp(1),
starknet_version: BlockHashVersion::VO_13_3.into()
timestamp: BlockTimestamp(1)
},
BlockHeaderCommitments {
transaction_commitment: TransactionCommitment(Felt::ONE),
Expand Down
5 changes: 5 additions & 0 deletions crates/starknet_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ use serde_utils::InnerDeserializationError;
// Note: if you need `Eq` see InnerDeserializationError's docstring.
#[derive(thiserror::Error, Clone, Debug, PartialEq)]
pub enum StarknetApiError {
/// An error when a starknet version is out of range.
#[error("Starknet version {version} is out of range for block hash calculation")]
BlockHashVersion { version: String },
/// Error in the inner deserialization of the node.
#[error(transparent)]
InnerDeserialization(#[from] InnerDeserializationError),
Expand All @@ -44,3 +47,5 @@ pub enum StarknetApiError {
#[error("NonzeroGasPrice cannot be zero.")]
ZeroGasPrice,
}

pub type StarknetApiResult<T> = Result<T, StarknetApiError>;

0 comments on commit 1b7252f

Please sign in to comment.