diff --git a/Cargo.lock b/Cargo.lock index f06a3a51df..c48e2cdfbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9025,7 +9025,6 @@ dependencies = [ "mockall", "mockito 1.4.0", "num-bigint 0.4.5", - "num-traits 0.2.19", "papyrus_config", "papyrus_rpc", "pretty_assertions", diff --git a/crates/gateway/Cargo.toml b/crates/gateway/Cargo.toml index fedf252781..b6a8874fc3 100644 --- a/crates/gateway/Cargo.toml +++ b/crates/gateway/Cargo.toml @@ -20,7 +20,6 @@ cairo-vm.workspace = true enum-assoc.workspace = true hyper.workspace = true mempool_test_utils.workspace = true -num-traits.workspace = true papyrus_config.workspace = true papyrus_rpc.workspace = true reqwest.workspace = true diff --git a/crates/gateway/src/compiler_version.rs b/crates/gateway/src/compiler_version.rs index 0aaf177f22..ee35b032bd 100644 --- a/crates/gateway/src/compiler_version.rs +++ b/crates/gateway/src/compiler_version.rs @@ -1,10 +1,11 @@ use std::collections::BTreeMap; use cairo_lang_starknet_classes::compiler_version::VersionId as CairoLangVersionId; -use num_traits::ToPrimitive; +use cairo_lang_starknet_classes::contract_class::version_id_from_serialized_sierra_program; use papyrus_config::dumping::{ser_param, SerializeConfig}; use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; +use starknet_sierra_compile::utils::sierra_program_as_felts_to_big_uint_as_hex; use starknet_types_core::felt::Felt; use thiserror::Error; use validator::Validate; @@ -12,6 +13,8 @@ use validator::Validate; #[derive(Debug, Error)] #[cfg_attr(test, derive(PartialEq))] pub enum VersionIdError { + // TODO(Arni): Consider removing the error message from VersionIdError::InvalidVersion. + // Error messages should be handled or cause a painc. Talk to product. #[error("{message}")] InvalidVersion { message: String }, } @@ -29,15 +32,21 @@ impl VersionId { pub const MAX: Self = Self { major: usize::MAX, minor: usize::MAX, patch: usize::MAX }; } -impl From<&VersionId> for CairoLangVersionId { - fn from(version: &VersionId) -> Self { +impl From for CairoLangVersionId { + fn from(version: VersionId) -> Self { CairoLangVersionId { major: version.major, minor: version.minor, patch: version.patch } } } +impl From for VersionId { + fn from(version: CairoLangVersionId) -> Self { + VersionId { major: version.major, minor: version.minor, patch: version.patch } + } +} + impl std::fmt::Display for VersionId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - CairoLangVersionId::from(self).fmt(f) + CairoLangVersionId::from(*self).fmt(f) } } @@ -45,31 +54,26 @@ impl VersionId { pub fn from_sierra_program(sierra_program: &[Felt]) -> Result { let sierra_program_length = sierra_program.len(); - if sierra_program_length < 3 { + if sierra_program_length < 6 { return Err(VersionIdError::InvalidVersion { message: format!( - "Sierra program is too short. got program of length {} which is not long \ - enough to hold the version field.", + "Sierra program is too short. Got program of length {}, which is not long \ + enough for Sierra program's headers.", sierra_program_length ), }); } + let sierra_program_for_compiler = + sierra_program_as_felts_to_big_uint_as_hex(&sierra_program[..6]); - fn get_version_component( - sierra_program: &[Felt], - index: usize, - ) -> Result { - let felt = &sierra_program[index]; - felt.to_usize().ok_or(VersionIdError::InvalidVersion { - message: format!("version contains a value that is out of range: {:?}", felt), - }) - } + let (version_id, _compiler_version_id) = version_id_from_serialized_sierra_program( + &sierra_program_for_compiler, + ) + .map_err(|err| VersionIdError::InvalidVersion { + message: format!("Error extracting version ID from Sierra program: {err}"), + })?; - Ok(VersionId { - major: get_version_component(sierra_program, 0)?, - minor: get_version_component(sierra_program, 1)?, - patch: get_version_component(sierra_program, 2)?, - }) + Ok(version_id.into()) } } diff --git a/crates/gateway/src/stateless_transaction_validator_test.rs b/crates/gateway/src/stateless_transaction_validator_test.rs index 1fedae9818..a445c8e2ec 100644 --- a/crates/gateway/src/stateless_transaction_validator_test.rs +++ b/crates/gateway/src/stateless_transaction_validator_test.rs @@ -205,8 +205,8 @@ fn test_signature_too_long( vec![], StatelessTransactionValidatorError::InvalidSierraVersion ( VersionIdError::InvalidVersion { - message: "Sierra program is too short. got program of length 0 which is not long enough \ - to hold the version field.".into() + message: "Sierra program is too short. Got program of length 0, which is not \ + long enough for Sierra program's headers.".into() } ) )] @@ -214,17 +214,26 @@ fn test_signature_too_long( vec![felt!(1_u128)], StatelessTransactionValidatorError::InvalidSierraVersion ( VersionIdError::InvalidVersion { - message: "Sierra program is too short. got program of length 1 which is not long enough \ - to hold the version field.".into() + message: "Sierra program is too short. Got program of length 1, which is not \ + long enough for Sierra program's headers.".into() } ) )] -#[case::sierra_program_length_two( - vec![felt!(1_u128), felt!(3_u128)], +#[case::sierra_program_length_three( + vec![felt!(1_u128), felt!(3_u128), felt!(0_u128)], StatelessTransactionValidatorError::InvalidSierraVersion ( VersionIdError::InvalidVersion { - message: "Sierra program is too short. got program of length 2 which is not long enough \ - to hold the version field.".into() + message: "Sierra program is too short. Got program of length 3, which is not \ + long enough for Sierra program's headers.".into() + } + ) +)] +#[case::sierra_program_length_four( + vec![felt!(1_u128), felt!(3_u128), felt!(0_u128), felt!(0_u128)], + StatelessTransactionValidatorError::InvalidSierraVersion ( + VersionIdError::InvalidVersion { + message: "Sierra program is too short. Got program of length 4, which is not \ + long enough for Sierra program's headers.".into() } ) )] @@ -233,11 +242,14 @@ fn test_signature_too_long( felt!(1_u128), felt!(3_u128), felt!(0x10000000000000000_u128), // Does not fit into a usize. + felt!(0_u128), + felt!(0_u128), + felt!(0_u128), ], StatelessTransactionValidatorError::InvalidSierraVersion ( VersionIdError::InvalidVersion { - message: "version contains a value that is out of range: \ - 0x10000000000000000".into() + message: "Error extracting version ID from Sierra program: \ + Invalid input for deserialization.".into() } ) ) @@ -296,8 +308,10 @@ fn test_declare_contract_class_size_too_long() { ..DEFAULT_VALIDATOR_CONFIG_FOR_TESTING }, }; - let contract_class = - ContractClass { sierra_program: vec![felt!(1_u128); 3], ..Default::default() }; + let contract_class = ContractClass { + sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), + ..Default::default() + }; let contract_class_length = serde_json::to_string(&contract_class).unwrap().len(); let tx = external_declare_tx(declare_tx_args!(contract_class)); @@ -359,7 +373,7 @@ fn test_declare_entry_points_not_sorted_by_selector( StatelessTransactionValidator { config: DEFAULT_VALIDATOR_CONFIG_FOR_TESTING }; let contract_class = ContractClass { - sierra_program: vec![felt!(1_u128); 3], + sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), entry_points_by_type: EntryPointByType { constructor: entry_points.clone(), external: vec![], @@ -372,7 +386,7 @@ fn test_declare_entry_points_not_sorted_by_selector( assert_eq!(tx_validator.validate(&tx), expected); let contract_class = ContractClass { - sierra_program: vec![felt!(1_u128); 3], + sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), entry_points_by_type: EntryPointByType { constructor: vec![], external: entry_points.clone(), @@ -385,7 +399,7 @@ fn test_declare_entry_points_not_sorted_by_selector( assert_eq!(tx_validator.validate(&tx), expected); let contract_class = ContractClass { - sierra_program: vec![felt!(1_u128); 3], + sierra_program: create_sierra_program(&MIN_SIERRA_VERSION), entry_points_by_type: EntryPointByType { constructor: vec![], external: vec![], diff --git a/crates/gateway/src/test_utils.rs b/crates/gateway/src/test_utils.rs index b9db31657a..1fac568182 100644 --- a/crates/gateway/src/test_utils.rs +++ b/crates/gateway/src/test_utils.rs @@ -4,8 +4,13 @@ use crate::compiler_version::VersionId; pub fn create_sierra_program(version_id: &VersionId) -> Vec { vec![ + // Sierra Version ID. Felt::from(u64::try_from(version_id.major).unwrap()), Felt::from(u64::try_from(version_id.minor).unwrap()), Felt::from(u64::try_from(version_id.patch).unwrap()), + // Compiler Version ID. + Felt::from(u64::try_from(0).unwrap()), + Felt::from(u64::try_from(0).unwrap()), + Felt::from(u64::try_from(0).unwrap()), ] } diff --git a/crates/mempool_test_utils/src/starknet_api_test_utils.rs b/crates/mempool_test_utils/src/starknet_api_test_utils.rs index bc0460e3b5..7948129d3c 100644 --- a/crates/mempool_test_utils/src/starknet_api_test_utils.rs +++ b/crates/mempool_test_utils/src/starknet_api_test_utils.rs @@ -62,7 +62,16 @@ pub fn external_tx_for_testing( TransactionType::Declare => { // Minimal contract class. let contract_class = ContractClass { - sierra_program: vec![felt!(1_u32), felt!(3_u32), felt!(0_u32)], + sierra_program: vec![ + // Sierra Version ID. + felt!(1_u32), + felt!(3_u32), + felt!(0_u32), + // Compiler version ID. + felt!(1_u32), + felt!(3_u32), + felt!(0_u32), + ], ..Default::default() }; external_declare_tx(declare_tx_args!(resource_bounds, signature, contract_class)) diff --git a/crates/starknet_sierra_compile/src/utils.rs b/crates/starknet_sierra_compile/src/utils.rs index 0a73f3cfd8..e96d0ada5f 100644 --- a/crates/starknet_sierra_compile/src/utils.rs +++ b/crates/starknet_sierra_compile/src/utils.rs @@ -19,7 +19,7 @@ pub fn into_contract_class_for_compilation( rpc_contract_class: &RpcContractClass, ) -> CairoLangContractClass { let sierra_program = - rpc_contract_class.sierra_program.iter().map(felt_to_big_uint_as_hex).collect(); + sierra_program_as_felts_to_big_uint_as_hex(&rpc_contract_class.sierra_program); let entry_points_by_type = into_cairo_lang_contract_entry_points(&rpc_contract_class.entry_points_by_type); @@ -58,6 +58,10 @@ fn into_cairo_lang_contract_entry_point( } } +pub fn sierra_program_as_felts_to_big_uint_as_hex(sierra_program: &[Felt]) -> Vec { + sierra_program.iter().map(felt_to_big_uint_as_hex).collect() +} + fn felt_to_big_uint_as_hex(felt: &Felt) -> BigUintAsHex { BigUintAsHex { value: felt.to_biguint() } }