Skip to content

Commit

Permalink
feat: add declare specific size related stateless tx validator
Browse files Browse the repository at this point in the history
  • Loading branch information
ArniStarkware committed Jun 6, 2024
1 parent 41a4675 commit 642c7a9
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 9 deletions.
3 changes: 3 additions & 0 deletions crates/gateway/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ pub struct StatelessTransactionValidatorConfig {

pub max_calldata_length: usize,
pub max_signature_length: usize,

pub max_bytecode_size: usize,
pub max_raw_class_size: usize,
}

impl SerializeConfig for StatelessTransactionValidatorConfig {
Expand Down
25 changes: 25 additions & 0 deletions crates/gateway/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,31 @@ pub enum StatelessTransactionValidatorError {
(allowed length: {max_signature_length})."
)]
SignatureTooLong { signature_length: usize, max_signature_length: usize },
#[error(transparent)]
DeclareTransactionError(#[from] DeclareTransactionError),
}

#[derive(Debug, Error)]
#[cfg_attr(test, derive(PartialEq))]
pub enum DeclareTransactionError {
#[error(
"Declared contract class {bytecode_language} bytecode size is {bytecode_size}. It must be \
less then {max_bytecode_size}."
)]
BytecodeSizeTooLarge {
bytecode_language: String,
bytecode_size: usize,
max_bytecode_size: usize,
},
#[error(
"Declared contract class {bytecode_language} size is {contract_class_object_size}. It \
must be less then {max_contract_class_object_size}."
)]
ContractClassObjectSizeTooLarge {
bytecode_language: String,
contract_class_object_size: usize,
max_contract_class_object_size: usize,
},
}

pub type StatelessTransactionValidatorResult<T> = Result<T, StatelessTransactionValidatorError>;
Expand Down
65 changes: 62 additions & 3 deletions crates/gateway/src/stateless_transaction_validator.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use starknet_api::external_transaction::{
ExternalDeployAccountTransaction, ExternalInvokeTransaction, ExternalTransaction,
ResourceBoundsMapping,
ExternalDeclareTransaction, ExternalDeclareTransactionV3, ExternalDeployAccountTransaction,
ExternalInvokeTransaction, ExternalTransaction, ResourceBoundsMapping,
};
use starknet_api::transaction::Resource;

use crate::config::StatelessTransactionValidatorConfig;
use crate::errors::{StatelessTransactionValidatorError, StatelessTransactionValidatorResult};
use crate::errors::{
DeclareTransactionError, StatelessTransactionValidatorError,
StatelessTransactionValidatorResult,
};

#[cfg(test)]
#[path = "stateless_transaction_validator_test.rs"]
Expand All @@ -24,6 +27,9 @@ impl StatelessTransactionValidator {
self.validate_resource_bounds(tx)?;
self.validate_tx_size(tx)?;

if let ExternalTransaction::Declare(ExternalDeclareTransaction::V3(declare_tx)) = tx {
self.validate_declare_tx(declare_tx)?;
}
Ok(())
}

Expand Down Expand Up @@ -95,10 +101,63 @@ impl StatelessTransactionValidator {

Ok(())
}

fn validate_declare_tx(
&self,
tx: &ExternalDeclareTransactionV3,
) -> StatelessTransactionValidatorResult<()> {
self.validate_class_length(&tx.contract_class)?;

Ok(())
}

fn validate_class_length(
&self,
contract_class: &starknet_api::external_transaction::ContractClass,
) -> StatelessTransactionValidatorResult<()> {
let bytecode_size = contract_class.sierra_program.len();
let serialized_class = serde_json::to_string(&contract_class)
.expect("Unexpected error serializing contract class.");
let raw_class_size = serialized_class.len();

Ok(validate_class_size(
"Sierra".to_string(),
bytecode_size,
self.config.max_bytecode_size,
raw_class_size,
self.config.max_raw_class_size,
)?)
}
}

// Utilities.

fn validate_class_size(
bytecode_language: String,
bytecode_size: usize,
max_bytecode_size: usize,
raw_class_size: usize,
max_raw_class_size: usize,
) -> Result<(), DeclareTransactionError> {
if bytecode_size > max_bytecode_size {
return Err(DeclareTransactionError::BytecodeSizeTooLarge {
bytecode_language,
bytecode_size,
max_bytecode_size,
});
}

if raw_class_size > max_raw_class_size {
return Err(DeclareTransactionError::ContractClassObjectSizeTooLarge {
bytecode_language,
contract_class_object_size: raw_class_size,
max_contract_class_object_size: max_raw_class_size,
});
}

Ok(())
}

