Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Cargo.lock

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

3 changes: 2 additions & 1 deletion crates/executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ thiserror.workspace = true
tracing.workspace = true

# cairo-native
cairo-lang-starknet-classes = { workspace = true, optional = true }
cairo-native = { version = "0.4.1", optional = true }
cairo-vm.workspace = true
parking_lot.workspace = true
Expand Down Expand Up @@ -49,7 +50,7 @@ pprof.workspace = true
rayon.workspace = true

[features]
native = [ "blockifier/cairo_native", "dep:cairo-native", "dep:rayon" ]
native = [ "blockifier/cairo_native", "dep:cairo-native", "dep:rayon", "dep:cairo-lang-starknet-classes" ]

[[bench]]
harness = false
Expand Down
7 changes: 6 additions & 1 deletion crates/executor/src/implementation/blockifier/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,12 @@ impl ClassCache {
use cairo_native::OptLevel;

#[cfg(feature = "native")]
let program = sierra.extract_sierra_program().unwrap();
let program = cairo_lang_starknet_classes::contract_class::ContractClass::from(
sierra.clone(), // TODO: avoid cloning here
)
.extract_sierra_program()
.unwrap();

#[cfg(feature = "native")]
let entry_points = sierra.entry_points_by_type.clone();

Expand Down
2 changes: 1 addition & 1 deletion crates/gateway/gateway-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use katana_primitives::class::{ClassHash, CompiledClassHash};
use katana_primitives::contract::{Nonce, StorageKey, StorageValue};
use katana_primitives::da::L1DataAvailabilityMode;
use katana_primitives::{ContractAddress, Felt};
pub use katana_rpc_types::class::SierraClass;
pub use katana_rpc_types::class::RpcSierraContractClass;
use serde::{Deserialize, Serialize};
use starknet::core::types::ResourcePrice;

Expand Down
17 changes: 9 additions & 8 deletions crates/gateway/gateway-types/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use katana_primitives::transaction::{
TxWithHash,
};
use katana_primitives::{ContractAddress, Felt};
use katana_rpc_types::SierraClassAbi;
use serde::{Deserialize, Deserializer, Serialize};

/// API response for an INVOKE_FUNCTION transaction
Expand Down Expand Up @@ -257,13 +256,15 @@ pub struct CompressedSierraClass {
pub sierra_program: CompressedSierraProgram,
pub contract_class_version: String,
pub entry_points_by_type: ContractEntryPoints,
pub abi: SierraClassAbi,
pub abi: Option<String>,
}

impl TryFrom<katana_rpc_types::class::SierraClass> for CompressedSierraClass {
impl TryFrom<katana_rpc_types::class::RpcSierraContractClass> for CompressedSierraClass {
type Error = CompressedSierraProgramError;

fn try_from(value: katana_rpc_types::class::SierraClass) -> Result<Self, Self::Error> {
fn try_from(
value: katana_rpc_types::class::RpcSierraContractClass,
) -> Result<Self, Self::Error> {
let abi = value.abi;
let entry_points_by_type = value.entry_points_by_type;
let contract_class_version = value.contract_class_version;
Expand All @@ -272,7 +273,7 @@ impl TryFrom<katana_rpc_types::class::SierraClass> for CompressedSierraClass {
}
}

impl TryFrom<CompressedSierraClass> for katana_rpc_types::class::SierraClass {
impl TryFrom<CompressedSierraClass> for katana_rpc_types::class::RpcSierraContractClass {
type Error = CompressedSierraProgramError;

fn try_from(value: CompressedSierraClass) -> Result<Self, Self::Error> {
Expand Down Expand Up @@ -724,7 +725,7 @@ mod tests {

use katana_primitives::fee::{ResourceBounds, ResourceBoundsMapping, Tip};
use katana_primitives::{address, Felt};
use katana_rpc_types::SierraClass;
use katana_rpc_types::RpcSierraContractClass;

use super::*;

Expand Down Expand Up @@ -772,7 +773,7 @@ mod tests {

#[test]
fn test_conversion_from_rpc_query_declare_tx() {
let sierra_class = Arc::new(katana_rpc_types::class::SierraClass {
let sierra_class = Arc::new(katana_rpc_types::class::RpcSierraContractClass {
sierra_program: vec![Felt::from(0x123), Felt::from(0x456)],
contract_class_version: "0.1.0".to_string(),
entry_points_by_type: Default::default(),
Expand Down Expand Up @@ -820,7 +821,7 @@ mod tests {
assert_eq!(gateway_tx.fee_data_availability_mode, rpc_tx.fee_data_availability_mode.into());

// convert the gateway contract class to rpc contract class and ensure they are equal
let converted_sierra_class: SierraClass =
let converted_sierra_class: RpcSierraContractClass =
gateway_tx.contract_class.as_ref().clone().try_into().unwrap();
assert_eq!(converted_sierra_class, sierra_class.as_ref().clone());
}
Expand Down
7 changes: 5 additions & 2 deletions crates/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ version.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
cairo-vm.workspace = true
cairo-lang-sierra.workspace = true
cairo-lang-utils.workspace = true
cairo-lang-starknet-classes.workspace = true

anyhow.workspace = true
arbitrary = { workspace = true, optional = true }
blockifier = { workspace = true, features = [ "testing" ] } # some Clone derives are gated behind 'testing' feature
cainome-cairo-serde.workspace = true
cairo-lang-starknet-classes.workspace = true
cairo-vm.workspace = true
derive_more.workspace = true
heapless = { version = "0.8.0", features = [ "serde" ] }
lazy_static.workspace = true
Expand Down
115 changes: 94 additions & 21 deletions crates/primitives/src/class.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::str::FromStr;

use cairo_lang_starknet_classes::abi;
use cairo_lang_starknet_classes::casm_contract_class::StarknetSierraCompilationError;
use cairo_lang_starknet_classes::contract_class::{
version_id_from_serialized_sierra_program, ContractEntryPoint, ContractEntryPoints,
};
use cairo_lang_utils::bigint::BigUintAsHex;
use serde_json_pythonic::to_string_pythonic;
use starknet::macros::short_string;
use starknet_api::contract_class::SierraVersion;
Expand All @@ -18,8 +18,6 @@ pub type ClassHash = Felt;
/// The hash of a compiled contract class.
pub type CompiledClassHash = Felt;

/// The canonical contract class (Sierra) type.
pub type SierraContractClass = cairo_lang_starknet_classes::contract_class::ContractClass;
/// The canonical legacy class (Cairo 0) type.
pub type LegacyContractClass = starknet_api::deprecated_contract_class::ContractClass;

Expand All @@ -29,6 +27,97 @@ pub type CasmContractClass = cairo_lang_starknet_classes::casm_contract_class::C
/// ABI for Sierra-based classes.
pub type ContractAbi = cairo_lang_starknet_classes::abi::Contract;

#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize), serde(untagged))]
pub enum MaybeInvalidSierraContractAbi {
Valid(ContractAbi),
Invalid(String),
}

impl std::fmt::Display for MaybeInvalidSierraContractAbi {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MaybeInvalidSierraContractAbi::Valid(abi) => {
let s = to_string_pythonic(abi).expect("failed to serialize abi");
write!(f, "{}", s)
}
MaybeInvalidSierraContractAbi::Invalid(abi) => write!(f, "{}", abi),
}
}
}

impl From<String> for MaybeInvalidSierraContractAbi {
fn from(value: String) -> Self {
match serde_json::from_str::<ContractAbi>(&value) {
Ok(abi) => MaybeInvalidSierraContractAbi::Valid(abi),
Err(..) => MaybeInvalidSierraContractAbi::Invalid(value),
}
}
}

impl From<&str> for MaybeInvalidSierraContractAbi {
fn from(value: &str) -> Self {
match serde_json::from_str::<ContractAbi>(value) {
Ok(abi) => MaybeInvalidSierraContractAbi::Valid(abi),
Err(..) => MaybeInvalidSierraContractAbi::Invalid(value.to_string()),
}
}
}

/// Represents a contract in the Starknet network.
///
/// The canonical contract class (Sierra) type.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
pub struct SierraContractClass {
pub sierra_program: Vec<BigUintAsHex>,
pub sierra_program_debug_info: Option<cairo_lang_sierra::debug_info::DebugInfo>,
pub contract_class_version: String,
pub entry_points_by_type: ContractEntryPoints,
pub abi: Option<MaybeInvalidSierraContractAbi>,
}

impl SierraContractClass {
/// Computes the hash of the Sierra contract class.
pub fn hash(&self) -> ClassHash {
let Self { sierra_program, abi, entry_points_by_type, .. } = self;

let program: Vec<Felt> = sierra_program.iter().map(|f| f.value.clone().into()).collect();
let abi: String = abi.as_ref().map(|abi| abi.to_string()).unwrap_or_default();

compute_sierra_class_hash(&abi, entry_points_by_type, &program)
}
}

impl From<SierraContractClass> for cairo_lang_starknet_classes::contract_class::ContractClass {
fn from(value: SierraContractClass) -> Self {
let abi = value.abi.and_then(|abi| match abi {
MaybeInvalidSierraContractAbi::Invalid(..) => None,
MaybeInvalidSierraContractAbi::Valid(abi) => Some(abi),
});

cairo_lang_starknet_classes::contract_class::ContractClass {
abi,
sierra_program: value.sierra_program,
entry_points_by_type: value.entry_points_by_type,
contract_class_version: value.contract_class_version,
sierra_program_debug_info: value.sierra_program_debug_info,
}
}
}

impl From<cairo_lang_starknet_classes::contract_class::ContractClass> for SierraContractClass {
fn from(value: cairo_lang_starknet_classes::contract_class::ContractClass) -> Self {
SierraContractClass {
abi: value.abi.map(MaybeInvalidSierraContractAbi::Valid),
sierra_program: value.sierra_program,
entry_points_by_type: value.entry_points_by_type,
contract_class_version: value.contract_class_version,
sierra_program_debug_info: value.sierra_program_debug_info,
}
}
}

#[derive(Debug, thiserror::Error)]
pub enum ContractClassCompilationError {
#[error(transparent)]
Expand All @@ -51,23 +140,7 @@ impl ContractClass {
/// Computes the hash of the class.
pub fn class_hash(&self) -> Result<ClassHash, ComputeClassHashError> {
match self {
Self::Class(class) => {
// Technically we don't have to use the Pythonic JSON style here. Doing this just to
// align with the official `cairo-lang` CLI.
//
// TODO: add an `AbiFormatter` trait and let users choose which one to use.
let abi = class.abi.as_ref();
let abi_str = to_string_pythonic(abi.unwrap_or(&abi::Contract::default())).unwrap();

let sierra_program = &class
.sierra_program
.iter()
.map(|f| f.value.clone().into())
.collect::<Vec<Felt>>();

Ok(compute_sierra_class_hash(&abi_str, &class.entry_points_by_type, sierra_program))
}

Self::Class(class) => Ok(class.hash()),
Self::Legacy(class) => compute_legacy_class_hash(class),
}
}
Expand All @@ -77,7 +150,7 @@ impl ContractClass {
match self {
Self::Legacy(class) => Ok(CompiledClass::Legacy(class)),
Self::Class(class) => {
let casm = CasmContractClass::from_contract_class(class, true, usize::MAX)?;
let casm = CasmContractClass::from_contract_class(class.into(), true, usize::MAX)?;
let casm = CompiledClass::Class(casm);
Ok(casm)
}
Expand Down
4 changes: 2 additions & 2 deletions crates/rpc/rpc-server/tests/starknet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ async fn get_compiled_casm() {
// Setup expected compiled class data to verify against

use katana_primitives::class::{ContractClass, SierraContractClass};
use katana_rpc_types::SierraClass as RpcSierraClass;
use katana_rpc_types::RpcSierraContractClass;

let rpc_class = RpcSierraClass::try_from(contract).unwrap();
let rpc_class = RpcSierraContractClass::try_from(contract).unwrap();
let class = SierraContractClass::try_from(rpc_class).unwrap();
let expected_casm = ContractClass::Class(class).compile().unwrap();

Expand Down
1 change: 0 additions & 1 deletion crates/rpc/rpc-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ katana-genesis.workspace = true
katana-trie.workspace = true
serde-utils.workspace = true

derive_more.workspace = true
cainome.workspace = true
cainome-cairo-serde.workspace = true
cairo-lang-starknet-classes.workspace = true
Expand Down
6 changes: 3 additions & 3 deletions crates/rpc/rpc-types/src/broadcasted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use katana_primitives::utils::get_contract_address;
use katana_primitives::{ContractAddress, Felt};
use serde::{de, Deserialize, Deserializer, Serialize};

use crate::class::SierraClass;
use crate::class::RpcSierraContractClass;

pub const QUERY_VERSION_OFFSET: Felt =
Felt::from_raw([576460752142434320, 18446744073709551584, 17407, 18446744073700081665]);
Expand Down Expand Up @@ -71,7 +71,7 @@ pub struct UntypedBroadcastedTx {
pub compiled_class_hash: Option<CompiledClassHash>,

#[serde(default, skip_serializing_if = "Option::is_none")]
pub contract_class: Option<Arc<SierraClass>>,
pub contract_class: Option<Arc<RpcSierraContractClass>>,

// Invoke & Declare only field
#[serde(default, skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -476,7 +476,7 @@ pub struct BroadcastedDeclareTx {
/// a transaction to be valid for execution, the nonce must be equal to the account's current
/// nonce.
pub nonce: Nonce,
pub contract_class: Arc<SierraClass>,
pub contract_class: Arc<RpcSierraContractClass>,
/// Data needed to allow the paymaster to pay for the transaction in native tokens.
pub paymaster_data: Vec<Felt>,
/// The tip for the transaction.
Expand Down
Loading
Loading