Skip to content

Commit

Permalink
chore: expose max bytecode size arg for the compile sierra to casm util
Browse files Browse the repository at this point in the history
  • Loading branch information
ArniStarkware committed Aug 4, 2024
1 parent 56c45e8 commit b76640a
Show file tree
Hide file tree
Showing 16 changed files with 199 additions and 49 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.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ cairo-felt = "0.9.1"
cairo-lang-casm = "2.7.0-rc.3"
cairo-lang-runner = "2.7.0-rc.3"
cairo-lang-sierra = "=2.7.0-rc.3"
cairo-lang-sierra-to-casm = "2.7.0-rc.3"
cairo-lang-starknet-classes = "2.7.0-rc.3"
cairo-lang-utils = "2.7.0-rc.3"
cairo-vm = "=1.0.0-rc5"
Expand Down
10 changes: 10 additions & 0 deletions config/mempool/default_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@
"privacy": "Public",
"value": true
},
"gateway_config.compiler_config.sierra_to_casm_compiler_config.max_bytecode_size": {
"description": "Limitation of contract bytecode size.",
"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",
Expand Down
1 change: 1 addition & 0 deletions crates/gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ validator.workspace = true

[dev-dependencies]
assert_matches.workspace = true
cairo-lang-sierra-to-casm.workspace = true
mockall.workspace = true
mockito = "1.4.0"
num-bigint.workspace = true
Expand Down
43 changes: 38 additions & 5 deletions crates/gateway/src/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use cairo_lang_starknet_classes::contract_class::ContractClass as CairoLangContractClass;
use starknet_api::core::CompiledClassHash;
use starknet_api::rpc_transaction::RpcDeclareTransaction;
use starknet_sierra_compile::compile::compile_sierra_to_casm;
use starknet_sierra_compile::compile::SierraToCasmCompiler;
use starknet_sierra_compile::errors::CompilationUtilError;
use starknet_sierra_compile::utils::into_contract_class_for_compilation;

Expand All @@ -19,11 +19,20 @@ mod compilation_test;
// TODO(Arni): Pass the compiler with dependancy injection.
#[derive(Clone)]
pub struct GatewayCompiler {
#[allow(dead_code)]
pub config: GatewayCompilerConfig,
config: GatewayCompilerConfig,
sierra_to_casm_compiler: SierraToCasmCompiler,
}

impl GatewayCompiler {
pub fn new(config: GatewayCompilerConfig) -> Self {
GatewayCompiler {
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.
Expand All @@ -38,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)?),
Expand All @@ -51,13 +61,36 @@ impl GatewayCompiler {
&self,
cairo_lang_contract_class: CairoLangContractClass,
) -> Result<CasmContractClass, GatewayError> {
let catch_unwind_result =
panic::catch_unwind(|| compile_sierra_to_casm(cairo_lang_contract_class));
let catch_unwind_result = panic::catch_unwind(|| {
self.sierra_to_casm_compiler.compile_sierra_to_casm(cairo_lang_contract_class)
});
let casm_contract_class =
catch_unwind_result.map_err(|_| CompilationUtilError::CompilationPanic)??;

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
Expand Down
40 changes: 39 additions & 1 deletion crates/gateway/src/compilation_test.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
use assert_matches::assert_matches;
use blockifier::execution::contract_class::ContractClass;
use cairo_lang_sierra_to_casm::compiler::CompilationError;
use cairo_lang_starknet_classes::allowed_libfuncs::AllowedLibfuncsError;
use cairo_lang_starknet_classes::casm_contract_class::StarknetSierraCompilationError;
use mempool_test_utils::starknet_api_test_utils::declare_tx as rpc_declare_tx;
use rstest::{fixture, rstest};
use starknet_api::core::CompiledClassHash;
use starknet_api::rpc_transaction::{RpcDeclareTransaction, 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;
use crate::errors::GatewayError;

#[fixture]
fn gateway_compiler() -> GatewayCompiler {
GatewayCompiler { config: Default::default() }
GatewayCompiler {
config: Default::default(),
sierra_to_casm_compiler: SierraToCasmCompiler { config: Default::default() },
}
}

#[fixture]
Expand Down Expand Up @@ -43,6 +51,36 @@ 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: RpcDeclareTransaction) {
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(&declare_tx);
assert_matches!(
result.unwrap_err(),
GatewayError::CompilationError(CompilationUtilError::StarknetSierraCompilationError(
StarknetSierraCompilationError::CompilationError(err)
))
if matches!(err.as_ref(), CompilationError::CodeSizeLimitExceeded)
)
}

// 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: RpcDeclareTransaction) {
let gateway_compiler = GatewayCompiler::new(GatewayCompilerConfig {
max_raw_casm_class_size: 1,
..Default::default()
});

let result = gateway_compiler.process_declare_tx(&declare_tx);
assert_matches!(result.unwrap_err(), GatewayError::CasmContractClassObjectSizeTooLarge { .. })
}

#[rstest]
fn test_compile_contract_class_bad_sierra(
gateway_compiler: GatewayCompiler,
Expand Down
36 changes: 31 additions & 5 deletions crates/gateway/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ use papyrus_config::dumping::{append_sub_config_name, ser_param, SerializeConfig
use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam};
use serde::{Deserialize, Serialize};
use starknet_api::core::Nonce;
use starknet_sierra_compile::config::SierraToCasmCompilationConfig;
use starknet_types_core::felt::Felt;
use validator::Validate;

use crate::compiler_version::VersionId;

const MAX_BYTECODE_SIZE: usize = 81920;
const MAX_RAW_CLASS_SIZE: usize = 4089446;

#[derive(Clone, Debug, Default, Serialize, Deserialize, Validate, PartialEq)]
pub struct GatewayConfig {
pub network_config: GatewayNetworkConfig,
Expand Down Expand Up @@ -88,8 +92,8 @@ impl Default for StatelessTransactionValidatorConfig {
validate_non_zero_l2_gas_fee: false,
max_calldata_length: 4000,
max_signature_length: 4000,
max_bytecode_size: 81920,
max_raw_class_size: 4089446,
max_bytecode_size: MAX_BYTECODE_SIZE,
max_raw_class_size: MAX_RAW_CLASS_SIZE,
min_sierra_version: VersionId { major: 1, minor: 1, patch: 0 },
max_sierra_version: VersionId { major: 1, minor: 5, patch: usize::MAX },
}
Expand Down Expand Up @@ -232,11 +236,33 @@ impl StatefulTransactionValidatorConfig {
}
}

#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, Validate, PartialEq)]
pub struct GatewayCompilerConfig {}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Validate, PartialEq)]
pub struct GatewayCompilerConfig {
pub sierra_to_casm_compiler_config: SierraToCasmCompilationConfig,
pub max_raw_casm_class_size: usize,
}

impl Default for GatewayCompilerConfig {
fn default() -> Self {
GatewayCompilerConfig {
max_raw_casm_class_size: MAX_RAW_CLASS_SIZE,
sierra_to_casm_compiler_config: SierraToCasmCompilationConfig::default(),
}
}
}

impl SerializeConfig for GatewayCompilerConfig {
fn dump(&self) -> BTreeMap<ParamPath, SerializedParam> {
BTreeMap::new()
let members = BTreeMap::from_iter([ser_param(
"max_raw_casm_class_size",
&self.max_raw_casm_class_size,
"Limitation of contract class object size.",
ParamPrivacyInput::Public,
)]);
let sub_configs = append_sub_config_name(
self.sierra_to_casm_compiler_config.dump(),
"sierra_to_casm_compiler_config",
);
vec![members, sub_configs].into_iter().flatten().collect()
}
}
8 changes: 8 additions & 0 deletions crates/gateway/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion crates/gateway/src/gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,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 { config: config.compiler_config };
let gateway_compiler = GatewayCompiler::new(config.compiler_config);
Gateway::new(config, state_reader_factory, gateway_compiler, mempool_client)
}

