diff --git a/crates/gateway/src/errors.rs b/crates/gateway/src/errors.rs index 02e775ea..e4eaa16f 100644 --- a/crates/gateway/src/errors.rs +++ b/crates/gateway/src/errors.rs @@ -21,7 +21,7 @@ pub enum GatewayError { CompilationError(#[from] starknet_sierra_compile::compile::CompilationUtilError), #[error( "The supplied compiled class hash {supplied:?} does not match the hash of the Casm class \ - compiled from the supplied Sierra {hash_result:?}." + compiled from the supplied Sierra {hash_result:?}" )] CompiledClassHashMismatch { supplied: CompiledClassHash, hash_result: CompiledClassHash }, #[error(transparent)] @@ -36,6 +36,8 @@ pub enum GatewayError { StatefulTransactionValidatorError(#[from] StatefulTransactionValidatorError), #[error(transparent)] StatelessTransactionValidatorError(#[from] StatelessTransactionValidatorError), + #[error("{builtins:?} is not a subsquence of {supported_builtins:?}")] + SupportedBuiltins { builtins: Vec, supported_builtins: Vec }, } impl IntoResponse for GatewayError { diff --git a/crates/gateway/src/gateway.rs b/crates/gateway/src/gateway.rs index 12464589..0529818d 100644 --- a/crates/gateway/src/gateway.rs +++ b/crates/gateway/src/gateway.rs @@ -8,6 +8,9 @@ use axum::routing::{get, post}; use axum::{Json, Router}; 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, RPCTransaction}; use starknet_api::transaction::TransactionHash; @@ -22,7 +25,7 @@ use crate::starknet_api_test_utils::get_sender_address; use crate::state_reader::StateReaderFactory; use crate::stateful_transaction_validator::StatefulTransactionValidator; use crate::stateless_transaction_validator::StatelessTransactionValidator; -use crate::utils::external_tx_to_thin_tx; +use crate::utils::{external_tx_to_thin_tx, is_subsequence}; #[cfg(test)] #[path = "gateway_test.rs"] @@ -158,6 +161,7 @@ pub fn compile_contract_class(declare_tx: &RPCDeclareTransaction) -> GatewayResu 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())); @@ -178,3 +182,36 @@ pub fn compile_contract_class(declare_tx: &RPCDeclareTransaction) -> GatewayResu )?; Ok(class_info) } + +// TODO(Arni): Add to a config. +fn get_supported_builtins() -> Vec { + vec![ + "pedersen".to_string(), + "range_check".to_string(), + "ecdsa".to_string(), + "bitwise".to_string(), + "ec_op".to_string(), + "poseidon".to_string(), + "segment_arena".to_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()); + + let supported_builtins = &get_supported_builtins(); + for entry_point in entry_points_iterator { + let builtins = &entry_point.builtins; + println!("{builtins:?}"); + if !is_subsequence(builtins, supported_builtins) { + return Err(GatewayError::SupportedBuiltins { + builtins: builtins.clone(), + supported_builtins: supported_builtins.clone(), + }); + } + } + Ok(()) +} diff --git a/crates/gateway/src/utils.rs b/crates/gateway/src/utils.rs index 2e438f63..672aa816 100644 --- a/crates/gateway/src/utils.rs +++ b/crates/gateway/src/utils.rs @@ -145,3 +145,20 @@ pub fn get_tx_hash(tx: &AccountTransaction) -> TransactionHash { AccountTransaction::Invoke(tx) => tx.tx_hash, } } + +/// Checks whether 'subsequence' is a subsequence of 'sequence'. +pub fn is_subsequence(subsequence: &[String], sequence: &[String]) -> bool { + let mut offset = 0; + + for item in sequence { + if offset == subsequence.len() { + return true; + } + + if item == &subsequence[offset] { + offset += 1; + } + } + + offset == subsequence.len() +}