Skip to content

Commit

Permalink
feat: create skelaton of transaction validator
Browse files Browse the repository at this point in the history
  • Loading branch information
ArniStarkware committed Mar 19, 2024
1 parent e33dbc7 commit c05d806
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 0 deletions.
9 changes: 9 additions & 0 deletions crates/gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,12 @@
name = "gateway"
version = "0.1.0"
edition = "2021"

[dependencies]
thiserror = "1.0"
starknet_api = "0.8.0"
assert_matches = "1.5.0"
rstest = "0.17.0"

[lib]
name = "gateway_lib"
1 change: 1 addition & 0 deletions crates/gateway/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod transaction_validator;
94 changes: 94 additions & 0 deletions crates/gateway/src/transaction_validator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use starknet_api::transaction::Transaction;
use starknet_api::transaction::TransactionVersion;

use thiserror::Error;

#[cfg(test)]
#[path = "transaction_validator_test.rs"]
mod transaction_validator_test;

#[derive(Debug, Error)]
#[cfg_attr(test, derive(PartialEq))]
pub enum TransactionValidatorError {
#[error("Invalid transaction type")]
InvalidTransactionType,
#[error("Transactions of version {0:?} are not valid. {1}")]
InvalidTransactionVersion(TransactionVersion, String),
#[error("Blocked transaction version {0:?}. {1}")]
BlockedTransactionVersion(TransactionVersion, String),
}

pub type TransactionValidatorResult<T> = Result<T, TransactionValidatorError>;

#[derive(Default)]
pub struct TransactionValidatorConfig {
pub block_declare_cairo1: bool,
pub block_declare_cairo0: bool,

pub min_allowed_tx_version: TransactionVersion,
pub max_allowed_tx_version: TransactionVersion,
}

pub struct TransactionValidator {
pub config: TransactionValidatorConfig,
}

impl TransactionValidator {
pub fn validate(&self, tx: Transaction) -> TransactionValidatorResult<()> {
// Deploy transactions are deprecated.
// L1Handler transactions are not supported in the gateway.
if matches!(tx, Transaction::Deploy(_) | Transaction::L1Handler(_)) {
return Err(TransactionValidatorError::InvalidTransactionType);
}

// Check if the declaration of Cairo / Cairo-0 contracts are blocked.
if let Transaction::Declare(tx) = &tx {
if tx.version() < TransactionVersion::TWO && self.config.block_declare_cairo0 {
return Err(TransactionValidatorError::BlockedTransactionVersion(
tx.version(),
"Declare of Cairo 0 is blocked.".into(),
));
}
if tx.version() >= TransactionVersion::TWO && self.config.block_declare_cairo1 {
return Err(TransactionValidatorError::BlockedTransactionVersion(
tx.version(),
"Transaction type is temporarily blocked.".into(),
));
}
}

// TODO(Arni, 1/4/2024): Add a mechanism that validate the sender address is not blocked.
let version = get_tx_version(&tx);
if version < self.config.min_allowed_tx_version {
return Err(TransactionValidatorError::InvalidTransactionVersion(
version,
format!(
"Minimal supported version is {:?}.",
self.config.min_allowed_tx_version
),
));
}
if version > self.config.max_allowed_tx_version {
return Err(TransactionValidatorError::InvalidTransactionVersion(
version,
format!(
"Maximal supported version is {:?}.",
self.config.max_allowed_tx_version
),
));
}

// TODO(Arni, 1/4/2024): Validate fee and tx size.
Ok(())
}
}

fn get_tx_version(tx: &Transaction) -> TransactionVersion {
match tx {
Transaction::Declare(tx) => tx.version(),
Transaction::DeployAccount(tx) => tx.version(),
Transaction::Invoke(tx) => tx.version(),
Transaction::Deploy(_) => TransactionVersion::ZERO,
Transaction::L1Handler(_) => TransactionVersion::ZERO,
}
}
99 changes: 99 additions & 0 deletions crates/gateway/src/transaction_validator_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use rstest::rstest;

use starknet_api::transaction::InvokeTransaction;
use starknet_api::transaction::InvokeTransactionV1;
use starknet_api::transaction::Transaction;
use starknet_api::transaction::TransactionVersion;

use crate::transaction_validator::{
TransactionValidator, TransactionValidatorConfig, TransactionValidatorError,
};

#[rstest]
#[case::block_declare_on_cairo_version_0(
TransactionValidatorConfig {
block_declare_cairo0: true,
..Default::default()
},
Transaction::Declare(starknet_api::transaction::DeclareTransaction::V0(
starknet_api::transaction::DeclareTransactionV0V1 {..Default::default()}
)),
Some(TransactionValidatorError::BlockedTransactionVersion(
TransactionVersion::ZERO,
"Declare of Cairo 0 is blocked.".to_string()
))
)]
#[case::block_declare_on_cairo_version_1(
TransactionValidatorConfig {
block_declare_cairo1: true,
..Default::default()
},
Transaction::Declare(starknet_api::transaction::DeclareTransaction::V2(
starknet_api::transaction::DeclareTransactionV2 {..Default::default()}
)),
Some(TransactionValidatorError::BlockedTransactionVersion(
TransactionVersion::TWO,
"Transaction type is temporarily blocked.".to_string()
))
)]
#[case::tx_version_below_minimal(
TransactionValidatorConfig {
min_allowed_tx_version: TransactionVersion::THREE,
max_allowed_tx_version: TransactionVersion::THREE,
..Default::default()
},
Transaction::Invoke(InvokeTransaction::V1(InvokeTransactionV1 {..Default::default()})),
Some(TransactionValidatorError::InvalidTransactionVersion(
TransactionVersion::ONE,
format!{"Minimal supported version is {:?}.", TransactionVersion::THREE}
))
)]
#[case::tx_version_above_maximal(
TransactionValidatorConfig {
min_allowed_tx_version: TransactionVersion::ZERO,
max_allowed_tx_version: TransactionVersion::ZERO,
..Default::default()
},
Transaction::Invoke(InvokeTransaction::V1(InvokeTransactionV1 {..Default::default()})),
Some(TransactionValidatorError::InvalidTransactionVersion(
TransactionVersion::ONE,
format!{"Maximal supported version is {:?}.", TransactionVersion::ZERO}
))
)]
#[case::deprecated_deploy_tx(
TransactionValidatorConfig {
..Default::default()
},
Transaction::Deploy(starknet_api::transaction::DeployTransaction {..Default::default()}),
Some(TransactionValidatorError::InvalidTransactionType)
)]
#[case::unsupported_l1_handler_tx(
TransactionValidatorConfig {
..Default::default()
},
Transaction::L1Handler(starknet_api::transaction::L1HandlerTransaction {..Default::default()}),
Some(TransactionValidatorError::InvalidTransactionType)
)]
#[case::valid_tx(
TransactionValidatorConfig {
min_allowed_tx_version: TransactionVersion::ZERO,
max_allowed_tx_version: TransactionVersion::THREE,
..Default::default()
},
Transaction::Invoke(InvokeTransaction::V1(InvokeTransactionV1 {..Default::default()})),
None
)]
fn test_transaction_version(
#[case] config: TransactionValidatorConfig,
#[case] tx: Transaction,
#[case] expected_error: Option<TransactionValidatorError>,
) {
let tx_validator = TransactionValidator { config };
let result = tx_validator.validate(tx);

if let Some(expected_error) = expected_error {
assert_eq!(result.unwrap_err(), expected_error);
} else {
assert!(result.is_ok());
}
}

0 comments on commit c05d806

Please sign in to comment.