-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: create skelaton of transaction validator
- Loading branch information
1 parent
e33dbc7
commit c05d806
Showing
4 changed files
with
203 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod transaction_validator; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()); | ||
} | ||
} |