fn validate_resource_is_non_zero(
resource_bounds_mapping: &ResourceBoundsMapping,
resource: Resource,
Expand Down
80 changes: 74 additions & 6 deletions crates/gateway/src/stateless_transaction_validator_test.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
use assert_matches::assert_matches;
use rstest::rstest;
use starknet_api::calldata;
use starknet_api::external_transaction::ResourceBoundsMapping;
use starknet_api::external_transaction::{ContractClass, ResourceBoundsMapping};
use starknet_api::hash::StarkFelt;
use starknet_api::transaction::{Calldata, Resource, ResourceBounds, TransactionSignature};
use starknet_api::{calldata, stark_felt};

use crate::config::StatelessTransactionValidatorConfig;
use crate::declare_tx_args;
use crate::errors::DeclareTransactionError;
use crate::starknet_api_test_utils::{
create_resource_bounds_mapping, external_tx_for_testing, non_zero_resource_bounds_mapping,
zero_resource_bounds_mapping, TransactionType, NON_EMPTY_RESOURCE_BOUNDS,
create_resource_bounds_mapping, external_declare_tx, external_tx_for_testing,
non_zero_resource_bounds_mapping, zero_resource_bounds_mapping, TransactionType,
NON_EMPTY_RESOURCE_BOUNDS,
};
use crate::stateless_transaction_validator::{
StatelessTransactionValidator, StatelessTransactionValidatorConfig,
StatelessTransactionValidatorError,
StatelessTransactionValidator, StatelessTransactionValidatorError,
};

const DEFAULT_VALIDATOR_CONFIG_FOR_TESTING: StatelessTransactionValidatorConfig =
Expand All @@ -21,6 +24,8 @@ const DEFAULT_VALIDATOR_CONFIG_FOR_TESTING: StatelessTransactionValidatorConfig

max_calldata_length: 1,
max_signature_length: 1,
max_bytecode_size: 3,
max_raw_class_size: 408,
};

#[rstest]
Expand Down Expand Up @@ -153,3 +158,66 @@ fn test_signature_too_long(
}
);
}

#[test]
fn test_declare_bytecode_size_too_long() {
let config_max_bytecode_size = 10;
let tx_validator = StatelessTransactionValidator {
config: StatelessTransactionValidatorConfig {
validate_non_zero_l1_gas_fee: false,
validate_non_zero_l2_gas_fee: false,
max_bytecode_size: config_max_bytecode_size,
..DEFAULT_VALIDATOR_CONFIG_FOR_TESTING
},
};
let mut sierra_program = vec![stark_felt!(1_u128), stark_felt!(3_u128), stark_felt!(0_u128)];
sierra_program.extend(vec![stark_felt!(12_u128); config_max_bytecode_size]);
let sierra_program_length = sierra_program.len();
let contract_class = ContractClass { sierra_program, ..Default::default() };
let tx = external_declare_tx(declare_tx_args!(contract_class));

assert_matches!(
tx_validator.validate(&tx).unwrap_err(),
StatelessTransactionValidatorError::DeclareTransactionError(
DeclareTransactionError::BytecodeSizeTooLarge {
bytecode_language,
bytecode_size,
max_bytecode_size
}
) => {
assert_eq!(bytecode_language, "Sierra");
assert_eq!(bytecode_size, sierra_program_length);
assert_eq!(max_bytecode_size, config_max_bytecode_size);
}
)
}

#[test]
fn test_declare_contract_class_size_too_long() {
let config_max_raw_class_size = 100;
let tx_validator = StatelessTransactionValidator {
config: StatelessTransactionValidatorConfig {
validate_non_zero_l1_gas_fee: false,
validate_non_zero_l2_gas_fee: false,
max_raw_class_size: config_max_raw_class_size,
..DEFAULT_VALIDATOR_CONFIG_FOR_TESTING
},
};
let contract_class = ContractClass {
sierra_program: vec![stark_felt!(1_u128), stark_felt!(3_u128), stark_felt!(0_u128)],
..Default::default()
};
let contract_class_len = serde_json::to_string(&contract_class).unwrap().len();
let tx = external_declare_tx(declare_tx_args!(contract_class));

assert_matches!(
tx_validator.validate(&tx).unwrap_err(),
StatelessTransactionValidatorError::DeclareTransactionError(
DeclareTransactionError::ContractClassObjectSizeTooLarge { bytecode_language, contract_class_object_size, max_contract_class_object_size }
) => {
assert_eq!(bytecode_language, "Sierra");
assert_eq!(contract_class_object_size, contract_class_len);
assert_eq!(max_contract_class_object_size, config_max_raw_class_size);
}
)
}

0 comments on commit 642c7a9

Please sign in to comment.