Skip to content

Commit

Permalink
chore: use cairo lang util to extract sierra program version id (#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
ArniStarkware authored Aug 12, 2024
1 parent 650ebd3 commit f92adc2
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 40 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion crates/gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 25 additions & 21 deletions crates/gateway/src/compiler_version.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
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;

#[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 },
}
Expand All @@ -29,47 +32,48 @@ 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<VersionId> for CairoLangVersionId {
fn from(version: VersionId) -> Self {
CairoLangVersionId { major: version.major, minor: version.minor, patch: version.patch }
}
}

impl From<CairoLangVersionId> 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)
}
}

impl VersionId {
pub fn from_sierra_program(sierra_program: &[Felt]) -> Result<Self, VersionIdError> {
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<usize, VersionIdError> {
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())
}
}

Expand Down
44 changes: 29 additions & 15 deletions crates/gateway/src/stateless_transaction_validator_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,26 +205,35 @@ 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()
}
)
)]
#[case::sierra_program_length_one(
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()
}
)
)]
Expand All @@ -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()
}
)
)
Expand Down Expand Up @@ -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));

Expand Down Expand Up @@ -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![],
Expand All @@ -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(),
Expand All @@ -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![],
Expand Down
5 changes: 5 additions & 0 deletions crates/gateway/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ use crate::compiler_version::VersionId;

pub fn create_sierra_program(version_id: &VersionId) -> Vec<Felt> {
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()),
]
}
11 changes: 10 additions & 1 deletion crates/mempool_test_utils/src/starknet_api_test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
6 changes: 5 additions & 1 deletion crates/starknet_sierra_compile/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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<BigUintAsHex> {
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() }
}

0 comments on commit f92adc2

Please sign in to comment.