From f75f21dd7e86c765ba6970e1e0087cd53cfd6859 Mon Sep 17 00:00:00 2001 From: Arni Hod Date: Thu, 1 Aug 2024 15:28:42 +0300 Subject: [PATCH] feat: post compilation size limit validation --- config/mempool/default_config.json | 7 +++- crates/gateway/src/compilation.rs | 36 +++++++++++++++++- crates/gateway/src/compilation_test.rs | 25 ++++++++---- crates/gateway/src/config.rs | 38 +++++++++++++++++-- crates/gateway/src/errors.rs | 8 ++++ crates/gateway/src/gateway.rs | 7 +--- crates/gateway/src/gateway_test.rs | 14 +++---- .../stateful_transaction_validator_test.rs | 11 ++---- 8 files changed, 112 insertions(+), 34 deletions(-) diff --git a/config/mempool/default_config.json b/config/mempool/default_config.json index 2671161c300..9d57ed70624 100644 --- a/config/mempool/default_config.json +++ b/config/mempool/default_config.json @@ -14,6 +14,11 @@ "privacy": "Public", "value": 81920 }, + "gateway_config.compiler_config.max_raw_casm_class_size": { + "description": "Limitation of contract class object size.", + "privacy": "Public", + "value": 4089446 + }, "gateway_config.network_config.ip": { "description": "The gateway server ip.", "privacy": "Public", @@ -119,4 +124,4 @@ "privacy": "Public", "value": "" } -} \ No newline at end of file +} diff --git a/crates/gateway/src/compilation.rs b/crates/gateway/src/compilation.rs index acdfe1335b1..a74e96364fb 100644 --- a/crates/gateway/src/compilation.rs +++ b/crates/gateway/src/compilation.rs @@ -9,6 +9,7 @@ use starknet_sierra_compile::compile::SierraToCasmCompiler; use starknet_sierra_compile::errors::CompilationUtilError; use starknet_sierra_compile::utils::into_contract_class_for_compilation; +use crate::config::{GatewayCompilerConfig, PostCompilationConfig}; use crate::errors::{GatewayError, GatewayResult}; #[cfg(test)] @@ -18,10 +19,20 @@ mod compilation_test; // TODO(Arni): Pass the compiler with dependancy injection. #[derive(Clone)] pub struct GatewayCompiler { - pub sierra_to_casm_compiler: SierraToCasmCompiler, + config: PostCompilationConfig, + sierra_to_casm_compiler: SierraToCasmCompiler, } impl GatewayCompiler { + pub fn new(config: GatewayCompilerConfig) -> Self { + GatewayCompiler { + config: config.post_compilation_config, + sierra_to_casm_compiler: SierraToCasmCompiler { + config: config.sierra_to_casm_compiler_config, + }, + } + } + /// 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. @@ -36,6 +47,7 @@ impl GatewayCompiler { let casm_contract_class = self.compile(cairo_lang_contract_class)?; validate_compiled_class_hash(&casm_contract_class, &tx.compiled_class_hash)?; + self.validate_casm_class_size(&casm_contract_class)?; Ok(ClassInfo::new( &ContractClass::V1(ContractClassV1::try_from(casm_contract_class)?), @@ -55,6 +67,28 @@ impl GatewayCompiler { Ok(casm_contract_class) } + + // TODO(Arni): consider validating the size of other members of the Casm class. Cosider removing + // the validation of the raw class size. The validation should be linked to the way the class is + // saved in Papyrus etc. + /// Validates that the Casm class is within size limit. Specifically, this function validates + /// the size of the serialized class. + fn validate_casm_class_size( + &self, + casm_contract_class: &CasmContractClass, + ) -> Result<(), GatewayError> { + let contract_class_object_size = serde_json::to_string(&casm_contract_class) + .expect("Unexpected error serializing Casm contract class.") + .len(); + if contract_class_object_size > self.config.max_raw_casm_class_size { + return Err(GatewayError::CasmContractClassObjectSizeTooLarge { + contract_class_object_size, + max_contract_class_object_size: self.config.max_raw_casm_class_size, + }); + } + + Ok(()) + } } /// Validates that the compiled class hash of the compiled contract class matches the supplied diff --git a/crates/gateway/src/compilation_test.rs b/crates/gateway/src/compilation_test.rs index 2a591df3be3..014f77a7e97 100644 --- a/crates/gateway/src/compilation_test.rs +++ b/crates/gateway/src/compilation_test.rs @@ -11,16 +11,16 @@ use starknet_api::rpc_transaction::{ RpcDeclareTransactionV3, RpcTransaction, }; -use starknet_sierra_compile::compile::SierraToCasmCompiler; use starknet_sierra_compile::config::SierraToCasmCompilationConfig; use starknet_sierra_compile::errors::CompilationUtilError; use crate::compilation::GatewayCompiler; +use crate::config::{GatewayCompilerConfig, PostCompilationConfig}; use crate::errors::GatewayError; #[fixture] fn gateway_compiler() -> GatewayCompiler { - GatewayCompiler { sierra_to_casm_compiler: SierraToCasmCompiler { config: Default::default() } } + GatewayCompiler::new(GatewayCompilerConfig::default()) } #[fixture] @@ -53,11 +53,10 @@ fn test_compile_contract_class_compiled_class_hash_mismatch( // TODO(Arni): Redesign this test once the compiler is passed with dependancy injection. #[rstest] fn test_compile_contract_class_bytecode_size_validation(declare_tx_v3: RpcDeclareTransactionV3) { - let gateway_compiler = GatewayCompiler { - sierra_to_casm_compiler: SierraToCasmCompiler { - config: SierraToCasmCompilationConfig { max_bytecode_size: 1 }, - }, - }; + let gateway_compiler = GatewayCompiler::new(GatewayCompilerConfig { + sierra_to_casm_compiler_config: SierraToCasmCompilationConfig { max_bytecode_size: 1 }, + ..Default::default() + }); let result = gateway_compiler.process_declare_tx(&RpcDeclareTransaction::V3(declare_tx_v3)); assert_matches!( @@ -69,6 +68,18 @@ fn test_compile_contract_class_bytecode_size_validation(declare_tx_v3: RpcDeclar ) } +// TODO(Arni): Redesign this test once the compiler is passed with dependancy injection. +#[rstest] +fn test_compile_contract_class_raw_class_size_validation(declare_tx_v3: RpcDeclareTransactionV3) { + let gateway_compiler = GatewayCompiler::new(GatewayCompilerConfig { + post_compilation_config: PostCompilationConfig { max_raw_casm_class_size: 1 }, + ..Default::default() + }); + + let result = gateway_compiler.process_declare_tx(&RpcDeclareTransaction::V3(declare_tx_v3)); + assert_matches!(result.unwrap_err(), GatewayError::CasmContractClassObjectSizeTooLarge { .. }) +} + #[rstest] fn test_compile_contract_class_bad_sierra( gateway_compiler: GatewayCompiler, diff --git a/crates/gateway/src/config.rs b/crates/gateway/src/config.rs index fbfed4520e4..2364ff352ee 100644 --- a/crates/gateway/src/config.rs +++ b/crates/gateway/src/config.rs @@ -228,13 +228,43 @@ impl StatefulTransactionValidatorConfig { #[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, Validate, PartialEq)] pub struct GatewayCompilerConfig { pub sierra_to_casm_compiler_config: SierraToCasmCompilationConfig, + pub post_compilation_config: PostCompilationConfig, } impl SerializeConfig for GatewayCompilerConfig { fn dump(&self) -> BTreeMap { - append_sub_config_name( - self.sierra_to_casm_compiler_config.dump(), - "sierra_to_casm_compiler_config", - ) + vec![ + append_sub_config_name( + self.sierra_to_casm_compiler_config.dump(), + "sierra_to_casm_compiler_config", + ), + append_sub_config_name(self.post_compilation_config.dump(), "post_compilation_config"), + ] + .into_iter() + .flatten() + .collect() + } +} + +/// The configuration for the post compilation process in the gateway compiler. +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Validate, PartialEq)] +pub struct PostCompilationConfig { + pub max_raw_casm_class_size: usize, +} + +impl Default for PostCompilationConfig { + fn default() -> Self { + PostCompilationConfig { max_raw_casm_class_size: 4089446 } + } +} + +impl SerializeConfig for PostCompilationConfig { + fn dump(&self) -> BTreeMap { + BTreeMap::from_iter([ser_param( + "max_raw_casm_class_size", + &self.max_raw_casm_class_size, + "Limitation of contract class object size.", + ParamPrivacyInput::Public, + )]) } } diff --git a/crates/gateway/src/errors.rs b/crates/gateway/src/errors.rs index 108e31e8ef3..526405f1f7f 100644 --- a/crates/gateway/src/errors.rs +++ b/crates/gateway/src/errors.rs @@ -39,6 +39,14 @@ use crate::compiler_version::{VersionId, VersionIdError}; /// Errors directed towards the end-user, as a result of gateway requests. #[derive(Debug, Error)] pub enum GatewayError { + #[error( + "Cannot declare Casm contract class with size of {contract_class_object_size}; max \ + allowed size: {max_contract_class_object_size}." + )] + CasmContractClassObjectSizeTooLarge { + contract_class_object_size: usize, + max_contract_class_object_size: usize, + }, #[error(transparent)] CompilationError(#[from] CompilationUtilError), #[error( diff --git a/crates/gateway/src/gateway.rs b/crates/gateway/src/gateway.rs index 326b1141ac8..5694735b8c1 100644 --- a/crates/gateway/src/gateway.rs +++ b/crates/gateway/src/gateway.rs @@ -11,7 +11,6 @@ use starknet_api::transaction::TransactionHash; use starknet_mempool_infra::component_runner::{ComponentStartError, ComponentStarter}; use starknet_mempool_types::communication::SharedMempoolClient; use starknet_mempool_types::mempool_types::{Account, AccountState, MempoolInput}; -use starknet_sierra_compile::compile::SierraToCasmCompiler; use tracing::{info, instrument}; use crate::compilation::GatewayCompiler; @@ -155,11 +154,7 @@ pub fn create_gateway( mempool_client: SharedMempoolClient, ) -> Gateway { let state_reader_factory = Arc::new(RpcStateReaderFactory { config: rpc_state_reader_config }); - let gateway_compiler = GatewayCompiler { - sierra_to_casm_compiler: SierraToCasmCompiler { - config: config.compiler_config.sierra_to_casm_compiler_config, - }, - }; + let gateway_compiler = GatewayCompiler::new(config.compiler_config); Gateway::new(config, state_reader_factory, gateway_compiler, mempool_client) } diff --git a/crates/gateway/src/gateway_test.rs b/crates/gateway/src/gateway_test.rs index 1f7554b4ccb..dfec9e54c70 100644 --- a/crates/gateway/src/gateway_test.rs +++ b/crates/gateway/src/gateway_test.rs @@ -13,11 +13,13 @@ use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::transaction::TransactionHash; use starknet_mempool_types::communication::MockMempoolClient; use starknet_mempool_types::mempool_types::{Account, AccountState, MempoolInput, ThinTransaction}; -use starknet_sierra_compile::compile::SierraToCasmCompiler; -use starknet_sierra_compile::config::SierraToCasmCompilationConfig; use crate::compilation::GatewayCompiler; -use crate::config::{StatefulTransactionValidatorConfig, StatelessTransactionValidatorConfig}; +use crate::config::{ + GatewayCompilerConfig, + StatefulTransactionValidatorConfig, + StatelessTransactionValidatorConfig, +}; use crate::gateway::{add_tx, AppState, SharedMempoolClient}; use crate::state_reader_test_utils::{local_test_state_reader_factory, TestStateReaderFactory}; use crate::stateful_transaction_validator::StatefulTransactionValidator; @@ -35,11 +37,7 @@ pub fn app_state( stateful_tx_validator: Arc::new(StatefulTransactionValidator { config: StatefulTransactionValidatorConfig::create_for_testing(), }), - gateway_compiler: GatewayCompiler { - sierra_to_casm_compiler: SierraToCasmCompiler { - config: SierraToCasmCompilationConfig::default(), - }, - }, + gateway_compiler: GatewayCompiler::new(GatewayCompilerConfig::default()), state_reader_factory: Arc::new(state_reader_factory), mempool_client, } diff --git a/crates/gateway/src/stateful_transaction_validator_test.rs b/crates/gateway/src/stateful_transaction_validator_test.rs index 595b0ba2511..ee144398eaa 100644 --- a/crates/gateway/src/stateful_transaction_validator_test.rs +++ b/crates/gateway/src/stateful_transaction_validator_test.rs @@ -19,11 +19,10 @@ use starknet_api::core::{ContractAddress, Nonce}; use starknet_api::felt; use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::transaction::TransactionHash; -use starknet_sierra_compile::compile::SierraToCasmCompiler; use starknet_types_core::felt::Felt; use crate::compilation::GatewayCompiler; -use crate::config::StatefulTransactionValidatorConfig; +use crate::config::{GatewayCompilerConfig, StatefulTransactionValidatorConfig}; use crate::errors::{StatefulTransactionValidatorError, StatefulTransactionValidatorResult}; use crate::state_reader::{MockStateReaderFactory, StateReaderFactory}; use crate::state_reader_test_utils::local_test_state_reader_factory; @@ -84,11 +83,9 @@ fn test_stateful_tx_validator( ) { let optional_class_info = match &external_tx { RpcTransaction::Declare(declare_tx) => Some( - GatewayCompiler { - sierra_to_casm_compiler: SierraToCasmCompiler { config: Default::default() }, - } - .process_declare_tx(declare_tx) - .unwrap(), + GatewayCompiler::new(GatewayCompilerConfig::default()) + .process_declare_tx(declare_tx) + .unwrap(), ), _ => None, };