diff --git a/crates/papyrus_execution/src/execution_test.rs b/crates/papyrus_execution/src/execution_test.rs index 78aea699e4..9dde083e0c 100644 --- a/crates/papyrus_execution/src/execution_test.rs +++ b/crates/papyrus_execution/src/execution_test.rs @@ -850,9 +850,9 @@ fn blockifier_error_mapping() { // Test that we retrieve the correct versioned constants. #[test] fn test_get_versioned_constants() { - let starknet_version_13_0 = StarknetVersion("0.13.0".to_string()); - let starknet_version_13_1 = StarknetVersion("0.13.1".to_string()); - let starknet_version_13_2 = StarknetVersion("0.13.2".to_string()); + let starknet_version_13_0 = StarknetVersion::try_from("0.13.0".to_string()).unwrap(); + let starknet_version_13_1 = StarknetVersion::try_from("0.13.1".to_string()).unwrap(); + let starknet_version_13_2 = StarknetVersion::try_from("0.13.2".to_string()).unwrap(); let versioned_constants = get_versioned_constants(Some(&starknet_version_13_0)).unwrap(); assert_eq!(versioned_constants.invoke_tx_max_n_steps, 3_000_000); let versioned_constants = get_versioned_constants(Some(&starknet_version_13_1)).unwrap(); diff --git a/crates/papyrus_protobuf/src/converters/header.rs b/crates/papyrus_protobuf/src/converters/header.rs index d5175c7df1..279064e185 100644 --- a/crates/papyrus_protobuf/src/converters/header.rs +++ b/crates/papyrus_protobuf/src/converters/header.rs @@ -136,7 +136,15 @@ impl TryFrom for SignedBlockHeader { let l1_da_mode = enum_int_to_l1_data_availability_mode(value.l1_data_availability_mode)?; - let starknet_version = StarknetVersion(value.protocol_version); + let starknet_version = match StarknetVersion::try_from(value.protocol_version.to_owned()) { + Ok(version) => version, + Err(_) => { + return Err(ProtobufConversionError::OutOfRangeValue { + type_description: "starknet version", + value_as_str: value.protocol_version, + }); + } + }; let l1_gas_price = GasPricePerToken { price_in_fri: GasPrice( @@ -259,7 +267,7 @@ impl From<(BlockHeader, Vec)> for protobuf::SignedBlockHeader { receipts: header .receipt_commitment .map(|receipt_commitment| receipt_commitment.0.into()), - protocol_version: header.starknet_version.0, + protocol_version: header.starknet_version.to_string(), gas_price_wei: Some(header.l1_gas_price.price_in_wei.0.into()), gas_price_fri: Some(header.l1_gas_price.price_in_fri.0.into()), data_gas_price_wei: Some(header.l1_data_gas_price.price_in_wei.0.into()), diff --git a/crates/papyrus_rpc/src/v0_6/api/api_impl.rs b/crates/papyrus_rpc/src/v0_6/api/api_impl.rs index 8a91b6aad8..655e21b365 100644 --- a/crates/papyrus_rpc/src/v0_6/api/api_impl.rs +++ b/crates/papyrus_rpc/src/v0_6/api/api_impl.rs @@ -1472,7 +1472,7 @@ async fn read_pending_data( strk_l1_gas_price: latest_header.l1_gas_price.price_in_fri, timestamp: latest_header.timestamp, sequencer_address: latest_header.sequencer, - starknet_version: latest_header.starknet_version.0, + starknet_version: latest_header.starknet_version.to_string(), ..Default::default() }), state_update: ClientPendingStateUpdate { diff --git a/crates/papyrus_rpc/src/v0_6/api/test.rs b/crates/papyrus_rpc/src/v0_6/api/test.rs index 94f4ae69e0..cc5fc10697 100644 --- a/crates/papyrus_rpc/src/v0_6/api/test.rs +++ b/crates/papyrus_rpc/src/v0_6/api/test.rs @@ -477,7 +477,7 @@ async fn get_block_w_full_transactions() { let block_hash = BlockHash(random::().into()); let sequencer_address = SequencerContractAddress(random::().into()); let timestamp = BlockTimestamp(random::()); - let starknet_version = StarknetVersion("test".to_owned()); + let starknet_version = StarknetVersion(vec![123]); block.header.block_hash = block_hash; block.header.sequencer = sequencer_address; block.header.timestamp = timestamp; @@ -595,7 +595,7 @@ async fn get_block_w_full_transactions() { price_in_wei: pending_l1_gas_price.price_in_wei, price_in_fri: pending_l1_gas_price.price_in_fri, }, - starknet_version: starknet_version.0.clone(), + starknet_version: starknet_version.to_string(), }), status: None, transactions: Transactions::Full(rpc_transactions), @@ -608,7 +608,7 @@ async fn get_block_w_full_transactions() { *pending_block.timestamp_mutable() = pending_timestamp; *pending_block.sequencer_address_mutable() = pending_sequencer_address; pending_block.set_l1_gas_price(&pending_l1_gas_price); - *pending_block.starknet_version_mutable() = starknet_version.0; + *pending_block.starknet_version_mutable() = starknet_version.to_string(); } // Using call_api_then_assert_and_validate_schema_for_result in order to validate the schema for // pending block. @@ -651,7 +651,7 @@ async fn get_block_w_transaction_hashes() { let block_hash = BlockHash(random::().into()); let sequencer_address = SequencerContractAddress(random::().into()); let timestamp = BlockTimestamp(random::()); - let starknet_version = StarknetVersion("test".to_owned()); + let starknet_version = StarknetVersion(vec![123]); block.header.block_hash = block_hash; block.header.sequencer = sequencer_address; block.header.timestamp = timestamp; @@ -765,7 +765,7 @@ async fn get_block_w_transaction_hashes() { price_in_wei: pending_l1_gas_price.price_in_wei, price_in_fri: pending_l1_gas_price.price_in_fri, }, - starknet_version: starknet_version.0.clone(), + starknet_version: starknet_version.to_string(), }), status: None, transactions: Transactions::Hashes( @@ -783,7 +783,7 @@ async fn get_block_w_transaction_hashes() { *pending_block.timestamp_mutable() = pending_timestamp; *pending_block.sequencer_address_mutable() = pending_sequencer_address; pending_block.set_l1_gas_price(&pending_l1_gas_price); - *pending_block.starknet_version_mutable() = starknet_version.0; + *pending_block.starknet_version_mutable() = starknet_version.to_string(); } // Using call_api_then_assert_and_validate_schema_for_result in order to validate the schema for // pending block. diff --git a/crates/papyrus_rpc/src/v0_6/block.rs b/crates/papyrus_rpc/src/v0_6/block.rs index da3c35a662..24bccdb61a 100644 --- a/crates/papyrus_rpc/src/v0_6/block.rs +++ b/crates/papyrus_rpc/src/v0_6/block.rs @@ -53,7 +53,7 @@ impl From for BlockHeader { price_in_wei: header.l1_gas_price.price_in_wei, price_in_fri: header.l1_gas_price.price_in_fri, }, - starknet_version: header.starknet_version.0, + starknet_version: header.starknet_version.to_string(), } } } diff --git a/crates/papyrus_rpc/src/v0_7/api/api_impl.rs b/crates/papyrus_rpc/src/v0_7/api/api_impl.rs index fc503f168c..c88f7186c9 100644 --- a/crates/papyrus_rpc/src/v0_7/api/api_impl.rs +++ b/crates/papyrus_rpc/src/v0_7/api/api_impl.rs @@ -1492,7 +1492,7 @@ async fn read_pending_data( strk_l1_gas_price: latest_header.l1_gas_price.price_in_fri, timestamp: latest_header.timestamp, sequencer_address: latest_header.sequencer, - starknet_version: latest_header.starknet_version.0, + starknet_version: latest_header.starknet_version.to_string(), ..Default::default() }), state_update: ClientPendingStateUpdate { diff --git a/crates/papyrus_rpc/src/v0_7/api/test.rs b/crates/papyrus_rpc/src/v0_7/api/test.rs index 4da2add3a4..96523e23a9 100644 --- a/crates/papyrus_rpc/src/v0_7/api/test.rs +++ b/crates/papyrus_rpc/src/v0_7/api/test.rs @@ -485,7 +485,7 @@ async fn get_block_w_full_transactions() { let block_hash = BlockHash(random::().into()); let sequencer_address = SequencerContractAddress(random::().into()); let timestamp = BlockTimestamp(random::()); - let starknet_version = StarknetVersion("test".to_owned()); + let starknet_version = StarknetVersion(vec![123]); block.header.block_hash = block_hash; block.header.sequencer = sequencer_address; block.header.timestamp = timestamp; @@ -605,7 +605,7 @@ async fn get_block_w_full_transactions() { }, l1_data_gas_price: ResourcePrice::default(), l1_da_mode: L1DataAvailabilityMode::Calldata, - starknet_version: starknet_version.0.clone(), + starknet_version: starknet_version.to_string(), }), status: None, transactions: Transactions::Full(rpc_transactions), @@ -618,7 +618,7 @@ async fn get_block_w_full_transactions() { *pending_block.timestamp_mutable() = pending_timestamp; *pending_block.sequencer_address_mutable() = pending_sequencer_address; pending_block.set_l1_gas_price(&pending_l1_gas_price); - *pending_block.starknet_version_mutable() = starknet_version.0; + *pending_block.starknet_version_mutable() = starknet_version.to_string(); } // Using call_api_then_assert_and_validate_schema_for_result in order to validate the schema for // pending block. @@ -662,7 +662,7 @@ async fn get_block_w_full_transactions_and_receipts() { let block_hash = BlockHash(random::().into()); let sequencer_address = SequencerContractAddress(random::().into()); let timestamp = BlockTimestamp(random::()); - let starknet_version = StarknetVersion("test".to_owned()); + let starknet_version = StarknetVersion(vec![123]); let block_number = block.header.block_number; block.header.block_hash = block_hash; block.header.sequencer = sequencer_address; @@ -788,7 +788,7 @@ async fn get_block_w_full_transactions_and_receipts() { }, l1_data_gas_price: ResourcePrice::default(), l1_da_mode: L1DataAvailabilityMode::Calldata, - starknet_version: starknet_version.0.clone(), + starknet_version: starknet_version.to_string(), }), status: None, transactions: Transactions::FullWithReceipts( @@ -811,7 +811,7 @@ async fn get_block_w_full_transactions_and_receipts() { *pending_block.timestamp_mutable() = pending_timestamp; *pending_block.sequencer_address_mutable() = pending_sequencer_address; pending_block.set_l1_gas_price(&pending_l1_gas_price); - *pending_block.starknet_version_mutable() = starknet_version.0; + *pending_block.starknet_version_mutable() = starknet_version.to_string(); } // Using call_api_then_assert_and_validate_schema_for_result again in order to validate the // schema for pending block too. @@ -855,7 +855,7 @@ async fn get_block_w_transaction_hashes() { let block_hash = BlockHash(random::().into()); let sequencer_address = SequencerContractAddress(random::().into()); let timestamp = BlockTimestamp(random::()); - let starknet_version = StarknetVersion("test".to_owned()); + let starknet_version = StarknetVersion(vec![123]); block.header.block_hash = block_hash; block.header.sequencer = sequencer_address; block.header.timestamp = timestamp; @@ -971,7 +971,7 @@ async fn get_block_w_transaction_hashes() { }, l1_data_gas_price: ResourcePrice::default(), l1_da_mode: L1DataAvailabilityMode::Calldata, - starknet_version: starknet_version.0.clone(), + starknet_version: starknet_version.to_string(), }), status: None, transactions: Transactions::Hashes( @@ -989,7 +989,7 @@ async fn get_block_w_transaction_hashes() { *pending_block.timestamp_mutable() = pending_timestamp; *pending_block.sequencer_address_mutable() = pending_sequencer_address; pending_block.set_l1_gas_price(&pending_l1_gas_price); - *pending_block.starknet_version_mutable() = starknet_version.0; + *pending_block.starknet_version_mutable() = starknet_version.to_string(); } // Using call_api_then_assert_and_validate_schema_for_result in order to validate the schema for // pending block. diff --git a/crates/papyrus_rpc/src/v0_7/block.rs b/crates/papyrus_rpc/src/v0_7/block.rs index 0fc352f09b..e1f6c9f0de 100644 --- a/crates/papyrus_rpc/src/v0_7/block.rs +++ b/crates/papyrus_rpc/src/v0_7/block.rs @@ -63,7 +63,7 @@ impl From for BlockHeader { price_in_fri: header.l1_data_gas_price.price_in_fri, }, l1_da_mode: header.l1_da_mode, - starknet_version: header.starknet_version.0, + starknet_version: header.starknet_version.to_string(), } } } diff --git a/crates/papyrus_storage/src/header_test.rs b/crates/papyrus_storage/src/header_test.rs index d5342cfad4..4bbc0d745c 100644 --- a/crates/papyrus_storage/src/header_test.rs +++ b/crates/papyrus_storage/src/header_test.rs @@ -172,8 +172,8 @@ async fn starknet_version() { reader.begin_ro_txn().unwrap().get_starknet_version(BlockNumber(1)).unwrap(); assert!(non_existing_block_starknet_version.is_none()); - let second_version = StarknetVersion("second_version".to_string()); - let yet_another_version = StarknetVersion("yet_another_version".to_string()); + let second_version = StarknetVersion(vec![2]); + let yet_another_version = StarknetVersion(vec![3]); writer .begin_rw_txn() diff --git a/crates/papyrus_storage/src/serialization/serializers.rs b/crates/papyrus_storage/src/serialization/serializers.rs index f707da82ac..0a32509541 100644 --- a/crates/papyrus_storage/src/serialization/serializers.rs +++ b/crates/papyrus_storage/src/serialization/serializers.rs @@ -386,7 +386,7 @@ auto_storage_serde! { pub enum StructType { Struct = 0, } - pub struct StarknetVersion(pub String); + pub struct StarknetVersion(pub Vec); pub struct StateDiffCommitment(pub PoseidonHash); pub struct Tip(pub u64); pub struct TransactionCommitment(pub StarkHash); diff --git a/crates/papyrus_test_utils/src/lib.rs b/crates/papyrus_test_utils/src/lib.rs index 012f2331c2..1f125f35d0 100644 --- a/crates/papyrus_test_utils/src/lib.rs +++ b/crates/papyrus_test_utils/src/lib.rs @@ -479,7 +479,7 @@ auto_impl_get_test_instance! { MulMod = 9, RangeCheck96 = 10, } - pub struct StarknetVersion(pub String); + pub struct StarknetVersion(pub Vec); pub struct Calldata(pub Arc>); pub struct ClassHash(pub StarkHash); pub struct CompiledClassHash(pub StarkHash); diff --git a/crates/starknet_api/src/block.rs b/crates/starknet_api/src/block.rs index dd0737f23b..da6dfd082c 100644 --- a/crates/starknet_api/src/block.rs +++ b/crates/starknet_api/src/block.rs @@ -5,6 +5,7 @@ mod block_test; use std::fmt::Display; use derive_more::Display; +use itertools::Itertools; use serde::{Deserialize, Serialize}; use starknet_types_core::hash::{Poseidon, StarkHash as CoreStarkHash}; @@ -22,6 +23,7 @@ use crate::data_availability::L1DataAvailabilityMode; use crate::hash::StarkHash; use crate::serde_utils::{BytesAsHex, PrefixedBytesAsHex}; use crate::transaction::{Transaction, TransactionHash, TransactionOutput}; +use crate::StarknetApiError; /// A block. #[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)] @@ -33,18 +35,49 @@ pub struct Block { } /// A version of the Starknet protocol used when creating a block. -#[derive(Clone, Debug, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] -pub struct StarknetVersion(pub String); +#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub struct StarknetVersion(pub Vec); impl Default for StarknetVersion { fn default() -> Self { - Self("0.0.0".to_string()) + Self(vec![0, 0, 0]) } } impl Display for StarknetVersion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) + write!(f, "{}", self.0.iter().map(|x| x.to_string()).join(".")) + } +} + +impl TryFrom for StarknetVersion { + type Error = StarknetApiError; + + /// Parses a string separated by dots into a StarknetVersion. + fn try_from(starknet_version: String) -> Result { + Ok(Self(starknet_version.split('.').map(|x| x.parse::()).try_collect()?)) + } +} + +impl Serialize for StarknetVersion { + fn serialize( + &self, + serializer: S, + ) -> Result<::Ok, ::Error> + where + S: serde::Serializer, + { + self.to_string().serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for StarknetVersion { + fn deserialize(deserializer: D) -> Result>::Error> + where + D: serde::Deserializer<'de>, + { + let version = String::deserialize(deserializer)?; + StarknetVersion::try_from(version).map_err(serde::de::Error::custom) } } diff --git a/crates/starknet_api/src/block_hash/block_hash_calculator.rs b/crates/starknet_api/src/block_hash/block_hash_calculator.rs index ae16d69cef..fd0ee1377b 100644 --- a/crates/starknet_api/src/block_hash/block_hash_calculator.rs +++ b/crates/starknet_api/src/block_hash/block_hash_calculator.rs @@ -42,8 +42,8 @@ pub enum BlockHashVersion { impl From for StarknetVersion { fn from(value: BlockHashVersion) -> Self { match value { - BlockHashVersion::VO_13_2 => Self("0.13.2".to_owned()), - BlockHashVersion::VO_13_3 => Self("0.13.3".to_owned()), + BlockHashVersion::VO_13_2 => Self(vec![0, 13, 2]), + BlockHashVersion::VO_13_3 => Self(vec![0, 13, 3]), } } } @@ -107,7 +107,9 @@ pub fn calculate_block_hash( (header.starknet_version >= BlockHashVersion::VO_13_3.into()) .then_some(l2_gas_prices.into_iter()) }) - .chain(&ascii_as_felt(&header.starknet_version.0).expect("Expect ASCII version")) + .chain( + &ascii_as_felt(&header.starknet_version.to_string()).expect("Expect ASCII version"), + ) .chain(&Felt::ZERO) .chain(&header.parent_hash.0) .get_poseidon_hash(), diff --git a/crates/starknet_api/src/block_test.rs b/crates/starknet_api/src/block_test.rs index 632ed6d871..bb5b199acf 100644 --- a/crates/starknet_api/src/block_test.rs +++ b/crates/starknet_api/src/block_test.rs @@ -1,4 +1,6 @@ -use super::verify_block_signature; +use serde_json::json; + +use super::{verify_block_signature, StarknetVersion}; use crate::block::{BlockHash, BlockNumber, BlockSignature}; use crate::core::{GlobalRoot, SequencerPublicKey}; use crate::crypto::utils::{PublicKey, Signature}; @@ -45,3 +47,20 @@ fn block_signature_verification() { .unwrap() ); } + +#[test] +fn test_vec_version() { + assert_eq!(StarknetVersion::default().to_string(), "0.0.0"); + + let version_123 = StarknetVersion::try_from("1.2.3".to_owned()).unwrap(); + assert_eq!(version_123, StarknetVersion(vec![1, 2, 3])); + + let serialized_123 = json!(version_123); + assert_eq!(serialized_123, "1.2.3".to_owned()); + assert_eq!(serde_json::from_value::(serialized_123).unwrap(), version_123); + + assert!(StarknetVersion(vec![0, 10, 0]) > StarknetVersion(vec![0, 2, 5])); + assert!(StarknetVersion(vec![0, 13, 1]) > StarknetVersion(vec![0, 12, 2])); + assert!(StarknetVersion(vec![0, 13, 0, 1]) > StarknetVersion(vec![0, 13, 0])); + assert!(StarknetVersion(vec![0, 13, 0]) > StarknetVersion(vec![0, 13])); +} diff --git a/crates/starknet_client/src/reader/objects/block.rs b/crates/starknet_client/src/reader/objects/block.rs index fdda5eceaa..e5de2de716 100644 --- a/crates/starknet_client/src/reader/objects/block.rs +++ b/crates/starknet_client/src/reader/objects/block.rs @@ -52,7 +52,7 @@ pub struct BlockPostV0_13_1 { pub transaction_receipts: Vec, // Default since old blocks don't include this field. #[serde(default)] - pub starknet_version: String, + pub starknet_version: StarknetVersion, // Additions to the block structure in V0.13.1. pub l1_da_mode: L1DataAvailabilityMode, // Replacing the eth_l1_gas_price & strk_l1_gas_price fields with a single field. @@ -213,7 +213,7 @@ impl Block { } } - pub fn starknet_version(&self) -> String { + pub fn starknet_version(&self) -> StarknetVersion { match self { Block::PostV0_13_1(block) => block.starknet_version.clone(), } @@ -305,7 +305,7 @@ impl Block { state_diff_length: self.state_diff_length(), n_transactions, n_events, - starknet_version: StarknetVersion(self.starknet_version()), + starknet_version: self.starknet_version(), }; let (transactions, transaction_receipts) = self.get_body();