Skip to content

Commit

Permalink
feat(gateway): validate that entry points are sorted by selector (#373)
Browse files Browse the repository at this point in the history
  • Loading branch information
yair-starkware authored Jul 14, 2024
1 parent 47925f1 commit 3516119
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 2 deletions.
2 changes: 2 additions & 0 deletions crates/gateway/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ pub enum StatelessTransactionValidatorError {
contract_class_object_size: usize,
max_contract_class_object_size: usize,
},
#[error("Entry points must be unique and sorted.")]
EntryPointsNotUniquelySorted,
}

pub type StatelessTransactionValidatorResult<T> = Result<T, StatelessTransactionValidatorError>;
Expand Down
23 changes: 22 additions & 1 deletion crates/gateway/src/stateless_transaction_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use starknet_api::rpc_transaction::{
RPCDeclareTransaction, RPCDeployAccountTransaction, RPCInvokeTransaction, RPCTransaction,
ResourceBoundsMapping,
};
use starknet_api::state::EntryPoint;
use starknet_api::transaction::Resource;
use starknet_types_core::felt::Felt;

Expand Down Expand Up @@ -106,7 +107,9 @@ impl StatelessTransactionValidator {
RPCDeclareTransaction::V3(tx) => &tx.contract_class,
};
self.validate_sierra_version(&contract_class.sierra_program)?;
self.validate_class_length(contract_class)
self.validate_class_length(contract_class)?;
self.validate_entry_points_sorted_and_unique(contract_class)?;
Ok(())
}

fn validate_sierra_version(
Expand Down Expand Up @@ -154,6 +157,24 @@ impl StatelessTransactionValidator {

Ok(())
}

fn validate_entry_points_sorted_and_unique(
&self,
contract_class: &starknet_api::rpc_transaction::ContractClass,
) -> StatelessTransactionValidatorResult<()> {
let is_sorted_unique = |entry_points: &[EntryPoint]| {
entry_points.windows(2).all(|pair| pair[0].selector < pair[1].selector)
};

if is_sorted_unique(&contract_class.entry_points_by_type.constructor)
&& is_sorted_unique(&contract_class.entry_points_by_type.external)
&& is_sorted_unique(&contract_class.entry_points_by_type.l1handler)
{
return Ok(());
}

Err(StatelessTransactionValidatorError::EntryPointsNotUniquelySorted)
}
}

fn validate_resource_is_non_zero(
Expand Down
94 changes: 93 additions & 1 deletion crates/gateway/src/stateless_transaction_validator_test.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
use std::vec;

use assert_matches::assert_matches;
use mempool_test_utils::declare_tx_args;
use mempool_test_utils::starknet_api_test_utils::{
create_resource_bounds_mapping, external_declare_tx, external_tx_for_testing,
zero_resource_bounds_mapping, TransactionType, NON_EMPTY_RESOURCE_BOUNDS,
};
use rstest::rstest;
use starknet_api::rpc_transaction::{ContractClass, ResourceBoundsMapping};
use starknet_api::core::EntryPointSelector;
use starknet_api::rpc_transaction::{ContractClass, EntryPointByType, ResourceBoundsMapping};
use starknet_api::state::EntryPoint;
use starknet_api::transaction::{Calldata, Resource, ResourceBounds, TransactionSignature};
use starknet_api::{calldata, felt};
use starknet_types_core::felt::Felt;

use crate::compiler_version::{VersionId, VersionIdError};
use crate::config::StatelessTransactionValidatorConfig;
use crate::errors::StatelessTransactionValidatorResult;
use crate::stateless_transaction_validator::{
StatelessTransactionValidator, StatelessTransactionValidatorError,
};
Expand Down Expand Up @@ -326,3 +331,90 @@ fn test_declare_contract_class_size_too_long() {
) == (contract_class_length, config_max_raw_class_size)
)
}

#[rstest]
#[case::valid(
vec![
EntryPoint { selector: EntryPointSelector(felt!(1_u128)), ..Default::default() },
EntryPoint { selector: EntryPointSelector(felt!(2_u128)), ..Default::default() }
],
Ok(())
)]
#[case::no_entry_points(
vec![],
Ok(())
)]
#[case::single_entry_point(
vec![
EntryPoint { selector: EntryPointSelector(felt!(1_u128)), ..Default::default() }
],
Ok(())
)]
#[case::not_sorted(
vec![
EntryPoint { selector: EntryPointSelector(felt!(2_u128)), ..Default::default() },
EntryPoint { selector: EntryPointSelector(felt!(1_u128)), ..Default::default() },
],
Err(StatelessTransactionValidatorError::EntryPointsNotUniquelySorted)
)]
#[case::not_unique(
vec![
EntryPoint { selector: EntryPointSelector(felt!(1_u128)), ..Default::default() },
EntryPoint { selector: EntryPointSelector(felt!(1_u128)), ..Default::default() },
],
Err(StatelessTransactionValidatorError::EntryPointsNotUniquelySorted)
)]
#[case::many_entry_points(
vec![
EntryPoint { selector: EntryPointSelector(felt!(1_u128)), ..Default::default() },
EntryPoint { selector: EntryPointSelector(felt!(2_u128)), ..Default::default() },
EntryPoint { selector: EntryPointSelector(felt!(1_u128)), ..Default::default() },
],
Err(StatelessTransactionValidatorError::EntryPointsNotUniquelySorted)
)]
fn test_declare_entry_points_not_sorted_by_selector(
#[case] entry_points: Vec<EntryPoint>,
#[case] expected: StatelessTransactionValidatorResult<()>,
) {
let tx_validator =
StatelessTransactionValidator { config: DEFAULT_VALIDATOR_CONFIG_FOR_TESTING };

let contract_class = ContractClass {
sierra_program: vec![felt!(1_u128); 3],
entry_points_by_type: EntryPointByType {
constructor: entry_points.clone(),
external: vec![],
l1handler: vec![],
},
..Default::default()
};
let tx = external_declare_tx(declare_tx_args!(contract_class));

assert_eq!(tx_validator.validate(&tx), expected);

let contract_class = ContractClass {
sierra_program: vec![felt!(1_u128); 3],
entry_points_by_type: EntryPointByType {
constructor: vec![],
external: entry_points.clone(),
l1handler: vec![],
},
..Default::default()
};
let tx = external_declare_tx(declare_tx_args!(contract_class));

assert_eq!(tx_validator.validate(&tx), expected);

let contract_class = ContractClass {
sierra_program: vec![felt!(1_u128); 3],
entry_points_by_type: EntryPointByType {
constructor: vec![],
external: vec![],
l1handler: entry_points,
},
..Default::default()
};
let tx = external_declare_tx(declare_tx_args!(contract_class));

assert_eq!(tx_validator.validate(&tx), expected);
}

0 comments on commit 3516119

Please sign in to comment.