Expand Down
11 changes: 2 additions & 9 deletions crates/gateway/src/gateway_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,12 @@ pub fn app_state(
) -> AppState {
AppState {
stateless_tx_validator: StatelessTransactionValidator {
config: StatelessTransactionValidatorConfig {
validate_non_zero_l1_gas_fee: true,
max_calldata_length: 10,
max_signature_length: 2,
max_bytecode_size: 10000,
max_raw_class_size: 1000000,
..Default::default()
},
config: StatelessTransactionValidatorConfig::default(),
},
stateful_tx_validator: Arc::new(StatefulTransactionValidator {
config: StatefulTransactionValidatorConfig::create_for_testing(),
}),
gateway_compiler: GatewayCompiler { config: GatewayCompilerConfig {} },
gateway_compiler: GatewayCompiler::new(GatewayCompilerConfig::default()),
state_reader_factory: Arc::new(state_reader_factory),
mempool_client,
}
Expand Down
2 changes: 1 addition & 1 deletion crates/gateway/src/stateful_transaction_validator_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ fn test_stateful_tx_validator(
) {
let optional_class_info = match &external_tx {
RpcTransaction::Declare(declare_tx) => Some(
GatewayCompiler { config: GatewayCompilerConfig {} }
GatewayCompiler::new(GatewayCompilerConfig::default())
.process_declare_tx(declare_tx)
.unwrap(),
),
Expand Down
3 changes: 3 additions & 0 deletions crates/starknet_sierra_compile/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ workspace = true
cairo-lang-sierra.workspace = true
cairo-lang-starknet-classes.workspace = true
cairo-lang-utils.workspace = true
papyrus_config = { path = "../papyrus_config", version = "0.4.0-rc.0" }
serde.workspace = true
serde_json.workspace = true
starknet-types-core.workspace = true
starknet_api = { path = "../starknet_api", version = "0.13.0-rc.0" }
thiserror.workspace = true
validator.workspace = true

[dev-dependencies]
assert_matches.workspace = true
mempool_test_utils = { path = "../mempool_test_utils" }
rstest.workspace = true
37 changes: 17 additions & 20 deletions crates/starknet_sierra_compile/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,29 @@ use cairo_lang_starknet_classes::allowed_libfuncs::ListSelector;
use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use cairo_lang_starknet_classes::contract_class::ContractClass;

use crate::config::SierraToCasmCompilationConfig;
use crate::errors::CompilationUtilError;

#[cfg(test)]
#[path = "compile_test.rs"]
pub mod compile_test;
pub struct SierraToCasmCompilationArgs {
list_selector: ListSelector,
add_pythonic_hints: bool,
max_bytecode_size: usize,
}

/// This function may panic.
pub fn compile_sierra_to_casm(
contract_class: ContractClass,
) -> Result<CasmContractClass, CompilationUtilError> {
let compilation_args = SierraToCasmCompilationArgs {
list_selector: ListSelector::DefaultList,
add_pythonic_hints: true,
max_bytecode_size: 1000000,
};
#[derive(Clone)]
pub struct SierraToCasmCompiler {
pub config: SierraToCasmCompilationConfig,
}

contract_class.validate_version_compatible(compilation_args.list_selector)?;
impl SierraToCasmCompiler {
pub fn compile_sierra_to_casm(
&self,
contract_class: ContractClass,
) -> Result<CasmContractClass, CompilationUtilError> {
contract_class.validate_version_compatible(ListSelector::DefaultList)?;

Ok(CasmContractClass::from_contract_class(
contract_class,
compilation_args.add_pythonic_hints,
compilation_args.max_bytecode_size,
)?)
Ok(CasmContractClass::from_contract_class(
contract_class,
true,
self.config.max_bytecode_size,
)?)
}
}
Loading

0 comments on commit b76640a

Please sign in to comment.