diff --git a/CHANGELOG.md b/CHANGELOG.md index 84cf5c96ac..d350dc1195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Next release +- feat: add `TransactionFilter` to pallet-starknet `Config` - chore: remove `ignore` from `storage_changes_should_revert_on_transaction_revert` test - dev: Implement tests for new rpc method starknet_getTransactionStatus diff --git a/crates/pallets/starknet/src/lib.rs b/crates/pallets/starknet/src/lib.rs index 65295bc386..8a3e8dc84b 100644 --- a/crates/pallets/starknet/src/lib.rs +++ b/crates/pallets/starknet/src/lib.rs @@ -79,10 +79,10 @@ use mp_block::{Block as StarknetBlock, Header as StarknetHeader}; use mp_chain_id::MADARA_CHAIN_ID; use mp_digest_log::MADARA_ENGINE_ID; use mp_felt::Felt252Wrapper; -use mp_starknet_inherent::{InherentError, InherentType, STARKNET_INHERENT_IDENTIFIER}; +use mp_starknet_inherent::{InherentError, InherentType, L1GasPrices, STARKNET_INHERENT_IDENTIFIER}; use mp_storage::{StarknetStorageSchemaVersion, PALLET_STARKNET_SCHEMA}; use mp_transactions::execution::{ - execute_l1_handler_transaction, run_non_revertible_transaction, run_revertible_transaction, + execute_l1_handler_transaction, run_non_revertible_transaction, run_revertible_transaction, TransactionFilter, }; use mp_transactions::{get_transaction_nonce, get_transaction_sender_address}; use sp_runtime::traits::UniqueSaturatedInto; @@ -118,7 +118,6 @@ macro_rules! log { #[frame_support::pallet] pub mod pallet { - use mp_starknet_inherent::L1GasPrices; use super::*; @@ -132,6 +131,12 @@ pub mod pallet { pub trait Config: frame_system::Config { /// The block time type TimestampProvider: Time; + /// Custom transaction filter for Invoke txs + type InvokeTransactionFilter: TransactionFilter; + /// Custom transaction filter for Declare txs + type DeclareTransactionFilter: TransactionFilter; + /// Custom transaction filter for DeployAccount txs + type DeployAccountTransactionFilter: TransactionFilter; /// A configuration for base priority of unsigned transactions. /// /// This is exposed so that it can be tuned for particular runtime, when @@ -519,10 +524,20 @@ pub mod pallet { // Execute let tx_execution_infos = match transaction.tx.version() { - TransactionVersion::ZERO => { - run_non_revertible_transaction(&transaction, &mut state, &block_context, true, charge_fee) - } - _ => run_revertible_transaction(&transaction, &mut state, &block_context, true, charge_fee), + TransactionVersion::ZERO => run_non_revertible_transaction::<_, _, T::InvokeTransactionFilter>( + &transaction, + &mut state, + &block_context, + true, + charge_fee, + ), + _ => run_revertible_transaction::<_, _, T::InvokeTransactionFilter>( + &transaction, + &mut state, + &block_context, + true, + charge_fee, + ), } .map_err(|e| { log!(error, "Invoke transaction execution failed: {:?}", e); @@ -576,12 +591,14 @@ pub mod pallet { let charge_fee = !::DisableTransactionFee::get(); // Execute - let tx_execution_infos = - run_non_revertible_transaction(&transaction, &mut state, &Self::get_block_context(), true, charge_fee) - .map_err(|e| { - log!(error, "Declare transaction execution failed: {:?}", e); - Error::::TransactionExecutionFailed - })?; + let tx_execution_infos = run_non_revertible_transaction::<_, _, T::DeclareTransactionFilter>( + &transaction, + &mut state, + &Self::get_block_context(), + true, + charge_fee, + ) + .map_err(|_| Error::::TransactionExecutionFailed)?; Self::emit_and_store_tx_and_fees_events( transaction.tx_hash(), @@ -626,12 +643,14 @@ pub mod pallet { let charge_fee = !::DisableTransactionFee::get(); // Execute - let tx_execution_infos = - run_non_revertible_transaction(&transaction, &mut state, &Self::get_block_context(), true, charge_fee) - .map_err(|e| { - log!(error, "Deploy account transaction execution failed: {:?}", e); - Error::::TransactionExecutionFailed - })?; + let tx_execution_infos = run_non_revertible_transaction::<_, _, T::DeployAccountTransactionFilter>( + &transaction, + &mut state, + &Self::get_block_context(), + true, + charge_fee, + ) + .map_err(|_| Error::::TransactionExecutionFailed)?; Self::emit_and_store_tx_and_fees_events( transaction.tx_hash, diff --git a/crates/pallets/starknet/src/simulations.rs b/crates/pallets/starknet/src/simulations.rs index 99f4ea5cf5..0194eacfd0 100644 --- a/crates/pallets/starknet/src/simulations.rs +++ b/crates/pallets/starknet/src/simulations.rs @@ -351,22 +351,24 @@ impl Pallet { simulation_flags: &SimulationFlags, ) -> Result { match transaction { - AccountTransaction::Declare(tx) => run_non_revertible_transaction( - tx, - state, - block_context, - simulation_flags.validate, - simulation_flags.charge_fee, - ), - AccountTransaction::DeployAccount(tx) => run_non_revertible_transaction( + AccountTransaction::Declare(tx) => run_non_revertible_transaction::<_, _, T::DeclareTransactionFilter>( tx, state, block_context, simulation_flags.validate, simulation_flags.charge_fee, ), + AccountTransaction::DeployAccount(tx) => { + run_non_revertible_transaction::<_, _, T::DeployAccountTransactionFilter>( + tx, + state, + block_context, + simulation_flags.validate, + simulation_flags.charge_fee, + ) + } AccountTransaction::Invoke(tx) if tx.tx.version() == TransactionVersion::ZERO => { - run_non_revertible_transaction( + run_non_revertible_transaction::<_, _, T::InvokeTransactionFilter>( tx, state, block_context, @@ -374,7 +376,7 @@ impl Pallet { simulation_flags.charge_fee, ) } - AccountTransaction::Invoke(tx) => run_revertible_transaction( + AccountTransaction::Invoke(tx) => run_revertible_transaction::<_, _, T::InvokeTransactionFilter>( tx, state, block_context, diff --git a/crates/pallets/starknet/src/tests/mock/setup_mock.rs b/crates/pallets/starknet/src/tests/mock/setup_mock.rs index 09455bf65e..4e0a8d374f 100644 --- a/crates/pallets/starknet/src/tests/mock/setup_mock.rs +++ b/crates/pallets/starknet/src/tests/mock/setup_mock.rs @@ -87,6 +87,9 @@ macro_rules! mock_runtime { type ProtocolVersion = ProtocolVersion; type ProgramHash = ProgramHash; type ExecutionConstants = ExecutionConstants; + type InvokeTransactionFilter = (); + type DeclareTransactionFilter = (); + type DeployAccountTransactionFilter = (); } /// Run to block n. diff --git a/crates/pallets/starknet/src/transaction_validation.rs b/crates/pallets/starknet/src/transaction_validation.rs index acdd35619c..b45bb77af5 100644 --- a/crates/pallets/starknet/src/transaction_validation.rs +++ b/crates/pallets/starknet/src/transaction_validation.rs @@ -70,13 +70,13 @@ impl Pallet { match transaction { AccountTransaction::Declare(transaction) => { - Validate::perform_pre_validation_stage(transaction, &mut state, tx_context, string_nonce_checking, charge_fee) + Validate::perform_pre_validation_stage::(transaction, &mut state, tx_context, string_nonce_checking, charge_fee) } AccountTransaction::DeployAccount(transaction) => { - Validate::perform_pre_validation_stage(transaction, &mut state, tx_context, string_nonce_checking, charge_fee) + Validate::perform_pre_validation_stage::(transaction, &mut state, tx_context, string_nonce_checking, charge_fee) } AccountTransaction::Invoke(transaction) => { - Validate::perform_pre_validation_stage(transaction, &mut state, tx_context, string_nonce_checking, charge_fee) + Validate::perform_pre_validation_stage::(transaction, &mut state, tx_context, string_nonce_checking, charge_fee) } } // TODO: have more granular error mapping diff --git a/crates/primitives/transactions/src/execution.rs b/crates/primitives/transactions/src/execution.rs index 74a2fbab27..d856905ce3 100644 --- a/crates/primitives/transactions/src/execution.rs +++ b/crates/primitives/transactions/src/execution.rs @@ -32,6 +32,32 @@ use starknet_api::transaction::{Calldata, Fee, ResourceBounds, TransactionVersio use super::SIMULATE_TX_VERSION_OFFSET; +pub trait TransactionFilter { + fn is_valid(transaction: &T) -> bool; +} + +impl TransactionFilter for () { + fn is_valid(_transaction: &T) -> bool { + true + } +} + +pub struct BanInvokeV0TransactionRule; + +impl TransactionFilter for BanInvokeV0TransactionRule { + fn is_valid(transaction: &InvokeTransaction) -> bool { + !matches!(transaction.tx, starknet_api::transaction::InvokeTransaction::V0(_)) + } +} + +pub struct BanDeclareV0TransactionRule; + +impl TransactionFilter for BanDeclareV0TransactionRule { + fn is_valid(transaction: &DeclareTransaction) -> bool { + !matches!(transaction.tx, starknet_api::transaction::DeclareTransaction::V0(_)) + } +} + /// Contains the execution configuration regarding transaction fee /// activation, transaction fee charging, nonce validation, transaction /// validation and the execution mode (query or not). @@ -332,13 +358,8 @@ impl GetValidateEntryPointSelector for L1HandlerTransaction { } #[allow(clippy::too_many_arguments)] -pub trait Validate: GetValidateEntryPointSelector { - // Implement this to blacklist some transaction versions - fn validate_tx_version(&self) -> TransactionExecutionResult<()> { - Ok(()) - } - - fn validate( +pub trait Validate: Sized + GetValidateEntryPointSelector { + fn validate>( &self, state: &mut dyn State, tx_context: Arc, @@ -349,7 +370,7 @@ pub trait Validate: GetValidateEntryPointSelector { strict_nonce_checking: bool, ) -> TransactionExecutionResult>; - fn perform_pre_validation_stage( + fn perform_pre_validation_stage>( &self, state: &mut dyn State, tx_context: Arc, @@ -375,7 +396,7 @@ impl< + TransactionInfoCreator, > Validate for T { - fn validate( + fn validate>( &self, state: &mut dyn State, tx_context: Arc, @@ -386,7 +407,7 @@ impl< strict_nonce_checking: bool, ) -> TransactionExecutionResult> { // Check tx version, nonce and fee - self.perform_pre_validation_stage(state, tx_context.clone(), strict_nonce_checking, charge_fee)?; + self.perform_pre_validation_stage::(state, tx_context.clone(), strict_nonce_checking, charge_fee)?; // Run the actual `validate` entrypoint if validate_tx { @@ -396,15 +417,14 @@ impl< } } - fn perform_pre_validation_stage( + fn perform_pre_validation_stage>( &self, state: &mut dyn State, tx_context: Arc, strict_nonce_checking: bool, charge_fee: bool, ) -> TransactionExecutionResult<()> { - // Check that version of the Tx is supported by the network - self.validate_tx_version()?; + assert!(F::is_valid(self), "custom chain provided tx filter failed"); // Check if nonce has a correct value Self::handle_nonce(state, &tx_context.tx_info, strict_nonce_checking)?; @@ -545,7 +565,7 @@ impl SetArbitraryNonce for CachedState { } } -pub fn run_non_revertible_transaction( +pub fn run_non_revertible_transaction( transaction: &T, state: &mut S, block_context: &BlockContext, @@ -554,6 +574,7 @@ pub fn run_non_revertible_transaction( ) -> TransactionExecutionResult where S: State, + F: TransactionFilter, T: GetTxType + Executable + Validate + GetActualCostBuilder + TransactionInfoCreator, { let mut resources = ExecutionResources::default(); @@ -570,7 +591,7 @@ where let mut execution_context = EntryPointExecutionContext::new_validate(tx_context.clone(), charge_fee)?; execute_call_info = transaction.run_execute(state, &mut resources, &mut execution_context, &mut remaining_gas)?; - validate_call_info = transaction.validate( + validate_call_info = transaction.validate::( state, tx_context.clone(), &mut resources, @@ -581,7 +602,7 @@ where )?; } else { let mut execution_context = EntryPointExecutionContext::new_invoke(tx_context.clone(), charge_fee)?; - validate_call_info = transaction.validate( + validate_call_info = transaction.validate::( state, tx_context.clone(), &mut resources, @@ -632,7 +653,7 @@ where Ok(tx_execution_info) } -pub fn run_revertible_transaction( +pub fn run_revertible_transaction( transaction: &T, state: &mut S, block_context: &BlockContext, @@ -647,12 +668,13 @@ where + GetCalldataLen + TransactionInfoCreator, S: State + SetArbitraryNonce, + F: TransactionFilter, { let mut resources = ExecutionResources::default(); let mut remaining_gas = block_context.versioned_constants().tx_initial_gas(); let tx_context = Arc::new(block_context.to_tx_context(transaction)); - let validate_call_info = transaction.validate( + let validate_call_info = transaction.validate::( state, tx_context.clone(), &mut resources, diff --git a/crates/runtime/src/pallets.rs b/crates/runtime/src/pallets.rs index e6b22473cc..41fc429405 100644 --- a/crates/runtime/src/pallets.rs +++ b/crates/runtime/src/pallets.rs @@ -75,6 +75,9 @@ impl pallet_starknet::Config for Runtime { type ProtocolVersion = ProtocolVersion; type ProgramHash = ProgramHash; type ExecutionConstants = ExecutionConstants; + type InvokeTransactionFilter = (); + type DeclareTransactionFilter = (); + type DeployAccountTransactionFilter = (); } /// --------------------------------------