-
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
39ac4d7
commit 4db9be8
Showing
5 changed files
with
210 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 |
---|---|---|
@@ -1,9 +1,24 @@ | ||
use starknet_api::transaction::TransactionVersion; | ||
use thiserror::Error; | ||
|
||
#[derive(Debug, Error)] | ||
#[cfg_attr(test, derive(PartialEq))] | ||
pub enum GatewayError { | ||
#[error("Internal server error")] | ||
InternalServerError, | ||
#[error("Error while starting the server")] | ||
ServerError, | ||
#[error("Invalid transaction: {0}")] | ||
TransactionValidatorError(#[from] TransactionValidatorError), | ||
} | ||
|
||
#[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), | ||
} |
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 |
---|---|---|
@@ -1,2 +1,3 @@ | ||
pub mod errors; | ||
pub mod gateway; | ||
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,91 @@ | ||
use crate::errors::TransactionValidatorError; | ||
use starknet_api::transaction::Transaction; | ||
use starknet_api::transaction::TransactionVersion; | ||
|
||
#[cfg(test)] | ||
#[path = "transaction_validator_test.rs"] | ||
mod transaction_validator_test; | ||
|
||
#[derive(Default)] | ||
pub struct TransactionValidatorConfig { | ||
pub block_declare_cairo1: bool, | ||
pub block_declare_cairo0: bool, | ||
|
||
pub min_allowed_tx_version: usize, | ||
pub max_allowed_tx_version: usize, | ||
pub current_tx_version: usize, // Should this constant be a part of the config? | ||
} | ||
|
||
pub struct TransactionValidator { | ||
pub config: TransactionValidatorConfig, | ||
} | ||
|
||
impl TransactionValidator { | ||
pub fn validate(&self, tx: Transaction) -> Result<(), TransactionValidatorError> { | ||
// 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); | ||
let version_as_usize: usize = version.0.try_into().expect("Invalid version."); | ||
if version_as_usize < self.config.min_allowed_tx_version { | ||
return Err(TransactionValidatorError::InvalidTransactionVersion( | ||
version, | ||
format!( | ||
"Minimal supported version is {}.", | ||
self.config.min_allowed_tx_version | ||
), | ||
)); | ||
} | ||
if version_as_usize > self.config.current_tx_version { | ||
return Err(TransactionValidatorError::InvalidTransactionVersion( | ||
version, | ||
format!( | ||
"Maximal valid version is {}.", | ||
self.config.current_tx_version | ||
), | ||
)); | ||
} | ||
if version_as_usize > 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,100 @@ | ||
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::errors::TransactionValidatorError; | ||
use crate::transaction_validator::{TransactionValidator, TransactionValidatorConfig}; | ||
|
||
#[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()} | ||
)), | ||
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()} | ||
)), | ||
TransactionValidatorError::BlockedTransactionVersion( | ||
TransactionVersion::TWO, | ||
"Transaction type is temporarily blocked.".to_string() | ||
) | ||
)] | ||
#[case::tx_version_below_minimal( | ||
TransactionValidatorConfig { | ||
min_allowed_tx_version: 3, | ||
max_allowed_tx_version: 3, | ||
current_tx_version: 3, | ||
..Default::default() | ||
}, | ||
Transaction::Invoke(InvokeTransaction::V1(InvokeTransactionV1 {..Default::default()})), | ||
TransactionValidatorError::InvalidTransactionVersion( | ||
TransactionVersion::ONE, | ||
"Minimal supported version is 3.".to_string() | ||
) | ||
)] | ||
#[case::tx_version_above_maximal( | ||
TransactionValidatorConfig { | ||
min_allowed_tx_version: 0, | ||
max_allowed_tx_version: 0, | ||
current_tx_version: 1, | ||
..Default::default() | ||
}, | ||
Transaction::Invoke(InvokeTransaction::V1(InvokeTransactionV1 {..Default::default()})), | ||
TransactionValidatorError::InvalidTransactionVersion( | ||
TransactionVersion::ONE, | ||
"Maximal supported version is 0.".to_string() | ||
) | ||
)] | ||
#[case::tx_version_above_current( | ||
TransactionValidatorConfig { | ||
min_allowed_tx_version: 0, | ||
max_allowed_tx_version: 0, | ||
current_tx_version: 0, | ||
..Default::default() | ||
}, | ||
Transaction::Invoke(InvokeTransaction::V1(InvokeTransactionV1 {..Default::default()})), | ||
TransactionValidatorError::InvalidTransactionVersion( | ||
TransactionVersion::ONE, | ||
"Maximal valid version is 0.".to_string() | ||
) | ||
)] | ||
#[case::deprecated_deploy_tx( | ||
TransactionValidatorConfig { | ||
..Default::default() | ||
}, | ||
Transaction::Deploy(starknet_api::transaction::DeployTransaction {..Default::default()}), | ||
TransactionValidatorError::InvalidTransactionType | ||
)] | ||
#[case::unsupported_l1_handler_tx( | ||
TransactionValidatorConfig { | ||
..Default::default() | ||
}, | ||
Transaction::L1Handler(starknet_api::transaction::L1HandlerTransaction {..Default::default()}), | ||
TransactionValidatorError::InvalidTransactionType | ||
)] | ||
fn test_transaction_version( | ||
#[case] config: TransactionValidatorConfig, | ||
#[case] tx: Transaction, | ||
#[case] expected_error: TransactionValidatorError, | ||
) { | ||
let tx_validator = TransactionValidator { config }; | ||
let result = tx_validator.validate(tx); | ||
|
||
assert_eq!(result.unwrap_err(), expected_error); | ||
} |