diff --git a/CHANGELOG.md b/CHANGELOG.md index e443515aa7..6960da9134 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Next release +- feat(rpc/trace_api): add `trace_block_transaction` +- chore(runtime_api): remove unused `filter_extrinsic` - fix: don't ignore Sierra to CASM mapping in genesis config - refacto: early exit txs fee estimation when one fails - dev: fix linter warning in README.md @@ -61,7 +63,7 @@ - feat: fixing getNonce Rpc Call and adding a new test - refactor: use Zaun crate for Starknet core contract bindings - refactor: use Anvil sandbox from Zaun crate -- feat(rpc) : estimateMessageFee RPC call implementation +- feat(rpc): estimateMessageFee RPC call implementation ## v0.6.0 diff --git a/crates/client/rpc-core/src/lib.rs b/crates/client/rpc-core/src/lib.rs index 537e6ec152..b4bbfcc18a 100644 --- a/crates/client/rpc-core/src/lib.rs +++ b/crates/client/rpc-core/src/lib.rs @@ -23,6 +23,7 @@ use starknet_core::types::{ DeployAccountTransactionResult, EventFilterWithPage, EventsPage, FeeEstimate, FieldElement, FunctionCall, InvokeTransactionResult, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingTransactionReceipt, MsgFromL1, SimulatedTransaction, SimulationFlag, StateUpdate, SyncStatusType, Transaction, + TransactionTraceWithHash, }; #[serde_as] @@ -178,4 +179,8 @@ pub trait StarknetTraceRpcApi { transactions: Vec, simulation_flags: Vec, ) -> RpcResult>; + + #[method(name = "traceBlockTransactions")] + /// Returns the execution traces of all transactions included in the given block + async fn trace_block_transactions(&self, block_id: BlockId) -> RpcResult>; } diff --git a/crates/client/rpc/src/trace_api.rs b/crates/client/rpc/src/trace_api.rs index 92c636dff3..e87c4105ec 100644 --- a/crates/client/rpc/src/trace_api.rs +++ b/crates/client/rpc/src/trace_api.rs @@ -4,6 +4,7 @@ use blockifier::transaction::objects::TransactionExecutionInfo; use jsonrpsee::core::{async_trait, RpcResult}; use log::error; use mc_genesis_data_provider::GenesisProvider; +use mc_rpc_core::utils::get_block_by_block_hash; use mc_rpc_core::{StarknetReadRpcApiServer, StarknetTraceRpcApiServer}; use mc_storage::StorageOverride; use mp_felt::Felt252Wrapper; @@ -19,7 +20,8 @@ use sp_blockchain::HeaderBackend; use sp_runtime::traits::Block as BlockT; use starknet_core::types::{ BlockId, BroadcastedTransaction, DeclareTransactionTrace, DeployAccountTransactionTrace, ExecuteInvocation, - FeeEstimate, InvokeTransactionTrace, RevertedInvocation, SimulatedTransaction, SimulationFlag, TransactionTrace, + FeeEstimate, InvokeTransactionTrace, L1HandlerTransactionTrace, RevertedInvocation, SimulatedTransaction, + SimulationFlag, TransactionTrace, TransactionTraceWithHash, }; use starknet_ff::FieldElement; use thiserror::Error; @@ -85,17 +87,73 @@ where let storage_override = self.overrides.for_block_hash(self.client.as_ref(), substrate_block_hash); let simulated_transactions = tx_execution_infos_to_simulated_transactions(&**storage_override, substrate_block_hash, tx_types, res) - .map_err(|e| match e { - ConvertCallInfoToExecuteInvocationError::TransactionExecutionFailed => { - StarknetRpcApiError::ContractError - } - ConvertCallInfoToExecuteInvocationError::GetFunctionInvocation(_) => { - StarknetRpcApiError::InternalServerError - } - })?; + .map_err(|e| StarknetRpcApiError::from(e))?; Ok(simulated_transactions) } + + async fn trace_block_transactions(&self, block_id: BlockId) -> RpcResult> { + let substrate_block_hash = self.substrate_block_hash_from_starknet_block(block_id).map_err(|e| { + error!("Block not found: '{e}'"); + StarknetRpcApiError::BlockNotFound + })?; + let block_extrinsics = self + .client + .block_body(substrate_block_hash) + .map_err(|e| { + error!("Failed to get block body. Substrate block hash: {substrate_block_hash}, error: {e}"); + StarknetRpcApiError::InternalServerError + })? + .ok_or(StarknetRpcApiError::BlockNotFound)?; + + let previous_block_substrate_hash = { + let starknet_block = + get_block_by_block_hash(self.client.as_ref(), substrate_block_hash).ok_or_else(|| { + error!("Failed to starknet block for substate block with hash {substrate_block_hash}"); + StarknetRpcApiError::InternalServerError + })?; + let block_number = starknet_block.header().block_number; + let previous_block_number = block_number - 1; + self.substrate_block_hash_from_starknet_block(BlockId::Number(previous_block_number)).map_err(|e| { + error!("Failed to retrieve previous block substrate hash: {e}"); + StarknetRpcApiError::InternalServerError + }) + }?; + + let execution_infos = self + .client + .runtime_api() + .re_execute_transactions(previous_block_substrate_hash, block_extrinsics) + .map_err(|e| { + error!("Failed to execute runtime API call: {e}"); + StarknetRpcApiError::InternalServerError + })? + .map_err(|e| { + error!("Failed to reexecute the block transactions: {e:?}"); + StarknetRpcApiError::InternalServerError + })? + .map_err(|_| { + error!( + "One of the transaction failed during it's reexecution. This should not happen, as the block has \ + already been executed successfully in the past. There is a bug somewhere." + ); + StarknetRpcApiError::InternalServerError + })?; + + let storage_override = self.overrides.for_block_hash(self.client.as_ref(), substrate_block_hash); + let traces = execution_infos + .into_iter() + .map(|(tx_hash, tx_type, tx_exec_info)| { + tx_execution_infos_to_tx_trace(&**storage_override, substrate_block_hash, tx_type, &tx_exec_info) + .and_then(|trace_root| { + Ok(TransactionTraceWithHash { transaction_hash: tx_hash.into(), trace_root }) + }) + }) + .collect::, _>>() + .map_err(|e| StarknetRpcApiError::from(e))?; + + Ok(traces) + } } #[derive(Error, Debug)] @@ -106,6 +164,17 @@ pub enum ConvertCallInfoToExecuteInvocationError { GetFunctionInvocation(#[from] TryFuntionInvocationFromCallInfoError), } +impl From for StarknetRpcApiError { + fn from(err: ConvertCallInfoToExecuteInvocationError) -> Self { + match err { + ConvertCallInfoToExecuteInvocationError::TransactionExecutionFailed => StarknetRpcApiError::ContractError, + ConvertCallInfoToExecuteInvocationError::GetFunctionInvocation(_) => { + StarknetRpcApiError::InternalServerError + } + } + } +} + fn collect_call_info_ordered_messages(call_info: &CallInfo) -> Vec { call_info .execution @@ -209,6 +278,78 @@ fn try_get_funtion_invocation_from_call_info( }) } +fn tx_execution_infos_to_tx_trace( + storage_override: &dyn StorageOverride, + substrate_block_hash: B::Hash, + tx_type: TxType, + tx_exec_info: &TransactionExecutionInfo, +) -> Result { + // If simulated with `SimulationFlag::SkipValidate` this will be `None` + // therefore we cannot unwrap it + let validate_invocation = tx_exec_info + .validate_call_info + .as_ref() + .map(|call_info| try_get_funtion_invocation_from_call_info(storage_override, substrate_block_hash, call_info)) + .transpose()?; + // If simulated with `SimulationFlag::SkipFeeCharge` this will be `None` + // therefore we cannot unwrap it + let fee_transfer_invocation = tx_exec_info + .fee_transfer_call_info + .as_ref() + .map(|call_info| try_get_funtion_invocation_from_call_info(storage_override, substrate_block_hash, call_info)) + .transpose()?; + + let tx_trace = match tx_type { + TxType::Invoke => TransactionTrace::Invoke(InvokeTransactionTrace { + validate_invocation, + execute_invocation: if let Some(e) = &tx_exec_info.revert_error { + ExecuteInvocation::Reverted(RevertedInvocation { revert_reason: e.clone() }) + } else { + ExecuteInvocation::Success(try_get_funtion_invocation_from_call_info( + storage_override, + substrate_block_hash, + // Safe to unwrap because is only `None` for `Declare` txs + tx_exec_info.execute_call_info.as_ref().unwrap(), + )?) + }, + fee_transfer_invocation, + // TODO(#1291): Compute state diff correctly + state_diff: None, + }), + TxType::Declare => TransactionTrace::Declare(DeclareTransactionTrace { + validate_invocation, + fee_transfer_invocation, + // TODO(#1291): Compute state diff correctly + state_diff: None, + }), + TxType::DeployAccount => { + TransactionTrace::DeployAccount(DeployAccountTransactionTrace { + validate_invocation, + constructor_invocation: try_get_funtion_invocation_from_call_info( + storage_override, + substrate_block_hash, + // Safe to unwrap because is only `None` for `Declare` txs + tx_exec_info.execute_call_info.as_ref().unwrap(), + )?, + fee_transfer_invocation, + // TODO(#1291): Compute state diff correctly + state_diff: None, + }) + } + TxType::L1Handler => TransactionTrace::L1Handler(L1HandlerTransactionTrace { + function_invocation: try_get_funtion_invocation_from_call_info( + storage_override, + substrate_block_hash, + // Safe to unwrap because is only `None` for `Declare` txs + tx_exec_info.execute_call_info.as_ref().unwrap(), + )?, + state_diff: None, + }), + }; + + Ok(tx_trace) +} + fn tx_execution_infos_to_simulated_transactions( storage_override: &dyn StorageOverride, substrate_block_hash: B::Hash, @@ -218,68 +359,11 @@ fn tx_execution_infos_to_simulated_transactions( >, ) -> Result, ConvertCallInfoToExecuteInvocationError> { let mut results = vec![]; - for (tx_type, res) in tx_types.iter().zip(transaction_execution_results.iter()) { + for (tx_type, res) in tx_types.into_iter().zip(transaction_execution_results.into_iter()) { match res { Ok(tx_exec_info) => { - // If simulated with `SimulationFlag::SkipValidate` this will be `None` - // therefore we cannot unwrap it - let validate_invocation = tx_exec_info - .validate_call_info - .as_ref() - .map(|call_info| { - try_get_funtion_invocation_from_call_info(storage_override, substrate_block_hash, call_info) - }) - .transpose()?; - // If simulated with `SimulationFlag::SkipFeeCharge` this will be `None` - // therefore we cannot unwrap it - let fee_transfer_invocation = tx_exec_info - .fee_transfer_call_info - .as_ref() - .map(|call_info| { - try_get_funtion_invocation_from_call_info(storage_override, substrate_block_hash, call_info) - }) - .transpose()?; - - let transaction_trace = match tx_type { - TxType::Invoke => TransactionTrace::Invoke(InvokeTransactionTrace { - validate_invocation, - execute_invocation: if let Some(e) = &tx_exec_info.revert_error { - ExecuteInvocation::Reverted(RevertedInvocation { revert_reason: e.clone() }) - } else { - ExecuteInvocation::Success(try_get_funtion_invocation_from_call_info( - storage_override, - substrate_block_hash, - // Safe to unwrap because is only `None` for `Declare` txs - tx_exec_info.execute_call_info.as_ref().unwrap(), - )?) - }, - fee_transfer_invocation, - // TODO(#1291): Compute state diff correctly - state_diff: None, - }), - TxType::Declare => TransactionTrace::Declare(DeclareTransactionTrace { - validate_invocation, - fee_transfer_invocation, - // TODO(#1291): Compute state diff correctly - state_diff: None, - }), - TxType::DeployAccount => { - TransactionTrace::DeployAccount(DeployAccountTransactionTrace { - validate_invocation, - constructor_invocation: try_get_funtion_invocation_from_call_info( - storage_override, - substrate_block_hash, - // Safe to unwrap because is only `None` for `Declare` txs - tx_exec_info.execute_call_info.as_ref().unwrap(), - )?, - fee_transfer_invocation, - // TODO(#1291): Compute state diff correctly - state_diff: None, - }) - } - TxType::L1Handler => unreachable!("L1Handler transactions cannot be simulated"), - }; - + let transaction_trace = + tx_execution_infos_to_tx_trace(storage_override, substrate_block_hash, tx_type, &tx_exec_info)?; let gas_consumed = tx_exec_info.execute_call_info.as_ref().map(|x| x.execution.gas_consumed).unwrap_or_default(); let overall_fee = tx_exec_info.actual_fee.0 as u64; diff --git a/crates/pallets/starknet/runtime_api/src/lib.rs b/crates/pallets/starknet/runtime_api/src/lib.rs index 0eaeb6fd5a..d954f2d827 100644 --- a/crates/pallets/starknet/runtime_api/src/lib.rs +++ b/crates/pallets/starknet/runtime_api/src/lib.rs @@ -18,6 +18,7 @@ use alloc::string::String; use alloc::vec::Vec; use mp_simulations::{PlaceHolderErrorTypeForFailedStarknetExecution, SimulationFlags}; +use mp_transactions::TxType; use sp_runtime::DispatchError; use starknet_api::api_core::{ChainId, ClassHash, ContractAddress, EntryPointSelector, Nonce}; use starknet_api::block::{BlockNumber, BlockTimestamp}; @@ -60,15 +61,8 @@ sp_api::decl_runtime_apis! { fn estimate_message_fee(message: HandleL1MessageTransaction) -> Result<(u128, u64, u64), DispatchError>; /// Simulates transactions and returns their trace fn simulate_transactions(transactions: Vec, simulation_flags: SimulationFlags) -> Result>, DispatchError>; - /// Filters extrinsic transactions to return only Starknet transactions - /// - /// To support runtime upgrades, the client must be unaware of the specific extrinsic - /// details. To achieve this, the client uses an OpaqueExtrinsic type to represent and - /// manipulate extrinsics. However, the client cannot decode and filter extrinsics due to - /// this limitation. The solution is to offload decoding and filtering to the RuntimeApi in - /// the runtime itself, accomplished through the extrinsic_filter method. This enables the - /// client to operate seamlessly while abstracting the extrinsic complexity. - fn extrinsic_filter(xts: Vec<::Extrinsic>) -> Vec; + /// Re-execute a block and return the TransactionExecutionInfos of every transaction in it + fn re_execute_transactions(xts: Vec<::Extrinsic>) -> Result, PlaceHolderErrorTypeForFailedStarknetExecution>, DispatchError>; fn get_index_and_tx_for_tx_hash(xts: Vec<::Extrinsic>, chain_id: Felt252Wrapper, tx_hash: Felt252Wrapper) -> Option<(u32, Transaction)>; /// Returns events, call with index from get_index_and_tx_for_tx_hash method fn get_events_for_tx_by_index(tx_index: u32) -> Option>; diff --git a/crates/pallets/starknet/src/lib.rs b/crates/pallets/starknet/src/lib.rs index 12f336fcff..01bd65dba6 100644 --- a/crates/pallets/starknet/src/lib.rs +++ b/crates/pallets/starknet/src/lib.rs @@ -85,7 +85,7 @@ use mp_storage::{StarknetStorageSchemaVersion, PALLET_STARKNET_SCHEMA}; use mp_transactions::execution::Execute; use mp_transactions::{ DeclareTransaction, DeployAccountTransaction, HandleL1MessageTransaction, InvokeTransaction, Transaction, - UserAndL1HandlerTransaction, UserTransaction, + UserOrL1HandlerTransaction, UserTransaction, }; use sp_runtime::traits::UniqueSaturatedInto; use sp_runtime::DigestItem; @@ -787,7 +787,7 @@ impl Pallet { /// # Returns /// /// The transaction - fn get_call_transaction(call: Call) -> Result { + fn get_call_transaction(call: Call) -> Result { let tx = match call { Call::::invoke { transaction } => UserTransaction::Invoke(transaction).into(), Call::::declare { transaction, contract_class } => { @@ -795,7 +795,7 @@ impl Pallet { } Call::::deploy_account { transaction } => UserTransaction::DeployAccount(transaction).into(), Call::::consume_l1_message { transaction, paid_fee_on_l1 } => { - UserAndL1HandlerTransaction::L1Handler(transaction, paid_fee_on_l1) + UserOrL1HandlerTransaction::L1Handler(transaction, paid_fee_on_l1) } _ => return Err(()), }; diff --git a/crates/pallets/starknet/src/simulations.rs b/crates/pallets/starknet/src/simulations.rs index 231f106e7a..07a96c0a85 100644 --- a/crates/pallets/starknet/src/simulations.rs +++ b/crates/pallets/starknet/src/simulations.rs @@ -6,8 +6,9 @@ use blockifier::transaction::objects::TransactionExecutionInfo; use frame_support::storage; use mp_felt::Felt252Wrapper; use mp_simulations::{PlaceHolderErrorTypeForFailedStarknetExecution, SimulationFlags}; +use mp_transactions::compute_hash::ComputeTransactionHash; use mp_transactions::execution::{Execute, ExecutionConfig}; -use mp_transactions::{HandleL1MessageTransaction, UserTransaction}; +use mp_transactions::{HandleL1MessageTransaction, TxType, UserOrL1HandlerTransaction, UserTransaction}; use sp_core::Get; use sp_runtime::DispatchError; use starknet_api::transaction::Fee; @@ -37,7 +38,7 @@ impl Pallet { .map(|tx| { execution_config.set_offset_version(tx.offset_version()); - match Self::execute_transaction(tx, chain_id, &block_context, &execution_config) { + match Self::execute_user_transaction(tx, chain_id, &block_context, &execution_config) { Ok(execution_info) if !execution_info.is_reverted() => Ok(execution_info), Err(e) => { log::error!("Transaction execution failed during fee estimation: {e}"); @@ -100,7 +101,7 @@ impl Pallet { .map(|tx| { execution_config.set_offset_version(tx.offset_version()); - Self::execute_transaction(tx, chain_id, &block_context, &execution_config).map_err(|e| { + Self::execute_user_transaction(tx, chain_id, &block_context, &execution_config).map_err(|e| { log::error!("Transaction execution failed during simulation: {e}"); PlaceHolderErrorTypeForFailedStarknetExecution }) @@ -141,7 +142,68 @@ impl Pallet { } } - fn execute_transaction( + pub fn re_execute_transactions( + transactions: Vec, + ) -> Result< + Result, PlaceHolderErrorTypeForFailedStarknetExecution>, + DispatchError, + > { + storage::transactional::with_transaction(|| { + storage::TransactionOutcome::Rollback(Result::<_, DispatchError>::Ok(Self::re_execute_transactions_inner( + transactions, + ))) + }) + .map_err(|_| Error::::FailedToCreateATransactionalStorageExecution)? + } + + fn re_execute_transactions_inner( + transactions: Vec, + ) -> Result< + Result, PlaceHolderErrorTypeForFailedStarknetExecution>, + DispatchError, + > { + let chain_id = Self::chain_id(); + let block_context = Self::get_block_context(); + let execution_config = RuntimeExecutionConfigBuilder::new::().build(); + + let execution_infos = transactions + .into_iter() + .map(|user_or_l1_tx| match user_or_l1_tx { + UserOrL1HandlerTransaction::User(tx) => match tx { + UserTransaction::Declare(tx, contract_class) => tx + .try_into_executable::(chain_id, contract_class.clone(), tx.offset_version()) + .map_err(|_| PlaceHolderErrorTypeForFailedStarknetExecution) + .and_then(|executable| { + executable + .execute(&mut BlockifierStateAdapter::::default(), &block_context, &execution_config) + .map_err(|_| PlaceHolderErrorTypeForFailedStarknetExecution) + }) + .map(|tx_info| (tx.compute_hash::(chain_id, false), TxType::Declare, tx_info)), + UserTransaction::DeployAccount(tx) => tx + .into_executable::(chain_id, tx.offset_version()) + .execute(&mut BlockifierStateAdapter::::default(), &block_context, &execution_config) + .map_err(|_| PlaceHolderErrorTypeForFailedStarknetExecution) + .map(|tx_info| { + (tx.compute_hash::(chain_id, false), TxType::DeployAccount, tx_info) + }), + UserTransaction::Invoke(tx) => tx + .into_executable::(chain_id, tx.offset_version()) + .execute(&mut BlockifierStateAdapter::::default(), &block_context, &execution_config) + .map_err(|_| PlaceHolderErrorTypeForFailedStarknetExecution) + .map(|tx_info| (tx.compute_hash::(chain_id, false), TxType::Invoke, tx_info)), + }, + UserOrL1HandlerTransaction::L1Handler(tx, fee) => tx + .into_executable::(chain_id, fee, false) + .execute(&mut BlockifierStateAdapter::::default(), &block_context, &execution_config) + .map_err(|_| PlaceHolderErrorTypeForFailedStarknetExecution) + .map(|tx_info| (tx.compute_hash::(chain_id, false), TxType::L1Handler, tx_info)), + }) + .collect::, _>>(); + + Ok(execution_infos) + } + + fn execute_user_transaction( transaction: UserTransaction, chain_id: Felt252Wrapper, block_context: &BlockContext, diff --git a/crates/pallets/starknet/src/tests/l1_handler_validation.rs b/crates/pallets/starknet/src/tests/l1_handler_validation.rs index 4ba2e10fc3..8ee9201dc7 100644 --- a/crates/pallets/starknet/src/tests/l1_handler_validation.rs +++ b/crates/pallets/starknet/src/tests/l1_handler_validation.rs @@ -1,5 +1,5 @@ use assert_matches::assert_matches; -use mp_transactions::{HandleL1MessageTransaction, UserAndL1HandlerTransaction}; +use mp_transactions::{HandleL1MessageTransaction, UserOrL1HandlerTransaction}; use sp_runtime::transaction_validity::InvalidTransaction; use starknet_api::api_core::Nonce; use starknet_api::hash::StarkFelt; @@ -38,7 +38,7 @@ fn should_accept_unused_nonce() { calldata: Default::default(), }; - let tx = UserAndL1HandlerTransaction::L1Handler(transaction, Fee(100)); + let tx = UserOrL1HandlerTransaction::L1Handler(transaction, Fee(100)); assert_matches!(Starknet::validate_unsigned_tx_nonce(&tx), Ok(TxPriorityInfo::L1Handler)); }); @@ -57,7 +57,7 @@ fn should_reject_used_nonce() { calldata: Default::default(), }; - let tx = UserAndL1HandlerTransaction::L1Handler(transaction, Fee(100)); + let tx = UserOrL1HandlerTransaction::L1Handler(transaction, Fee(100)); L1Messages::::mutate(|nonces| nonces.insert(Nonce(nonce.into()))); @@ -78,7 +78,7 @@ fn should_accept_valid_unsigned_l1_message_tx() { calldata: Default::default(), }; - let tx = UserAndL1HandlerTransaction::L1Handler(transaction, Fee(100)); + let tx = UserOrL1HandlerTransaction::L1Handler(transaction, Fee(100)); assert!(Starknet::validate_unsigned_tx(&tx).is_ok()); }); diff --git a/crates/pallets/starknet/src/transaction_validation.rs b/crates/pallets/starknet/src/transaction_validation.rs index 0da8bd6955..56ecc70af2 100644 --- a/crates/pallets/starknet/src/transaction_validation.rs +++ b/crates/pallets/starknet/src/transaction_validation.rs @@ -64,10 +64,10 @@ pub enum TxPriorityInfo { impl Pallet { pub fn validate_unsigned_tx_nonce( - transaction: &UserAndL1HandlerTransaction, + transaction: &UserOrL1HandlerTransaction, ) -> Result { match transaction { - UserAndL1HandlerTransaction::User(tx) => { + UserOrL1HandlerTransaction::User(tx) => { let sender_address: ContractAddress = tx.sender_address().into(); let sender_nonce: Felt252Wrapper = Pallet::::nonce(sender_address).into(); let transaction_nonce = match tx.nonce() { @@ -93,14 +93,14 @@ impl Pallet { Ok(TxPriorityInfo::RegularTxs { sender_address: tx.sender_address(), transaction_nonce, sender_nonce }) } - UserAndL1HandlerTransaction::L1Handler(tx, _fee) => { + UserOrL1HandlerTransaction::L1Handler(tx, _fee) => { Self::ensure_l1_message_not_executed(&Nonce(StarkFelt::from(tx.nonce)))?; Ok(TxPriorityInfo::L1Handler) } } } - pub fn validate_unsigned_tx(transaction: &UserAndL1HandlerTransaction) -> Result<(), InvalidTransaction> { + pub fn validate_unsigned_tx(transaction: &UserOrL1HandlerTransaction) -> Result<(), InvalidTransaction> { let chain_id = Self::chain_id(); let block_context = Self::get_block_context(); let mut state: BlockifierStateAdapter = BlockifierStateAdapter::::default(); @@ -108,7 +108,7 @@ impl Pallet { let mut initial_gas = blockifier::abi::constants::INITIAL_GAS_COST; match transaction { - UserAndL1HandlerTransaction::User(transaction) => { + UserOrL1HandlerTransaction::User(transaction) => { let validation_result = match transaction { // There is no way to validate it before the account is actuallly deployed @@ -140,7 +140,7 @@ impl Pallet { validation_result } } - UserAndL1HandlerTransaction::L1Handler(_, fee) => { + UserOrL1HandlerTransaction::L1Handler(_, fee) => { // The tx will fail if no fee have been paid if fee.0 == 0 { return Err(InvalidTransaction::Payment); diff --git a/crates/primitives/transactions/src/getters.rs b/crates/primitives/transactions/src/getters.rs index f2d965f153..1661358f8a 100644 --- a/crates/primitives/transactions/src/getters.rs +++ b/crates/primitives/transactions/src/getters.rs @@ -5,7 +5,7 @@ use mp_felt::Felt252Wrapper; use super::{DeclareTransaction, DeployAccountTransaction, InvokeTransaction, Transaction, UserTransaction}; use crate::{ DeclareTransactionV0, DeclareTransactionV1, DeclareTransactionV2, HandleL1MessageTransaction, InvokeTransactionV0, - InvokeTransactionV1, UserAndL1HandlerTransaction, + InvokeTransactionV1, UserOrL1HandlerTransaction, }; impl Transaction { @@ -230,12 +230,12 @@ impl TransactionVersion for Transaction { } } -impl TransactionVersion for UserAndL1HandlerTransaction { +impl TransactionVersion for UserOrL1HandlerTransaction { #[inline(always)] fn version(&self) -> u8 { match self { - UserAndL1HandlerTransaction::User(tx) => tx.version(), - UserAndL1HandlerTransaction::L1Handler(tx, _) => tx.version(), + UserOrL1HandlerTransaction::User(tx) => tx.version(), + UserOrL1HandlerTransaction::L1Handler(tx, _) => tx.version(), } } } diff --git a/crates/primitives/transactions/src/lib.rs b/crates/primitives/transactions/src/lib.rs index becd247215..6df71912b9 100644 --- a/crates/primitives/transactions/src/lib.rs +++ b/crates/primitives/transactions/src/lib.rs @@ -87,7 +87,7 @@ pub enum Transaction { #[derive(Clone, Debug, Eq, PartialEq, From)] #[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, parity_scale_codec::Decode))] #[cfg_attr(feature = "scale-info", derive(scale_info::TypeInfo))] -pub enum UserAndL1HandlerTransaction { +pub enum UserOrL1HandlerTransaction { User(UserTransaction), L1Handler(HandleL1MessageTransaction, Fee), } diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs index 4013be4684..8a5f8857f2 100644 --- a/crates/runtime/src/lib.rs +++ b/crates/runtime/src/lib.rs @@ -31,7 +31,7 @@ use frame_system::{EventRecord, Phase}; use mp_felt::Felt252Wrapper; use mp_simulations::{PlaceHolderErrorTypeForFailedStarknetExecution, SimulationFlags}; use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::{HandleL1MessageTransaction, Transaction, UserTransaction}; +use mp_transactions::{HandleL1MessageTransaction, Transaction, TxType, UserOrL1HandlerTransaction, UserTransaction}; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; /// Import the Starknet pallet. pub use pallet_starknet; @@ -280,6 +280,17 @@ impl_runtime_apis! { Starknet::estimate_fee(transactions) } + fn re_execute_transactions(xts: Vec<::Extrinsic>) -> Result, PlaceHolderErrorTypeForFailedStarknetExecution>, DispatchError> { + let transactions = xts.into_iter().filter_map(|xt| match xt.function { + RuntimeCall::Starknet( invoke { transaction }) => Some(UserOrL1HandlerTransaction::User(UserTransaction::Invoke(transaction))), + RuntimeCall::Starknet( declare { transaction, contract_class}) => Some(UserOrL1HandlerTransaction::User(UserTransaction::Declare(transaction, contract_class))), + RuntimeCall::Starknet( deploy_account { transaction }) => Some(UserOrL1HandlerTransaction::User(UserTransaction::DeployAccount(transaction))), + RuntimeCall::Starknet( consume_l1_message { transaction, paid_fee_on_l1 }) => Some(UserOrL1HandlerTransaction::L1Handler(transaction, paid_fee_on_l1)), + _ => None + }).collect::>(); + Starknet::re_execute_transactions(transactions) + } + fn estimate_message_fee(message: HandleL1MessageTransaction) -> Result<(u128, u64, u64), DispatchError> { Starknet::estimate_message_fee(message) } @@ -313,16 +324,6 @@ impl_runtime_apis! { }).collect() } - fn extrinsic_filter(xts: Vec<::Extrinsic>) -> Vec { - xts.into_iter().filter_map(|xt| match xt.function { - RuntimeCall::Starknet( invoke { transaction }) => Some(Transaction::Invoke(transaction)), - RuntimeCall::Starknet( declare { transaction, .. }) => Some(Transaction::Declare(transaction)), - RuntimeCall::Starknet( deploy_account { transaction }) => Some(Transaction::DeployAccount(transaction)), - RuntimeCall::Starknet( consume_l1_message { transaction, .. }) => Some(Transaction::L1Handler(transaction)), - _ => None - }).collect::>() - } - fn get_index_and_tx_for_tx_hash(extrinsics: Vec<::Extrinsic>, chain_id: Felt252Wrapper, tx_hash: Felt252Wrapper) -> Option<(u32, Transaction)> { // Find our tx and it's index let (tx_index, tx) = extrinsics.into_iter().enumerate().find(|(_, xt)| {