From 24527f368953caa91b21749fa628c95a1e91451d Mon Sep 17 00:00:00 2001 From: Dori Medini Date: Sun, 13 Oct 2024 20:02:22 +0300 Subject: [PATCH] feat(starknet_api): the StarknetVersion type is now an enum --- crates/papyrus_rpc/src/v0_8/api/test.rs | 6 +- crates/papyrus_storage/src/header_test.rs | 4 +- .../src/serialization/serializers.rs | 22 ++++- crates/papyrus_test_utils/src/lib.rs | 22 ++++- crates/starknet_api/src/block.rs | 89 +++++++++++++++++-- .../src/block_hash/block_hash_calculator.rs | 4 +- crates/starknet_api/src/block_test.rs | 31 ++++--- crates/starknet_api/src/lib.rs | 2 + 8 files changed, 151 insertions(+), 29 deletions(-) diff --git a/crates/papyrus_rpc/src/v0_8/api/test.rs b/crates/papyrus_rpc/src/v0_8/api/test.rs index a535f5e3f9..84814d21f7 100644 --- a/crates/papyrus_rpc/src/v0_8/api/test.rs +++ b/crates/papyrus_rpc/src/v0_8/api/test.rs @@ -494,7 +494,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(vec![123]); + let starknet_version = StarknetVersion::V0_10_0; block.header.block_hash = block_hash; block.header.block_header_without_hash.sequencer = sequencer_address; block.header.block_header_without_hash.timestamp = timestamp; @@ -680,7 +680,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(vec![123]); + let starknet_version = StarknetVersion::V0_10_0; let block_number = block.header.block_header_without_hash.block_number; block.header.block_hash = block_hash; block.header.block_header_without_hash.sequencer = sequencer_address; @@ -882,7 +882,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(vec![123]); + let starknet_version = StarknetVersion::V0_10_0; block.header.block_hash = block_hash; block.header.block_header_without_hash.sequencer = sequencer_address; block.header.block_header_without_hash.timestamp = timestamp; diff --git a/crates/papyrus_storage/src/header_test.rs b/crates/papyrus_storage/src/header_test.rs index 94297a9dc2..b2be22408e 100644 --- a/crates/papyrus_storage/src/header_test.rs +++ b/crates/papyrus_storage/src/header_test.rs @@ -181,8 +181,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(vec![2]); - let yet_another_version = StarknetVersion(vec![3]); + let second_version = StarknetVersion::V0_9_1; + let yet_another_version = StarknetVersion::V0_12_0; writer .begin_rw_txn() diff --git a/crates/papyrus_storage/src/serialization/serializers.rs b/crates/papyrus_storage/src/serialization/serializers.rs index 31f18161a5..f092e69aa5 100644 --- a/crates/papyrus_storage/src/serialization/serializers.rs +++ b/crates/papyrus_storage/src/serialization/serializers.rs @@ -377,7 +377,27 @@ auto_storage_serde! { pub enum StructType { Struct = 0, } - pub struct StarknetVersion(pub Vec); + pub enum StarknetVersion { + V0_9_1 = 0, + V0_10_0 = 1, + V0_10_1 = 2, + V0_10_2 = 3, + V0_10_3 = 4, + V0_11_0 = 5, + V0_11_0_2 = 6, + V0_11_1 = 7, + V0_11_2 = 8, + V0_12_0 = 9, + V0_12_1 = 10, + V0_12_2 = 11, + V0_12_3 = 12, + V0_13_0 = 13, + V0_13_1 = 14, + V0_13_1_1 = 15, + V0_13_2 = 16, + V0_13_2_1 = 17, + V0_13_3 = 18, + } 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 a2e0b65452..1113bc941e 100644 --- a/crates/papyrus_test_utils/src/lib.rs +++ b/crates/papyrus_test_utils/src/lib.rs @@ -474,7 +474,27 @@ auto_impl_get_test_instance! { MulMod = 9, RangeCheck96 = 10, } - pub struct StarknetVersion(pub Vec); + pub enum StarknetVersion { + V0_9_1 = 0, + V0_10_0 = 1, + V0_10_1 = 2, + V0_10_2 = 3, + V0_10_3 = 4, + V0_11_0 = 5, + V0_11_0_2 = 6, + V0_11_1 = 7, + V0_11_2 = 8, + V0_12_0 = 9, + V0_12_1 = 10, + V0_12_2 = 11, + V0_12_3 = 12, + V0_13_0 = 13, + V0_13_1 = 14, + V0_13_1_1 = 15, + V0_13_2 = 16, + V0_13_2_1 = 17, + V0_13_3 = 18, + } 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 1c74cdb859..3877aa7260 100644 --- a/crates/starknet_api/src/block.rs +++ b/crates/starknet_api/src/block.rs @@ -37,18 +37,91 @@ pub struct Block { } /// A version of the Starknet protocol used when creating a block. -#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] -pub struct StarknetVersion(pub Vec); +#[cfg_attr(any(test, feature = "testing"), derive(strum_macros::EnumIter))] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum StarknetVersion { + V0_9_1, + V0_10_0, + V0_10_1, + V0_10_2, + V0_10_3, + V0_11_0, + V0_11_0_2, + V0_11_1, + V0_11_2, + V0_12_0, + V0_12_1, + V0_12_2, + V0_12_3, + V0_13_0, + V0_13_1, + V0_13_1_1, + V0_13_2, + V0_13_2_1, + #[default] + V0_13_3, +} -impl Default for StarknetVersion { - fn default() -> Self { - Self(vec![0, 0, 0]) +impl From for Vec { + fn from(value: StarknetVersion) -> Self { + match value { + StarknetVersion::V0_9_1 => vec![0, 9, 1, 0], + StarknetVersion::V0_10_0 => vec![0, 10, 0, 0], + StarknetVersion::V0_10_1 => vec![0, 10, 1, 0], + StarknetVersion::V0_10_2 => vec![0, 10, 2, 0], + StarknetVersion::V0_10_3 => vec![0, 10, 3, 0], + StarknetVersion::V0_11_0 => vec![0, 11, 0, 0], + StarknetVersion::V0_11_0_2 => vec![0, 11, 0, 2], + StarknetVersion::V0_11_1 => vec![0, 11, 1, 0], + StarknetVersion::V0_11_2 => vec![0, 11, 2, 0], + StarknetVersion::V0_12_0 => vec![0, 12, 0, 0], + StarknetVersion::V0_12_1 => vec![0, 12, 1, 0], + StarknetVersion::V0_12_2 => vec![0, 12, 2, 0], + StarknetVersion::V0_12_3 => vec![0, 12, 3, 0], + StarknetVersion::V0_13_0 => vec![0, 13, 0, 0], + StarknetVersion::V0_13_1 => vec![0, 13, 1, 0], + StarknetVersion::V0_13_1_1 => vec![0, 13, 1, 1], + StarknetVersion::V0_13_2 => vec![0, 13, 2, 0], + StarknetVersion::V0_13_2_1 => vec![0, 13, 2, 1], + StarknetVersion::V0_13_3 => vec![0, 13, 3, 0], + } + } +} + +impl TryFrom> for StarknetVersion { + type Error = StarknetApiError; + fn try_from(value: Vec) -> Result { + if value.len() != 4 { + return Err(StarknetApiError::InvalidStarknetVersion(value)); + } + match (value[0], value[1], value[2], value[3]) { + (0, 9, 1, 0) => Ok(Self::V0_9_1), + (0, 10, 0, 0) => Ok(Self::V0_10_0), + (0, 10, 1, 0) => Ok(Self::V0_10_1), + (0, 10, 2, 0) => Ok(Self::V0_10_2), + (0, 10, 3, 0) => Ok(Self::V0_10_3), + (0, 11, 0, 0) => Ok(Self::V0_11_0), + (0, 11, 0, 2) => Ok(Self::V0_11_0_2), + (0, 11, 1, 0) => Ok(Self::V0_11_1), + (0, 11, 2, 0) => Ok(Self::V0_11_2), + (0, 12, 0, 0) => Ok(Self::V0_12_0), + (0, 12, 1, 0) => Ok(Self::V0_12_1), + (0, 12, 2, 0) => Ok(Self::V0_12_2), + (0, 12, 3, 0) => Ok(Self::V0_12_3), + (0, 13, 0, 0) => Ok(Self::V0_13_0), + (0, 13, 1, 0) => Ok(Self::V0_13_1), + (0, 13, 1, 1) => Ok(Self::V0_13_1_1), + (0, 13, 2, 0) => Ok(Self::V0_13_2), + (0, 13, 2, 1) => Ok(Self::V0_13_2_1), + (0, 13, 3, 0) => Ok(Self::V0_13_3), + _ => Err(StarknetApiError::InvalidStarknetVersion(value)), + } } } impl Display for StarknetVersion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0.iter().map(|x| x.to_string()).join(".")) + write!(f, "{}", Vec::::from(self.clone()).iter().map(|x| x.to_string()).join(".")) } } @@ -57,7 +130,9 @@ impl TryFrom for StarknetVersion { /// 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()?)) + let version: Vec = + starknet_version.split('.').map(|x| x.parse::()).try_collect()?; + Ok(Self::try_from(version)?) } } 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 fe5381d7f0..55b19ac487 100644 --- a/crates/starknet_api/src/block_hash/block_hash_calculator.rs +++ b/crates/starknet_api/src/block_hash/block_hash_calculator.rs @@ -54,8 +54,8 @@ pub enum BlockHashVersion { impl From for StarknetVersion { fn from(value: BlockHashVersion) -> Self { match value { - BlockHashVersion::VO_13_2 => StarknetVersion(vec![0, 13, 2]), - BlockHashVersion::VO_13_3 => StarknetVersion(vec![0, 13, 3]), + BlockHashVersion::VO_13_2 => StarknetVersion::V0_13_2, + BlockHashVersion::VO_13_3 => StarknetVersion::V0_13_3, } } } diff --git a/crates/starknet_api/src/block_test.rs b/crates/starknet_api/src/block_test.rs index bb5b199acf..13b04f8ceb 100644 --- a/crates/starknet_api/src/block_test.rs +++ b/crates/starknet_api/src/block_test.rs @@ -1,4 +1,5 @@ use serde_json::json; +use strum::IntoEnumIterator; use super::{verify_block_signature, StarknetVersion}; use crate::block::{BlockHash, BlockNumber, BlockSignature}; @@ -49,18 +50,22 @@ fn block_signature_verification() { } #[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); +fn test_version_serde() { + for version in StarknetVersion::iter() { + // To/from Vec. + assert_eq!(StarknetVersion::try_from(Vec::::from(version.clone())).unwrap(), version); + // To/from json. + assert_eq!(serde_json::from_value::(json!(version)).unwrap(), version); + } +} - 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])); +/// Order of version variants should match byte-vector lexicographic order. +#[test] +fn test_version_order() { + let versions = StarknetVersion::iter().collect::>(); + for i in 0..(versions.len() - 1) { + for j in i..versions.len() { + assert!(Vec::::from(versions[i]) <= Vec::::from(versions[j])); + } + } } diff --git a/crates/starknet_api/src/lib.rs b/crates/starknet_api/src/lib.rs index f477849667..e789972a03 100644 --- a/crates/starknet_api/src/lib.rs +++ b/crates/starknet_api/src/lib.rs @@ -44,6 +44,8 @@ pub enum StarknetApiError { /// Missing resource type / duplicated resource type. #[error("Missing resource type / duplicated resource type; got {0}.")] InvalidResourceMappingInitializer(String), + #[error("Invalid Starknet version: {0:?}")] + InvalidStarknetVersion(Vec), #[error("NonzeroGasPrice cannot be zero.")] ZeroGasPrice, }