Skip to content

Commit

Permalink
feat: compile sierra to casm in declare tx
Browse files Browse the repository at this point in the history
  • Loading branch information
ArniStarkware committed Jun 17, 2024
1 parent 3efd4a5 commit 42eaf2b
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 3 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ blockifier = { git = "https://github.com/starkware-libs/blockifier.git", rev = "
cairo-lang-sierra = "2.6.0"
cairo-lang-starknet-classes = "2.6.0"
cairo-lang-utils = "2.6.0"
cairo-vm = "0.9.2"
clap = "4.3.10"
colored = "2.1.0"
const_format = "0.2.30"
Expand All @@ -50,6 +51,7 @@ futures = "0.3.30"
hyper = { version = "0.14", features = ["client", "http1"] }
indexmap = "2.1.0"
itertools = "0.13.0"
num-bigint = { version = "0.4.5", default-features = false }
# TODO(YaelD, 28/5/2024): The special Papyrus version is needed in order to be aligned with the
# starknet-api version. This should be removed once we have a mono-repo.
papyrus_common = { git = "https://github.com/starkware-libs/papyrus.git", rev = "5d37fc32" }
Expand Down
2 changes: 2 additions & 0 deletions crates/gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ testing = []
axum.workspace = true
blockifier.workspace = true
cairo-lang-starknet-classes.workspace = true
cairo-vm.workspace = true
hyper.workspace = true
indexmap.workspace = true
papyrus_common.workspace = true
Expand All @@ -27,6 +28,7 @@ serde_json.workspace = true
starknet_api.workspace = true
starknet_client.workspace = true
starknet_mempool_types = { path = "../mempool_types", version = "0.0" }
starknet_sierra_compile ={ path = "../starknet_sierra_compile", version = "0.0" }
strum.workspace = true
tempfile.workspace = true
thiserror.workspace = true
Expand Down
5 changes: 5 additions & 0 deletions crates/gateway/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use axum::response::{IntoResponse, Response};
use blockifier::blockifier::stateful_validator::StatefulValidatorError;
use blockifier::state::errors::StateError;
use blockifier::transaction::errors::TransactionExecutionError;
use cairo_vm::types::errors::program_errors::ProgramError;
use starknet_api::block::BlockNumber;
use starknet_api::transaction::{Resource, ResourceBounds};
use starknet_api::StarknetApiError;
Expand All @@ -12,6 +13,8 @@ use tokio::task::JoinError;
/// Errors directed towards the end-user, as a result of gateway requests.
#[derive(Debug, Error)]
pub enum GatewayError {
#[error(transparent)]
CompilationError(#[from] starknet_sierra_compile::compile::CompilationUtilError),
#[error("Internal server error: {0}")]
InternalServerError(#[from] JoinError),
#[error("Error sending message: {0}")]
Expand All @@ -20,6 +23,8 @@ pub enum GatewayError {
StatefulTransactionValidatorError(#[from] StatefulTransactionValidatorError),
#[error(transparent)]
StatelessTransactionValidatorError(#[from] StatelessTransactionValidatorError),
#[error(transparent)]
ProgramError(#[from] ProgramError),
}

impl IntoResponse for GatewayError {
Expand Down
60 changes: 57 additions & 3 deletions crates/gateway/src/gateway.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
use std::clone::Clone;
use std::net::SocketAddr;
use std::panic;
use std::sync::Arc;

use axum::extract::State;
use axum::routing::{get, post};
use axum::{Json, Router};
use starknet_api::external_transaction::ExternalTransaction;
use blockifier::execution::contract_class::{ClassInfo, ContractClassV1};
use blockifier::execution::errors::ContractClassError;
use starknet_api::external_transaction::{ExternalDeclareTransaction, ExternalTransaction};
use starknet_api::transaction::TransactionHash;
use starknet_mempool_types::communication::SharedMempoolClient;
use starknet_mempool_types::mempool_types::{Account, MempoolInput};
use starknet_sierra_compile::compile::{compile_sierra_to_casm, CompilationUtilError};
use starknet_sierra_compile::utils::into_contract_class_for_compilation;

use crate::config::{GatewayConfig, GatewayNetworkConfig};
use crate::errors::{GatewayError, GatewayRunError};
Expand Down Expand Up @@ -118,11 +123,60 @@ fn process_tx(
// Perform stateless validations.
stateless_tx_validator.validate(&tx)?;

// TODO(Yael, 19/5/2024): pass the relevant class_info and deploy_account_hash.
let tx_hash = stateful_tx_validator.run_validate(state_reader_factory, &tx, None, None)?;
// Compile Sierra to Casm.
let optional_class_info = match &tx {
ExternalTransaction::Declare(declare_tx) => Some(compile_contract_class(declare_tx)?),
_ => None,
};

// TODO(Yael, 19/5/2024): pass the relevant deploy_account_hash.
let tx_hash =
stateful_tx_validator.run_validate(state_reader_factory, &tx, optional_class_info, None)?;

// TODO(Arni): Add the Sierra and the Casm to the mempool input.
Ok(MempoolInput {
tx: external_tx_to_thin_tx(&tx, tx_hash),
account: Account { sender_address: get_sender_address(&tx), ..Default::default() },
})
}

/// Formats the contract class for compilation, compiles it, and returns the compiled contract class
/// wrapped in a [`ClassInfo`].
/// Assumes the contract class is of a Sierra program which is compiled to Casm.
fn compile_contract_class(declare_tx: &ExternalDeclareTransaction) -> GatewayResult<ClassInfo> {
let ExternalDeclareTransaction::V3(tx) = declare_tx;
let starknet_api_contract_class = &tx.contract_class;
let cairo_lang_contract_class =
into_contract_class_for_compilation(starknet_api_contract_class);

// Compile Sierra to Casm.
let catch_unwind_result =
panic::catch_unwind(|| compile_sierra_to_casm(cairo_lang_contract_class));
let casm_contract_class = match catch_unwind_result {
Ok(compilation_result) => compilation_result?,
Err(_) => {
// TODO(Arni): Log the panic.
return Err(GatewayError::CompilationError(CompilationUtilError::CompilationPanic));
}
};

// Convert Casm contract class to Starknet contract class directly.
let blockifier_contract_class = ContractClassV1::try_from(casm_contract_class)?.into();
let class_info = match ClassInfo::new(
&blockifier_contract_class,
starknet_api_contract_class.sierra_program.len(),
starknet_api_contract_class.abi.len(),
) {
Ok(class_info) => class_info,
Err(ContractClassError::ContractClassVersionSierraProgramLengthMismatch {
contract_class_version: _,
sierra_program_length: _,
}) => {
panic!(
"Sierra program length mismatch. Version 3 declare transaction should always have \
Sierra program (of length > 0) which matches a V1 contract class."
);
}
};
Ok(class_info)
}
2 changes: 2 additions & 0 deletions crates/starknet_sierra_compile/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ workspace = true
cairo-lang-sierra.workspace = true
cairo-lang-starknet-classes.workspace = true
cairo-lang-utils.workspace = true
num-bigint.workspace = true
serde_json.workspace = true
serde.workspace = true
starknet_api.workspace = true
thiserror.workspace = true

[dev-dependencies]
Expand Down
2 changes: 2 additions & 0 deletions crates/starknet_sierra_compile/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub enum CompilationUtilError {
AllowedLibfuncsError(#[from] AllowedLibfuncsError),
#[error(transparent)]
StarknetSierraCompilationError(#[from] StarknetSierraCompilationError),
#[error("Compilation panicked")]
CompilationPanic,
}

/// This function may panic.
Expand Down
1 change: 1 addition & 0 deletions crates/starknet_sierra_compile/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! A lib for compiling Sierra into Casm.
pub mod compile;
pub mod utils;

#[cfg(any(feature = "testing", test))]
pub mod test_utils;
69 changes: 69 additions & 0 deletions crates/starknet_sierra_compile/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use std::clone::Clone;

use cairo_lang_starknet_classes::contract_class::{
ContractClass as CairoLangContractClass, ContractEntryPoint as CairoLangContractEntryPoint,
ContractEntryPoints as CairoLangContractEntryPoints,
};
use cairo_lang_utils::bigint::BigUintAsHex;
use num_bigint::BigUint;
use starknet_api::external_transaction::{
ContractClass as StarknetApiContractClass, EntryPointByType as StarknetApiEntryPointByType,
};
use starknet_api::hash::StarkFelt;
use starknet_api::state::EntryPoint as StarknetApiEntryPoint;

/// Retruns a [`CairoLangContractClass`] struct ready for Sierra to Casm compilation. Note the `abi`
/// field is None as it is not relevant for the compilation.
pub fn into_contract_class_for_compilation(
starknet_api_contract_class: &StarknetApiContractClass,
) -> CairoLangContractClass {
let sierra_program = starknet_api_contract_class
.sierra_program
.iter()
.map(stark_felt_to_big_uint_as_hex)
.collect();
let entry_points_by_type =
into_cairo_lang_contract_entry_points(&starknet_api_contract_class.entry_points_by_type);

CairoLangContractClass {
sierra_program,
sierra_program_debug_info: None,
contract_class_version: starknet_api_contract_class.contract_class_version.clone(),
entry_points_by_type,
abi: None,
}
}

fn into_cairo_lang_contract_entry_points(
entry_points_by_type: &StarknetApiEntryPointByType,
) -> CairoLangContractEntryPoints {
let StarknetApiEntryPointByType { constructor, external, l1handler } = entry_points_by_type;
CairoLangContractEntryPoints {
external: into_cairo_lang_contract_entry_points_vec(external),
l1_handler: into_cairo_lang_contract_entry_points_vec(l1handler),
constructor: into_cairo_lang_contract_entry_points_vec(constructor),
}
}

fn into_cairo_lang_contract_entry_points_vec(
entry_points: &[StarknetApiEntryPoint],
) -> Vec<CairoLangContractEntryPoint> {
entry_points.iter().map(into_cairo_lang_contract_entry_point).collect()
}

fn into_cairo_lang_contract_entry_point(
entry_point: &StarknetApiEntryPoint,
) -> CairoLangContractEntryPoint {
CairoLangContractEntryPoint {
selector: stark_felt_to_big_uint(&entry_point.selector.0),
function_idx: entry_point.function_idx.0,
}
}

fn stark_felt_to_big_uint_as_hex(stark_felt: &StarkFelt) -> BigUintAsHex {
BigUintAsHex { value: stark_felt_to_big_uint(stark_felt) }
}

fn stark_felt_to_big_uint(stark_felt: &StarkFelt) -> BigUint {
BigUint::from_bytes_be(stark_felt.bytes())
}

0 comments on commit 42eaf2b

Please sign in to comment.