-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: code to compilation file from gateway
- Loading branch information
1 parent
c553217
commit 0f229c0
Showing
7 changed files
with
185 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
use std::panic; | ||
use std::sync::OnceLock; | ||
|
||
use blockifier::execution::contract_class::{ClassInfo, ContractClass, ContractClassV1}; | ||
use blockifier::execution::execution_utils::felt_to_stark_felt; | ||
use cairo_lang_starknet_classes::casm_contract_class::{ | ||
CasmContractClass, CasmContractEntryPoints, | ||
}; | ||
use starknet_api::core::CompiledClassHash; | ||
use starknet_api::rpc_transaction::RPCDeclareTransaction; | ||
use starknet_api::transaction::Builtin; | ||
use starknet_sierra_compile::compile::compile_sierra_to_casm; | ||
use starknet_sierra_compile::errors::CompilationUtilError; | ||
use starknet_sierra_compile::utils::into_contract_class_for_compilation; | ||
|
||
use crate::errors::{GatewayError, GatewayResult}; | ||
use crate::utils::{is_subsequence, IntoEnumIteratorExt}; | ||
|
||
#[cfg(test)] | ||
#[path = "compilation_test.rs"] | ||
mod compilation_test; | ||
|
||
/// 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. | ||
pub fn compile_contract_class(declare_tx: &RPCDeclareTransaction) -> GatewayResult<ClassInfo> { | ||
let RPCDeclareTransaction::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)); | ||
} | ||
}; | ||
validate_casm_class(&casm_contract_class)?; | ||
|
||
let hash_result = | ||
CompiledClassHash(felt_to_stark_felt(&casm_contract_class.compiled_class_hash())); | ||
if hash_result != tx.compiled_class_hash { | ||
return Err(GatewayError::CompiledClassHashMismatch { | ||
supplied: tx.compiled_class_hash, | ||
hash_result, | ||
}); | ||
} | ||
|
||
// Convert Casm contract class to Starknet contract class directly. | ||
let blockifier_contract_class = | ||
ContractClass::V1(ContractClassV1::try_from(casm_contract_class)?); | ||
let class_info = ClassInfo::new( | ||
&blockifier_contract_class, | ||
starknet_api_contract_class.sierra_program.len(), | ||
starknet_api_contract_class.abi.len(), | ||
)?; | ||
Ok(class_info) | ||
} | ||
|
||
// TODO(Arni): Consider moving into Starknet-api. | ||
// List of supported builtins. | ||
// This is an explicit function so that it is explicitly desiced which builtins are supported. | ||
// If new builtins are added, they should be added here. | ||
fn is_supported_builtin(builtin: &Builtin) -> bool { | ||
match builtin { | ||
Builtin::RangeCheck | ||
| Builtin::Pedersen | ||
| Builtin::Poseidon | ||
| Builtin::EcOp | ||
| Builtin::Ecdsa | ||
| Builtin::Bitwise | ||
| Builtin::SegmentArena => true, | ||
Builtin::Keccak => false, | ||
} | ||
} | ||
|
||
// TODO(Arni): Add to a config. | ||
// TODO(Arni): Use the Builtin enum from Starknet-api, and explicitly tag each builtin as supported | ||
// or unsupported so that the compiler would alert us on new builtins. | ||
fn supported_builtins() -> &'static Vec<String> { | ||
static SUPPORTED_BUILTINS: OnceLock<Vec<String>> = OnceLock::new(); | ||
SUPPORTED_BUILTINS.get_or_init(|| { | ||
Builtin::iter() | ||
.filter(is_supported_builtin) | ||
.map(|builtin| builtin.name().to_string()) | ||
.collect::<Vec<String>>() | ||
}) | ||
} | ||
|
||
// TODO(Arni): Add test. | ||
fn validate_casm_class(contract_class: &CasmContractClass) -> Result<(), GatewayError> { | ||
let CasmContractEntryPoints { external, l1_handler, constructor } = | ||
&contract_class.entry_points_by_type; | ||
let entry_points_iterator = external.iter().chain(l1_handler.iter()).chain(constructor.iter()); | ||
|
||
for entry_point in entry_points_iterator { | ||
let builtins = &entry_point.builtins; | ||
if !is_subsequence(builtins, supported_builtins()) { | ||
return Err(GatewayError::UnsupportedBuiltins { | ||
builtins: builtins.clone(), | ||
supported_builtins: supported_builtins().to_vec(), | ||
}); | ||
} | ||
} | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
use assert_matches::assert_matches; | ||
use blockifier::execution::contract_class::ContractClass; | ||
use cairo_lang_starknet_classes::allowed_libfuncs::AllowedLibfuncsError; | ||
use starknet_api::core::CompiledClassHash; | ||
use starknet_api::rpc_transaction::{RPCDeclareTransaction, RPCTransaction}; | ||
use starknet_sierra_compile::errors::CompilationUtilError; | ||
use test_utils::starknet_api_test_utils::declare_tx; | ||
|
||
use crate::compilation::compile_contract_class; | ||
use crate::errors::GatewayError; | ||
|
||
#[test] | ||
fn test_compile_contract_class_compiled_class_hash_missmatch() { | ||
let mut tx = assert_matches!( | ||
declare_tx(), | ||
RPCTransaction::Declare(RPCDeclareTransaction::V3(tx)) => tx | ||
); | ||
let expected_hash_result = tx.compiled_class_hash; | ||
let supplied_hash = CompiledClassHash::default(); | ||
|
||
tx.compiled_class_hash = supplied_hash; | ||
let declare_tx = RPCDeclareTransaction::V3(tx); | ||
|
||
let result = compile_contract_class(&declare_tx); | ||
assert_matches!( | ||
result.unwrap_err(), | ||
GatewayError::CompiledClassHashMismatch { supplied, hash_result } | ||
if supplied == supplied_hash && hash_result == expected_hash_result | ||
); | ||
} | ||
|
||
#[test] | ||
fn test_compile_contract_class_bad_sierra() { | ||
let mut tx = assert_matches!( | ||
declare_tx(), | ||
RPCTransaction::Declare(RPCDeclareTransaction::V3(tx)) => tx | ||
); | ||
// Truncate the sierra program to trigger an error. | ||
tx.contract_class.sierra_program = tx.contract_class.sierra_program[..100].to_vec(); | ||
let declare_tx = RPCDeclareTransaction::V3(tx); | ||
|
||
let result = compile_contract_class(&declare_tx); | ||
assert_matches!( | ||
result.unwrap_err(), | ||
GatewayError::CompilationError(CompilationUtilError::AllowedLibfuncsError( | ||
AllowedLibfuncsError::SierraProgramError | ||
)) | ||
) | ||
} | ||
|
||
#[test] | ||
fn test_compile_contract_class() { | ||
let declare_tx = assert_matches!( | ||
declare_tx(), | ||
RPCTransaction::Declare(declare_tx) => declare_tx | ||
); | ||
let RPCDeclareTransaction::V3(declare_tx_v3) = &declare_tx; | ||
let contract_class = &declare_tx_v3.contract_class; | ||
|
||
let class_info = compile_contract_class(&declare_tx).unwrap(); | ||
assert_matches!(class_info.contract_class(), ContractClass::V1(_)); | ||
assert_eq!(class_info.sierra_program_length(), contract_class.sierra_program.len()); | ||
assert_eq!(class_info.abi_length(), contract_class.abi.len()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.