diff --git a/Cargo.lock b/Cargo.lock index a116550c712..b4c2d05f6b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10714,6 +10714,7 @@ dependencies = [ "starknet-types-core", "starknet_api", "starknet_batcher_types", + "starknet_class_manager_types", "starknet_infra_utils", "starknet_l1_provider_types", "starknet_mempool_types", @@ -10939,6 +10940,7 @@ dependencies = [ "serde_json", "starknet-types-core", "starknet_api", + "starknet_class_manager_types", "starknet_gateway_types", "starknet_mempool", "starknet_mempool_types", @@ -11133,6 +11135,7 @@ dependencies = [ "rand_chacha 0.3.1", "serde", "starknet_api", + "starknet_class_manager_types", "starknet_gateway_types", "starknet_mempool_p2p_types", "starknet_sequencer_infra", diff --git a/crates/papyrus_test_utils/src/lib.rs b/crates/papyrus_test_utils/src/lib.rs index d6bea4c7fb1..ec2b36851f8 100644 --- a/crates/papyrus_test_utils/src/lib.rs +++ b/crates/papyrus_test_utils/src/lib.rs @@ -87,8 +87,12 @@ use starknet_api::deprecated_contract_class::{ use starknet_api::execution_resources::{Builtin, ExecutionResources, GasAmount, GasVector}; use starknet_api::hash::{PoseidonHash, StarkHash}; use starknet_api::rpc_transaction::{ + DeployAccountTransactionV3WithAddress, EntryPointByType as RpcEntryPointByType, EntryPointByType, + InternalRpcDeclareTransactionV3, + InternalRpcTransaction, + InternalRpcTransactionWithoutTxHash, RpcDeclareTransaction, RpcDeclareTransactionV3, RpcDeployAccountTransaction, @@ -749,6 +753,32 @@ auto_impl_get_test_instance! { pub max_amount: GasAmount, pub max_price_per_unit: GasPrice, } + pub struct InternalRpcTransaction { + pub tx: InternalRpcTransactionWithoutTxHash, + pub tx_hash: TransactionHash, + } + pub enum InternalRpcTransactionWithoutTxHash { + Declare(InternalRpcDeclareTransactionV3) = 0, + Invoke(RpcInvokeTransaction) = 1, + DeployAccount(DeployAccountTransactionV3WithAddress) = 2, + } + pub struct InternalRpcDeclareTransactionV3 { + pub sender_address: ContractAddress, + pub compiled_class_hash: CompiledClassHash, + pub signature: TransactionSignature, + pub nonce: Nonce, + pub class_hash: ClassHash, + pub resource_bounds: AllResourceBounds, + pub tip: Tip, + pub paymaster_data: PaymasterData, + pub account_deployment_data: AccountDeploymentData, + pub nonce_data_availability_mode: DataAvailabilityMode, + pub fee_data_availability_mode: DataAvailabilityMode, + } + pub struct DeployAccountTransactionV3WithAddress { + pub tx: RpcDeployAccountTransaction, + pub contract_address: ContractAddress, + } pub enum RpcTransaction { Declare(RpcDeclareTransaction) = 0, DeployAccount(RpcDeployAccountTransaction) = 1, diff --git a/crates/starknet_api/src/rpc_transaction.rs b/crates/starknet_api/src/rpc_transaction.rs index df3dd382726..71eb51ab5fa 100644 --- a/crates/starknet_api/src/rpc_transaction.rs +++ b/crates/starknet_api/src/rpc_transaction.rs @@ -124,6 +124,44 @@ impl From for Transaction { } } +macro_rules! implement_internal_getters_for_internal_rpc { + ($(($field_name:ident, $field_ty:ty)),* $(,)?) => { + $( + pub fn $field_name(&self) -> $field_ty { + match &self.tx { + InternalRpcTransactionWithoutTxHash::Declare(tx) => tx.$field_name.clone(), + InternalRpcTransactionWithoutTxHash::Invoke(RpcInvokeTransaction::V3(tx)) => tx.$field_name.clone(), + InternalRpcTransactionWithoutTxHash::DeployAccount(tx) => { + let RpcDeployAccountTransaction::V3(tx) = &tx.tx; + tx.$field_name.clone() + }, + } + } + )* + }; +} + +impl InternalRpcTransaction { + implement_internal_getters_for_internal_rpc!( + (nonce, Nonce), + (resource_bounds, AllResourceBounds), + (tip, Tip), + ); + + pub fn contract_address(&self) -> ContractAddress { + match &self.tx { + InternalRpcTransactionWithoutTxHash::Declare(tx) => tx.sender_address, + InternalRpcTransactionWithoutTxHash::Invoke(RpcInvokeTransaction::V3(tx)) => { + tx.sender_address + } + InternalRpcTransactionWithoutTxHash::DeployAccount(tx) => tx.contract_address, + } + } + + pub fn tx_hash(&self) -> TransactionHash { + self.tx_hash + } +} /// A RPC declare transaction. /// /// This transaction is equivalent to the component DECLARE_TXN in the diff --git a/crates/starknet_api/src/test_utils/invoke.rs b/crates/starknet_api/src/test_utils/invoke.rs index a9eefce639c..29d49885293 100644 --- a/crates/starknet_api/src/test_utils/invoke.rs +++ b/crates/starknet_api/src/test_utils/invoke.rs @@ -6,7 +6,13 @@ use crate::executable_transaction::{ AccountTransaction, InvokeTransaction as ExecutableInvokeTransaction, }; -use crate::rpc_transaction::{RpcInvokeTransaction, RpcInvokeTransactionV3, RpcTransaction}; +use crate::rpc_transaction::{ + InternalRpcTransaction, + InternalRpcTransactionWithoutTxHash, + RpcInvokeTransaction, + RpcInvokeTransactionV3, + RpcTransaction, +}; use crate::transaction::constants::EXECUTE_ENTRY_POINT_NAME; use crate::transaction::fields::{ AccountDeploymentData, @@ -149,3 +155,17 @@ pub fn rpc_invoke_tx(invoke_args: InvokeTxArgs) -> RpcTransaction { account_deployment_data: invoke_args.account_deployment_data, })) } + +pub fn internal_invoke_tx(invoke_args: InvokeTxArgs) -> InternalRpcTransaction { + if invoke_args.version != TransactionVersion::THREE { + panic!("Unsupported transaction version: {:?}.", invoke_args.version); + } + let tx_hash = invoke_args.tx_hash; + let RpcTransaction::Invoke(tx) = rpc_invoke_tx(invoke_args) else { + panic!("Expected RpcTransaction::Invoke"); + }; + + let invoke_tx = InternalRpcTransactionWithoutTxHash::Invoke(tx); + + InternalRpcTransaction { tx: invoke_tx, tx_hash } +} diff --git a/crates/starknet_batcher/Cargo.toml b/crates/starknet_batcher/Cargo.toml index 21d32223842..6e03503a41d 100644 --- a/crates/starknet_batcher/Cargo.toml +++ b/crates/starknet_batcher/Cargo.toml @@ -12,6 +12,7 @@ workspace = true async-trait.workspace = true blockifier.workspace = true chrono.workspace = true +futures.workspace = true indexmap.workspace = true papyrus_config.workspace = true papyrus_state_reader.workspace = true @@ -19,6 +20,7 @@ papyrus_storage.workspace = true serde.workspace = true starknet_api.workspace = true starknet_batcher_types.workspace = true +starknet_class_manager_types.workspace = true starknet_l1_provider_types.workspace = true starknet_mempool_types.workspace = true starknet_sequencer_infra.workspace = true diff --git a/crates/starknet_batcher/src/batcher.rs b/crates/starknet_batcher/src/batcher.rs index 4bd7c9edf59..7ed94faa914 100644 --- a/crates/starknet_batcher/src/batcher.rs +++ b/crates/starknet_batcher/src/batcher.rs @@ -31,6 +31,8 @@ use starknet_batcher_types::batcher_types::{ ValidateBlockInput, }; use starknet_batcher_types::errors::BatcherError; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::SharedClassManagerClient; use starknet_l1_provider_types::SharedL1ProviderClient; use starknet_mempool_types::communication::SharedMempoolClient; use starknet_mempool_types::mempool_types::CommitBlockArgs; @@ -74,6 +76,7 @@ pub struct Batcher { pub storage_writer: Box, pub l1_provider_client: SharedL1ProviderClient, pub mempool_client: SharedMempoolClient, + pub transaction_converter: TransactionConverter, // Used to create block builders. // Using the factory pattern to allow for easier testing. @@ -109,6 +112,7 @@ impl Batcher { storage_writer: Box, l1_provider_client: SharedL1ProviderClient, mempool_client: SharedMempoolClient, + transaction_converter: TransactionConverter, block_builder_factory: Box, ) -> Self { let storage_height = storage_reader @@ -121,6 +125,7 @@ impl Batcher { storage_writer, l1_provider_client, mempool_client, + transaction_converter, block_builder_factory, active_height: None, active_proposal: Arc::new(Mutex::new(None)), @@ -171,6 +176,7 @@ impl Batcher { let tx_provider = ProposeTransactionProvider::new( self.mempool_client.clone(), self.l1_provider_client.clone(), + self.transaction_converter.clone(), self.config.max_l1_handler_txs_per_block_proposal, propose_block_input.block_info.block_number, ); @@ -629,6 +635,7 @@ pub fn create_batcher( config: BatcherConfig, mempool_client: SharedMempoolClient, l1_provider_client: SharedL1ProviderClient, + class_manager_client: SharedClassManagerClient, ) -> Batcher { let (storage_reader, storage_writer) = papyrus_storage::open_storage(config.storage.clone()) .expect("Failed to open batcher's storage"); @@ -642,12 +649,16 @@ pub fn create_batcher( }); let storage_reader = Arc::new(storage_reader); let storage_writer = Box::new(storage_writer); + let transaction_converter = + TransactionConverter::new(class_manager_client, config.storage.db_config.chain_id.clone()); + Batcher::new( config, storage_reader, storage_writer, l1_provider_client, mempool_client, + transaction_converter, block_builder_factory, ) } diff --git a/crates/starknet_batcher/src/batcher_test.rs b/crates/starknet_batcher/src/batcher_test.rs index 033ce7bdec9..b68d453cdc6 100644 --- a/crates/starknet_batcher/src/batcher_test.rs +++ b/crates/starknet_batcher/src/batcher_test.rs @@ -8,7 +8,7 @@ use metrics_exporter_prometheus::PrometheusBuilder; use mockall::predicate::eq; use rstest::rstest; use starknet_api::block::{BlockHeaderWithoutHash, BlockInfo, BlockNumber}; -use starknet_api::core::{ContractAddress, Nonce}; +use starknet_api::core::{ChainId, ContractAddress, Nonce}; use starknet_api::executable_transaction::Transaction; use starknet_api::state::ThinStateDiff; use starknet_api::transaction::TransactionHash; @@ -31,6 +31,8 @@ use starknet_batcher_types::batcher_types::{ ValidateBlockInput, }; use starknet_batcher_types::errors::BatcherError; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::{EmptyClassManagerClient, SharedClassManagerClient}; use starknet_l1_provider_types::MockL1ProviderClient; use starknet_mempool_types::communication::MockMempoolClient; use starknet_mempool_types::mempool_types::CommitBlockArgs; @@ -93,6 +95,7 @@ struct MockDependencies { mempool_client: MockMempoolClient, l1_provider_client: MockL1ProviderClient, block_builder_factory: MockBlockBuilderFactoryTrait, + class_manager_client: SharedClassManagerClient, } impl Default for MockDependencies { @@ -105,6 +108,8 @@ impl Default for MockDependencies { l1_provider_client: MockL1ProviderClient::new(), mempool_client: MockMempoolClient::new(), block_builder_factory: MockBlockBuilderFactoryTrait::new(), + // TODO(noamsp): use MockClassManagerClient + class_manager_client: Arc::new(EmptyClassManagerClient), } } } @@ -116,6 +121,10 @@ fn create_batcher(mock_dependencies: MockDependencies) -> Batcher { Box::new(mock_dependencies.storage_writer), Arc::new(mock_dependencies.l1_provider_client), Arc::new(mock_dependencies.mempool_client), + TransactionConverter::new( + mock_dependencies.class_manager_client, + ChainId::create_for_testing(), + ), Box::new(mock_dependencies.block_builder_factory), ) } diff --git a/crates/starknet_batcher/src/transaction_provider.rs b/crates/starknet_batcher/src/transaction_provider.rs index 8bc1b924291..b9f95af18d4 100644 --- a/crates/starknet_batcher/src/transaction_provider.rs +++ b/crates/starknet_batcher/src/transaction_provider.rs @@ -2,11 +2,17 @@ use std::cmp::min; use std::vec; use async_trait::async_trait; +use futures::future::try_join_all; #[cfg(test)] use mockall::automock; use starknet_api::block::BlockNumber; use starknet_api::executable_transaction::Transaction; use starknet_api::transaction::TransactionHash; +use starknet_class_manager_types::transaction_converter::{ + TransactionConverter, + TransactionConverterError, + TransactionConverterTrait, +}; use starknet_l1_provider_types::errors::L1ProviderClientError; use starknet_l1_provider_types::{SharedL1ProviderClient, ValidationStatus as L1ValidationStatus}; use starknet_mempool_types::communication::{MempoolClientError, SharedMempoolClient}; @@ -22,6 +28,8 @@ pub enum TransactionProviderError { L1HandlerTransactionValidationFailed(TransactionHash), #[error(transparent)] L1ProviderError(#[from] L1ProviderClientError), + #[error(transparent)] + TransactionConverterError(#[from] TransactionConverterError), } #[derive(Debug, PartialEq)] @@ -40,6 +48,7 @@ pub trait TransactionProvider: Send { pub struct ProposeTransactionProvider { pub mempool_client: SharedMempoolClient, pub l1_provider_client: SharedL1ProviderClient, + pub transaction_converter: TransactionConverter, pub max_l1_handler_txs_per_block: usize, pub height: BlockNumber, phase: TxProviderPhase, @@ -57,12 +66,14 @@ impl ProposeTransactionProvider { pub fn new( mempool_client: SharedMempoolClient, l1_provider_client: SharedL1ProviderClient, + transaction_converter: TransactionConverter, max_l1_handler_txs_per_block: usize, height: BlockNumber, ) -> Self { Self { mempool_client, l1_provider_client, + transaction_converter, max_l1_handler_txs_per_block, height, phase: TxProviderPhase::L1, @@ -87,13 +98,17 @@ impl ProposeTransactionProvider { &mut self, n_txs: usize, ) -> TransactionProviderResult> { - Ok(self + let txs_futures = self .mempool_client .get_txs(n_txs) .await? .into_iter() - .map(Transaction::Account) - .collect()) + .map(|tx| self.transaction_converter.convert_internal_rpc_tx_to_executable_tx(tx)); + + let converted_txs = + try_join_all(txs_futures).await?.into_iter().map(Transaction::Account).collect(); + + Ok(converted_txs) } } diff --git a/crates/starknet_batcher/src/transaction_provider_test.rs b/crates/starknet_batcher/src/transaction_provider_test.rs index 396c3a18d33..abb965fb5b8 100644 --- a/crates/starknet_batcher/src/transaction_provider_test.rs +++ b/crates/starknet_batcher/src/transaction_provider_test.rs @@ -4,9 +4,12 @@ use assert_matches::assert_matches; use mockall::predicate::eq; use rstest::{fixture, rstest}; use starknet_api::block::BlockNumber; +use starknet_api::core::ChainId; use starknet_api::executable_transaction::{L1HandlerTransaction, Transaction}; -use starknet_api::test_utils::invoke::{executable_invoke_tx, InvokeTxArgs}; +use starknet_api::test_utils::invoke::{executable_invoke_tx, internal_invoke_tx, InvokeTxArgs}; use starknet_api::tx_hash; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::{EmptyClassManagerClient, SharedClassManagerClient}; use starknet_l1_provider_types::{MockL1ProviderClient, ValidationStatus as L1ValidationStatus}; use starknet_mempool_types::communication::MockMempoolClient; @@ -28,6 +31,7 @@ struct MockDependencies { l1_provider_client: MockL1ProviderClient, tx_sender: tokio::sync::mpsc::Sender, tx_receiver: tokio::sync::mpsc::Receiver, + class_manager_client: SharedClassManagerClient, } impl MockDependencies { @@ -40,7 +44,7 @@ impl MockDependencies { fn expect_get_mempool_txs(&mut self, n_to_request: usize) { self.mempool_client.expect_get_txs().with(eq(n_to_request)).returning(move |n_requested| { - Ok(vec![executable_invoke_tx(InvokeTxArgs::default()); n_requested]) + Ok(vec![internal_invoke_tx(InvokeTxArgs::default()); n_requested]) }); } @@ -61,6 +65,7 @@ impl MockDependencies { ProposeTransactionProvider::new( Arc::new(self.mempool_client), Arc::new(self.l1_provider_client), + TransactionConverter::new(self.class_manager_client, ChainId::create_for_testing()), MAX_L1_HANDLER_TXS_PER_BLOCK, HEIGHT, ) @@ -85,6 +90,8 @@ fn mock_dependencies( l1_provider_client: MockL1ProviderClient::new(), tx_sender, tx_receiver, + // TODO(noamsp): use MockClassManagerClient + class_manager_client: Arc::new(EmptyClassManagerClient), } } diff --git a/crates/starknet_class_manager_types/src/transaction_converter.rs b/crates/starknet_class_manager_types/src/transaction_converter.rs index 211a097e6d6..544286d482d 100644 --- a/crates/starknet_class_manager_types/src/transaction_converter.rs +++ b/crates/starknet_class_manager_types/src/transaction_converter.rs @@ -60,6 +60,7 @@ pub trait TransactionConverterTrait { ) -> TransactionConverterResult; } +#[derive(Clone)] pub struct TransactionConverter { class_manager_client: SharedClassManagerClient, chain_id: ChainId, diff --git a/crates/starknet_gateway/Cargo.toml b/crates/starknet_gateway/Cargo.toml index 26e9f6e4a88..c043caf159a 100644 --- a/crates/starknet_gateway/Cargo.toml +++ b/crates/starknet_gateway/Cargo.toml @@ -26,6 +26,7 @@ serde.workspace = true serde_json.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true +starknet_class_manager_types.workspace = true starknet_gateway_types.workspace = true starknet_mempool_types.workspace = true starknet_sequencer_infra.workspace = true diff --git a/crates/starknet_gateway/bench/utils.rs b/crates/starknet_gateway/bench/utils.rs index 5e3d0c56a60..81fb8bb0f51 100644 --- a/crates/starknet_gateway/bench/utils.rs +++ b/crates/starknet_gateway/bench/utils.rs @@ -9,12 +9,12 @@ use starknet_api::invoke_tx_args; use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::test_utils::invoke::rpc_invoke_tx; use starknet_api::test_utils::NonceManager; -use starknet_gateway::compilation::GatewayCompiler; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::EmptyClassManagerClient; use starknet_gateway::config::GatewayConfig; use starknet_gateway::gateway::Gateway; use starknet_gateway::state_reader_test_utils::local_test_state_reader_factory; use starknet_mempool_types::communication::MockMempoolClient; -use starknet_sierra_multicompile::config::SierraCompilationConfig; const N_TXS: usize = 100; @@ -48,7 +48,6 @@ impl TransactionGenerator { pub struct BenchTestSetupConfig { pub n_txs: usize, pub gateway_config: GatewayConfig, - pub compiler_config: SierraCompilationConfig, } impl Default for BenchTestSetupConfig { @@ -59,7 +58,6 @@ impl Default for BenchTestSetupConfig { chain_info: ChainInfo::create_for_testing(), ..Default::default() }, - compiler_config: SierraCompilationConfig::default(), } } } @@ -82,16 +80,20 @@ impl BenchTestSetup { } let state_reader_factory = local_test_state_reader_factory(cairo_version, false); - let gateway_compiler = - GatewayCompiler::new_command_line_compiler(config.compiler_config.clone()); let mut mempool_client = MockMempoolClient::new(); + // TODO(noamsp): use MockTransactionConverter + let class_manager_client = Arc::new(EmptyClassManagerClient); + let transaction_converter = TransactionConverter::new( + class_manager_client.clone(), + config.gateway_config.chain_info.chain_id.clone(), + ); mempool_client.expect_add_tx().returning(|_| Ok(())); let gateway_business_logic = Gateway::new( config.gateway_config, Arc::new(state_reader_factory), - gateway_compiler, Arc::new(mempool_client), + transaction_converter, ); Self { gateway: gateway_business_logic, txs } diff --git a/crates/starknet_gateway/src/compilation.rs b/crates/starknet_gateway/src/compilation.rs deleted file mode 100644 index 71d5da58a06..00000000000 --- a/crates/starknet_gateway/src/compilation.rs +++ /dev/null @@ -1,75 +0,0 @@ -use std::sync::Arc; - -use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; -use cairo_lang_starknet_classes::contract_class::ContractClass as CairoLangContractClass; -use starknet_api::contract_class::{ClassInfo, ContractClass, SierraVersion}; -use starknet_api::rpc_transaction::RpcDeclareTransaction; -use starknet_gateway_types::errors::GatewaySpecError; -use starknet_sierra_multicompile::command_line_compiler::CommandLineCompiler; -use starknet_sierra_multicompile::config::SierraCompilationConfig; -use starknet_sierra_multicompile::utils::into_contract_class_for_compilation; -use starknet_sierra_multicompile::SierraToCasmCompiler; -use tracing::{debug, error}; - -use crate::errors::GatewayResult; - -#[cfg(test)] -#[path = "compilation_test.rs"] -mod compilation_test; - -// TODO(Arni): Pass the compiler with dependancy injection. -#[derive(Clone)] -pub struct GatewayCompiler { - pub sierra_to_casm_compiler: Arc, -} - -impl GatewayCompiler { - pub fn new_command_line_compiler(config: SierraCompilationConfig) -> Self { - Self { sierra_to_casm_compiler: Arc::new(CommandLineCompiler::new(config)) } - } - - /// Formats the contract class for compilation, compiles it, and returns the compiled contract - /// class wrapped in a [`ClassInfo`]. - /// Assumes the contract class is of a Sierra program which is compiled to Casm. - pub(crate) fn process_declare_tx( - &self, - declare_tx: &RpcDeclareTransaction, - ) -> GatewayResult { - let RpcDeclareTransaction::V3(tx) = declare_tx; - let rpc_contract_class = &tx.contract_class; - let cairo_lang_contract_class = into_contract_class_for_compilation(rpc_contract_class); - - let sierra_version = - SierraVersion::extract_from_program(&rpc_contract_class.sierra_program) - .map_err(|e| GatewaySpecError::UnexpectedError { data: (e.to_string()) })?; - - let casm_contract_class = - (self.compile(cairo_lang_contract_class)?, sierra_version.clone()); - - Ok(ClassInfo { - contract_class: ContractClass::V1(casm_contract_class), - sierra_program_length: rpc_contract_class.sierra_program.len(), - abi_length: rpc_contract_class.abi.len(), - sierra_version, - }) - } - - fn compile( - &self, - cairo_lang_contract_class: CairoLangContractClass, - ) -> GatewayResult { - match self.sierra_to_casm_compiler.compile(cairo_lang_contract_class) { - Ok(casm_contract_class) => Ok(casm_contract_class), - Err(starknet_sierra_multicompile::errors::CompilationUtilError::UnexpectedError( - error, - )) => { - error!("Compilation panicked. Error: {:?}", error); - Err(GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() }) - } - Err(e) => { - debug!("Compilation failed: {:?}", e); - Err(GatewaySpecError::CompilationFailed) - } - } - } -} diff --git a/crates/starknet_gateway/src/compilation_test.rs b/crates/starknet_gateway/src/compilation_test.rs deleted file mode 100644 index d6f0b157ed6..00000000000 --- a/crates/starknet_gateway/src/compilation_test.rs +++ /dev/null @@ -1,86 +0,0 @@ -use assert_matches::assert_matches; -use mempool_test_utils::starknet_api_test_utils::{ - declare_tx as rpc_declare_tx, - COMPILED_CLASS_HASH, -}; -use rstest::{fixture, rstest}; -use starknet_api::rpc_transaction::{ - RpcDeclareTransaction, - RpcDeclareTransactionV3, - RpcTransaction, -}; -use starknet_gateway_types::errors::GatewaySpecError; -use starknet_sierra_multicompile::config::SierraCompilationConfig; -use starknet_sierra_multicompile::errors::CompilationUtilError; -use tracing_test::traced_test; - -use crate::compilation::GatewayCompiler; - -#[fixture] -fn gateway_compiler() -> GatewayCompiler { - GatewayCompiler::new_command_line_compiler(SierraCompilationConfig::default()) -} - -#[fixture] -fn declare_tx_v3() -> RpcDeclareTransactionV3 { - assert_matches!( - rpc_declare_tx(), - RpcTransaction::Declare(RpcDeclareTransaction::V3(declare_tx)) => declare_tx - ) -} - -// TODO(Arni): Redesign this test once the compiler is passed with dependancy injection. -#[traced_test] -#[rstest] -fn test_compile_contract_class_bytecode_size_validation(declare_tx_v3: RpcDeclareTransactionV3) { - let gateway_compiler = GatewayCompiler::new_command_line_compiler(SierraCompilationConfig { - max_casm_bytecode_size: 1, - ..SierraCompilationConfig::default() - }); - - let result = gateway_compiler.process_declare_tx(&RpcDeclareTransaction::V3(declare_tx_v3)); - assert_matches!(result.unwrap_err(), GatewaySpecError::CompilationFailed); - let expected_compilation_error = CompilationUtilError::CompilationError( - "Exit status: exit status: 1\n Stderr: Error: Compilation failed.\n\nCaused by:\n Code \ - size limit exceeded.\n" - .to_owned(), - ); - assert!(logs_contain(format!("Compilation failed: {:?}", expected_compilation_error).as_str())); -} - -#[traced_test] -#[rstest] -fn test_compile_contract_class_bad_sierra( - gateway_compiler: GatewayCompiler, - mut declare_tx_v3: RpcDeclareTransactionV3, -) { - // Truncate the sierra program to trigger an error. - declare_tx_v3.contract_class.sierra_program = - declare_tx_v3.contract_class.sierra_program[..100].to_vec(); - let declare_tx = RpcDeclareTransaction::V3(declare_tx_v3); - - let err = gateway_compiler.process_declare_tx(&declare_tx).unwrap_err(); - assert_eq!(err, GatewaySpecError::CompilationFailed); - - let expected_compilation_error = CompilationUtilError::CompilationError( - "Exit status: exit status: 1\n Stderr: Error: Invalid Sierra program.\n".to_owned(), - ); - assert!(logs_contain(format!("Compilation failed: {:?}", expected_compilation_error).as_str())); -} - -#[rstest] -fn test_process_declare_tx_success( - gateway_compiler: GatewayCompiler, - declare_tx_v3: RpcDeclareTransactionV3, -) { - let contract_class = &declare_tx_v3.contract_class; - let sierra_program_length = contract_class.sierra_program.len(); - let abi_length = contract_class.abi.len(); - let declare_tx = RpcDeclareTransaction::V3(declare_tx_v3); - - let class_info = gateway_compiler.process_declare_tx(&declare_tx).unwrap(); - let compiled_class_hash = class_info.contract_class.compiled_class_hash(); - assert_eq!(compiled_class_hash, *COMPILED_CLASS_HASH); - assert_eq!(class_info.sierra_program_length, sierra_program_length); - assert_eq!(class_info.abi_length, abi_length); -} diff --git a/crates/starknet_gateway/src/gateway.rs b/crates/starknet_gateway/src/gateway.rs index 5cc61521ae9..6c2c58baa00 100644 --- a/crates/starknet_gateway/src/gateway.rs +++ b/crates/starknet_gateway/src/gateway.rs @@ -2,26 +2,29 @@ use std::clone::Clone; use std::sync::Arc; use blockifier::context::ChainInfo; +use futures::executor::block_on; use papyrus_network_types::network_types::BroadcastedMessageMetadata; use starknet_api::executable_transaction::AccountTransaction; use starknet_api::rpc_transaction::RpcTransaction; use starknet_api::transaction::TransactionHash; +use starknet_class_manager_types::transaction_converter::{ + TransactionConverter, + TransactionConverterTrait, +}; +use starknet_class_manager_types::SharedClassManagerClient; use starknet_gateway_types::errors::GatewaySpecError; use starknet_mempool_types::communication::{AddTransactionArgsWrapper, SharedMempoolClient}; use starknet_mempool_types::mempool_types::{AccountState, AddTransactionArgs}; use starknet_sequencer_infra::component_definitions::ComponentStarter; -use starknet_sierra_multicompile::config::SierraCompilationConfig; use starknet_state_sync_types::communication::SharedStateSyncClient; use tracing::{debug, error, instrument, Span}; -use crate::compilation::GatewayCompiler; use crate::config::GatewayConfig; use crate::errors::{mempool_client_result_to_gw_spec_result, GatewayResult}; use crate::state_reader::StateReaderFactory; use crate::stateful_transaction_validator::StatefulTransactionValidator; use crate::stateless_transaction_validator::StatelessTransactionValidator; use crate::sync_state_reader::SyncStateReaderFactory; -use crate::utils::compile_contract_and_build_executable_tx; #[cfg(test)] #[path = "gateway_test.rs"] @@ -32,8 +35,8 @@ pub struct Gateway { pub stateless_tx_validator: Arc, pub stateful_tx_validator: Arc, pub state_reader_factory: Arc, - pub gateway_compiler: Arc, pub mempool_client: SharedMempoolClient, + pub transaction_converter: TransactionConverter, pub chain_info: ChainInfo, } @@ -41,8 +44,8 @@ impl Gateway { pub fn new( config: GatewayConfig, state_reader_factory: Arc, - gateway_compiler: GatewayCompiler, mempool_client: SharedMempoolClient, + transaction_converter: TransactionConverter, ) -> Self { Self { config: config.clone(), @@ -53,9 +56,9 @@ impl Gateway { config: config.stateful_tx_validator_config.clone(), }), state_reader_factory, - gateway_compiler: Arc::new(gateway_compiler), mempool_client, chain_info: config.chain_info.clone(), + transaction_converter, } } @@ -92,10 +95,10 @@ struct ProcessTxBlockingTask { stateless_tx_validator: Arc, stateful_tx_validator: Arc, state_reader_factory: Arc, - gateway_compiler: Arc, mempool_client: SharedMempoolClient, chain_info: ChainInfo, tx: RpcTransaction, + transaction_converter: TransactionConverter, } impl ProcessTxBlockingTask { @@ -104,10 +107,10 @@ impl ProcessTxBlockingTask { stateless_tx_validator: gateway.stateless_tx_validator.clone(), stateful_tx_validator: gateway.stateful_tx_validator.clone(), state_reader_factory: gateway.state_reader_factory.clone(), - gateway_compiler: gateway.gateway_compiler.clone(), mempool_client: gateway.mempool_client.clone(), chain_info: gateway.chain_info.clone(), tx, + transaction_converter: gateway.transaction_converter.clone(), } } @@ -117,11 +120,21 @@ impl ProcessTxBlockingTask { // Perform stateless validations. self.stateless_tx_validator.validate(&self.tx)?; - let executable_tx = compile_contract_and_build_executable_tx( - self.tx, - self.gateway_compiler.as_ref(), - &self.chain_info.chain_id, - )?; + let internal_tx = + block_on(self.transaction_converter.convert_rpc_tx_to_internal_rpc_tx(self.tx)) + .map_err(|err| { + error!( + "Failed to convert internal RPC transaction to executable transaction: {}", + err + ); + GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() } + })?; + + let executable_tx = block_on( + self.transaction_converter + .convert_internal_rpc_tx_to_executable_tx(internal_tx.clone()), + ) + .unwrap(); // Perform post compilation validations. if let AccountTransaction::Declare(executable_declare_tx) = &executable_tx { @@ -147,20 +160,22 @@ impl ProcessTxBlockingTask { )?; // TODO(Arni): Add the Sierra and the Casm to the mempool input. - Ok(AddTransactionArgs { tx: executable_tx, account_state: AccountState { address, nonce } }) + Ok(AddTransactionArgs { tx: internal_tx, account_state: AccountState { address, nonce } }) } } pub fn create_gateway( config: GatewayConfig, shared_state_sync_client: SharedStateSyncClient, - compiler_config: SierraCompilationConfig, mempool_client: SharedMempoolClient, + class_manager_client: SharedClassManagerClient, ) -> Gateway { let state_reader_factory = Arc::new(SyncStateReaderFactory { shared_state_sync_client }); - let gateway_compiler = GatewayCompiler::new_command_line_compiler(compiler_config); - Gateway::new(config, state_reader_factory, gateway_compiler, mempool_client) + let transaction_converter = + TransactionConverter::new(class_manager_client, config.chain_info.chain_id.clone()); + + Gateway::new(config, state_reader_factory, mempool_client, transaction_converter) } impl ComponentStarter for Gateway {} diff --git a/crates/starknet_gateway/src/gateway_test.rs b/crates/starknet_gateway/src/gateway_test.rs index d7ea33f6d69..18a52ddaec8 100644 --- a/crates/starknet_gateway/src/gateway_test.rs +++ b/crates/starknet_gateway/src/gateway_test.rs @@ -9,9 +9,15 @@ use papyrus_network_types::network_types::BroadcastedMessageMetadata; use papyrus_test_utils::{get_rng, GetTestInstance}; use rstest::{fixture, rstest}; use starknet_api::core::{ChainId, CompiledClassHash, ContractAddress, Nonce}; -use starknet_api::executable_transaction::{AccountTransaction, InvokeTransaction}; -use starknet_api::rpc_transaction::{RpcDeclareTransaction, RpcTransaction}; -use starknet_api::transaction::TransactionHash; +use starknet_api::rpc_transaction::{ + InternalRpcTransaction, + InternalRpcTransactionWithoutTxHash, + RpcDeclareTransaction, + RpcTransaction, +}; +use starknet_api::transaction::{InvokeTransaction, TransactionHash, TransactionVersion}; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::{EmptyClassManagerClient, SharedClassManagerClient}; use starknet_gateway_types::errors::GatewaySpecError; use starknet_mempool_types::communication::{ AddTransactionArgsWrapper, @@ -21,9 +27,7 @@ use starknet_mempool_types::communication::{ }; use starknet_mempool_types::errors::MempoolError; use starknet_mempool_types::mempool_types::{AccountState, AddTransactionArgs}; -use starknet_sierra_multicompile::config::SierraCompilationConfig; -use crate::compilation::GatewayCompiler; use crate::config::{ GatewayConfig, StatefulTransactionValidatorConfig, @@ -41,11 +45,6 @@ fn config() -> GatewayConfig { } } -#[fixture] -fn compiler() -> GatewayCompiler { - GatewayCompiler::new_command_line_compiler(SierraCompilationConfig::default()) -} - #[fixture] fn state_reader_factory() -> TestStateReaderFactory { local_test_state_reader_factory(CairoVersion::Cairo1(RunnableCairo1::Casm), false) @@ -54,27 +53,28 @@ fn state_reader_factory() -> TestStateReaderFactory { #[fixture] fn mock_dependencies( config: GatewayConfig, - compiler: GatewayCompiler, state_reader_factory: TestStateReaderFactory, ) -> MockDependencies { let mock_mempool_client = MockMempoolClient::new(); - MockDependencies { config, compiler, state_reader_factory, mock_mempool_client } + // TODO(noamsp): use MockTransactionConverter + let class_manager_client = Arc::new(EmptyClassManagerClient); + MockDependencies { config, state_reader_factory, mock_mempool_client, class_manager_client } } struct MockDependencies { config: GatewayConfig, - compiler: GatewayCompiler, state_reader_factory: TestStateReaderFactory, mock_mempool_client: MockMempoolClient, + class_manager_client: SharedClassManagerClient, } impl MockDependencies { fn gateway(self) -> Gateway { Gateway::new( - self.config, + self.config.clone(), Arc::new(self.state_reader_factory), - self.compiler, Arc::new(self.mock_mempool_client), + TransactionConverter::new(self.class_manager_client, self.config.chain_info.chain_id), ) } @@ -123,18 +123,28 @@ async fn test_add_tx( #[case] expected_result: Result<(), MempoolClientError>, #[case] expected_error: Option, ) { + use starknet_api::transaction::TransactionHasher; + let (rpc_tx, address) = create_tx(); let rpc_invoke_tx = assert_matches!(rpc_tx.clone(), RpcTransaction::Invoke(rpc_invoke_tx) => rpc_invoke_tx); - let executable_tx = AccountTransaction::Invoke( - InvokeTransaction::from_rpc_tx(rpc_invoke_tx, &ChainId::create_for_testing()).unwrap(), - ); - let tx_hash = executable_tx.tx_hash(); + let InvokeTransaction::V3(invoke_tx): InvokeTransaction = rpc_invoke_tx.clone().into() else { + panic!("Unexpected transaction version") + }; + + let tx_hash = invoke_tx + .calculate_transaction_hash(&ChainId::create_for_testing(), &TransactionVersion::THREE) + .unwrap(); + + let internal_invoke_tx = InternalRpcTransaction { + tx: InternalRpcTransactionWithoutTxHash::Invoke(rpc_invoke_tx.clone()), + tx_hash, + }; let p2p_message_metadata = Some(BroadcastedMessageMetadata::get_test_instance(&mut get_rng())); let add_tx_args = AddTransactionArgs { - tx: executable_tx, + tx: internal_invoke_tx, account_state: AccountState { address, nonce: *rpc_tx.nonce() }, }; mock_dependencies.expect_add_tx( diff --git a/crates/starknet_gateway/src/lib.rs b/crates/starknet_gateway/src/lib.rs index 704ca65a9cf..b9fcc42eac9 100644 --- a/crates/starknet_gateway/src/lib.rs +++ b/crates/starknet_gateway/src/lib.rs @@ -1,5 +1,4 @@ pub mod communication; -pub mod compilation; mod compiler_version; pub mod config; pub mod errors; @@ -18,4 +17,3 @@ mod sync_state_reader; mod sync_state_reader_test; #[cfg(test)] mod test_utils; -mod utils; diff --git a/crates/starknet_gateway/src/utils.rs b/crates/starknet_gateway/src/utils.rs deleted file mode 100644 index bf51b14bf3f..00000000000 --- a/crates/starknet_gateway/src/utils.rs +++ /dev/null @@ -1,79 +0,0 @@ -use starknet_api::core::ChainId; -use starknet_api::executable_transaction::{ - AccountTransaction as ExecutableTransaction, - DeclareTransaction as ExecutableDeclareTransaction, - DeployAccountTransaction as ExecutableDeployAccountTransaction, - InvokeTransaction as ExecutableInvokeTransaction, -}; -use starknet_api::rpc_transaction::{RpcDeclareTransaction, RpcTransaction}; -use starknet_gateway_types::errors::GatewaySpecError; -use tracing::{debug, error}; - -use crate::compilation::GatewayCompiler; -use crate::errors::GatewayResult; - -/// Converts an RPC transaction to an executable transaction. -/// Note, for declare transaction this step is heavy, as it requires compilation of Sierra to -/// executable contract class. -pub fn compile_contract_and_build_executable_tx( - rpc_tx: RpcTransaction, - gateway_compiler: &GatewayCompiler, - chain_id: &ChainId, -) -> GatewayResult { - Ok(match rpc_tx { - RpcTransaction::Declare(rpc_declare_tx) => { - let executable_declare_tx = compile_contract_and_build_executable_declare_tx( - rpc_declare_tx, - gateway_compiler, - chain_id, - )?; - ExecutableTransaction::Declare(executable_declare_tx) - } - RpcTransaction::DeployAccount(rpc_deploy_account_tx) => { - let executable_deploy_account_tx = - ExecutableDeployAccountTransaction::from_rpc_tx(rpc_deploy_account_tx, chain_id) - .map_err(|error| { - error!( - "Failed to convert RPC deploy account transaction to executable \ - transaction: {}", - error - ); - GatewaySpecError::UnexpectedError { - data: "Internal server error".to_owned(), - } - })?; - ExecutableTransaction::DeployAccount(executable_deploy_account_tx) - } - RpcTransaction::Invoke(rpc_invoke_tx) => { - let executable_invoke_tx = ExecutableInvokeTransaction::from_rpc_tx( - rpc_invoke_tx, - chain_id, - ) - .map_err(|error| { - error!( - "Failed to convert RPC invoke transaction to executable transaction: {}", - error - ); - GatewaySpecError::UnexpectedError { data: "Internal server error".to_owned() } - })?; - ExecutableTransaction::Invoke(executable_invoke_tx) - } - }) -} - -fn compile_contract_and_build_executable_declare_tx( - rpc_tx: RpcDeclareTransaction, - gateway_compiler: &GatewayCompiler, - chain_id: &ChainId, -) -> GatewayResult { - let class_info = gateway_compiler.process_declare_tx(&rpc_tx)?; - // TODO(Arni): Convert to internal tx and use the class manager to create the executable tx. - let declare_tx: starknet_api::transaction::DeclareTransaction = rpc_tx.into(); - let executable_declare_tx = - ExecutableDeclareTransaction::create(declare_tx, class_info, chain_id).map_err(|err| { - debug!("Failed to create executable declare transaction {:?}", err); - GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() } - })?; - - Ok(executable_declare_tx) -} diff --git a/crates/starknet_mempool/src/communication.rs b/crates/starknet_mempool/src/communication.rs index 3b2cca41e85..d66ac604136 100644 --- a/crates/starknet_mempool/src/communication.rs +++ b/crates/starknet_mempool/src/communication.rs @@ -1,12 +1,7 @@ use async_trait::async_trait; use papyrus_network_types::network_types::BroadcastedMessageMetadata; use starknet_api::core::ContractAddress; -use starknet_api::executable_transaction::AccountTransaction; -use starknet_api::rpc_transaction::{ - RpcDeployAccountTransaction, - RpcInvokeTransaction, - RpcTransaction, -}; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_mempool_p2p_types::communication::SharedMempoolP2pPropagatorClient; use starknet_mempool_types::communication::{ AddTransactionArgsWrapper, @@ -47,33 +42,20 @@ impl MempoolCommunicationWrapper { async fn send_tx_to_p2p( &self, message_metadata: Option, - tx: AccountTransaction, + tx: InternalRpcTransaction, ) -> MempoolResult<()> { match message_metadata { Some(message_metadata) => self .mempool_p2p_propagator_client .continue_propagation(message_metadata) .await - .map_err(|_| MempoolError::P2pPropagatorClientError { tx_hash: tx.tx_hash() }), + .map_err(|_| MempoolError::P2pPropagatorClientError { tx_hash: tx.tx_hash }), None => { - let tx_hash = tx.tx_hash(); - match tx { - AccountTransaction::Invoke(invoke_tx) => self - .mempool_p2p_propagator_client - .add_transaction(RpcTransaction::Invoke(RpcInvokeTransaction::V3( - invoke_tx.into(), - ))) - .await - .map_err(|_| MempoolError::P2pPropagatorClientError { tx_hash })?, - AccountTransaction::DeployAccount(deploy_account_tx) => self - .mempool_p2p_propagator_client - .add_transaction(RpcTransaction::DeployAccount( - RpcDeployAccountTransaction::V3(deploy_account_tx.into()), - )) - .await - .map_err(|_| MempoolError::P2pPropagatorClientError { tx_hash })?, - AccountTransaction::Declare(_) => {} - } + let tx_hash = tx.tx_hash; + self.mempool_p2p_propagator_client + .add_transaction(tx) + .await + .map_err(|_| MempoolError::P2pPropagatorClientError { tx_hash })?; Ok(()) } } @@ -85,18 +67,14 @@ impl MempoolCommunicationWrapper { ) -> MempoolResult<()> { self.mempool.add_tx(args_wrapper.args.clone())?; // TODO(AlonH): Verify that only transactions that were added to the mempool are sent. - // TODO(AlonH): handle declare correctly and remove this match. - match args_wrapper.args.tx { - AccountTransaction::Declare(_) => Ok(()), - _ => self.send_tx_to_p2p(args_wrapper.p2p_message_metadata, args_wrapper.args.tx).await, - } + self.send_tx_to_p2p(args_wrapper.p2p_message_metadata, args_wrapper.args.tx).await } fn commit_block(&mut self, args: CommitBlockArgs) -> MempoolResult<()> { self.mempool.commit_block(args) } - fn get_txs(&mut self, n_txs: usize) -> MempoolResult> { + fn get_txs(&mut self, n_txs: usize) -> MempoolResult> { self.mempool.get_txs(n_txs) } diff --git a/crates/starknet_mempool/src/mempool.rs b/crates/starknet_mempool/src/mempool.rs index e62d3cf195b..3ec860189ca 100644 --- a/crates/starknet_mempool/src/mempool.rs +++ b/crates/starknet_mempool/src/mempool.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use starknet_api::block::GasPrice; use starknet_api::core::{ContractAddress, Nonce}; -use starknet_api::executable_transaction::AccountTransaction; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_api::transaction::fields::Tip; use starknet_api::transaction::TransactionHash; use starknet_mempool_types::errors::MempoolError; @@ -156,7 +156,7 @@ impl Mempool { /// created. // TODO(AlonH): Consider renaming to `pop_txs` to be more consistent with the standard library. #[instrument(skip(self), err)] - pub fn get_txs(&mut self, n_txs: usize) -> MempoolResult> { + pub fn get_txs(&mut self, n_txs: usize) -> MempoolResult> { let mut eligible_tx_references: Vec = Vec::with_capacity(n_txs); let mut n_remaining_txs = n_txs; @@ -193,9 +193,9 @@ impl Mempool { skip(self, args), fields( // Log subset of (informative) fields. tx_nonce = %args.tx.nonce(), - tx_hash = %args.tx.tx_hash(), - tx_tip = %tip(&args.tx), - tx_max_l2_gas_price = %max_l2_gas_price(&args.tx), + tx_hash = %args.tx.tx_hash, + tx_tip = %args.tx.tip(), + tx_max_l2_gas_price = %args.tx.resource_bounds().l2_gas.max_price_per_unit, account_state = %args.account_state ), err @@ -318,7 +318,7 @@ impl Mempool { } #[instrument(level = "debug", skip(self, incoming_tx), err)] - fn handle_fee_escalation(&mut self, incoming_tx: &AccountTransaction) -> MempoolResult<()> { + fn handle_fee_escalation(&mut self, incoming_tx: &InternalRpcTransaction) -> MempoolResult<()> { let incoming_tx_reference = TransactionReference::new(incoming_tx); let TransactionReference { address, nonce, .. } = incoming_tx_reference; @@ -385,15 +385,6 @@ impl Mempool { } } -// TODO(Elin): move to a shared location with other next-gen node crates. -fn tip(tx: &AccountTransaction) -> Tip { - tx.tip() -} - -fn max_l2_gas_price(tx: &AccountTransaction) -> GasPrice { - tx.resource_bounds().get_l2_bounds().max_price_per_unit -} - /// Provides a lightweight representation of a transaction for mempool usage (e.g., excluding /// execution fields). /// TODO(Mohammad): rename this struct to `ThinTransaction` once that name @@ -408,13 +399,13 @@ pub struct TransactionReference { } impl TransactionReference { - pub fn new(tx: &AccountTransaction) -> Self { + pub fn new(tx: &InternalRpcTransaction) -> Self { TransactionReference { address: tx.contract_address(), nonce: tx.nonce(), tx_hash: tx.tx_hash(), - tip: tip(tx), - max_l2_gas_price: max_l2_gas_price(tx), + tip: tx.tip(), + max_l2_gas_price: tx.resource_bounds().l2_gas.max_price_per_unit, } } } diff --git a/crates/starknet_mempool/src/mempool_test.rs b/crates/starknet_mempool/src/mempool_test.rs index dcc9d8dfd48..0bf3d509fc6 100644 --- a/crates/starknet_mempool/src/mempool_test.rs +++ b/crates/starknet_mempool/src/mempool_test.rs @@ -7,12 +7,7 @@ use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; use starknet_api::block::GasPrice; use starknet_api::core::ContractAddress; -use starknet_api::executable_transaction::AccountTransaction; -use starknet_api::rpc_transaction::{ - RpcDeployAccountTransaction, - RpcInvokeTransaction, - RpcTransaction, -}; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_api::{contract_address, nonce}; use starknet_mempool_p2p_types::communication::MockMempoolP2pPropagatorClient; use starknet_mempool_types::communication::AddTransactionArgsWrapper; @@ -88,7 +83,7 @@ impl MempoolContentBuilder { fn with_pool

(mut self, pool_txs: P) -> Self where - P: IntoIterator, + P: IntoIterator, { self.tx_pool = Some(pool_txs.into_iter().collect()); self @@ -140,8 +135,8 @@ impl MempoolContentBuilder { } } -impl FromIterator for TransactionPool { - fn from_iter>(txs: T) -> Self { +impl FromIterator for TransactionPool { + fn from_iter>(txs: T) -> Self { let mut pool = Self::default(); for tx in txs { pool.insert(tx).unwrap(); @@ -154,7 +149,7 @@ impl FromIterator for TransactionPool { fn builder_with_queue( in_priority_queue: bool, in_pending_queue: bool, - tx: &AccountTransaction, + tx: &InternalRpcTransaction, ) -> MempoolContentBuilder { assert!( !(in_priority_queue && in_pending_queue), @@ -209,7 +204,7 @@ fn add_tx_and_verify_replacement_in_pool( #[track_caller] fn add_txs_and_verify_no_replacement( mut mempool: Mempool, - existing_tx: AccountTransaction, + existing_tx: InternalRpcTransaction, invalid_replacement_inputs: impl IntoIterator, in_priority_queue: bool, in_pending_queue: bool, @@ -235,7 +230,7 @@ fn add_txs_and_verify_no_replacement( #[track_caller] fn add_txs_and_verify_no_replacement_in_pool( mempool: Mempool, - existing_tx: AccountTransaction, + existing_tx: InternalRpcTransaction, invalid_replacement_inputs: impl IntoIterator, ) { let in_priority_queue = false; @@ -811,26 +806,11 @@ async fn test_new_tx_sent_to_p2p(mempool: Mempool) { let tx_args = add_tx_input!(tx_hash: 1, address: "0x0", tx_nonce: 2, account_nonce: 2); let propagateor_args = AddTransactionArgsWrapper { args: tx_args.clone(), p2p_message_metadata: None }; - // TODO(AlonH): use regular conversion once we have a compiler component - let rpc_tx = match tx_args.tx { - AccountTransaction::Declare(_declare_tx) => { - panic!("No implementation for converting DeclareTransaction to an RpcTransaction") - } - AccountTransaction::DeployAccount(deploy_account_transaction) => { - RpcTransaction::DeployAccount(RpcDeployAccountTransaction::V3( - deploy_account_transaction.clone().into(), - )) - } - AccountTransaction::Invoke(invoke_transaction) => { - RpcTransaction::Invoke(RpcInvokeTransaction::V3(invoke_transaction.clone().into())) - } - }; - let mut mock_mempool_p2p_propagator_client = MockMempoolP2pPropagatorClient::new(); mock_mempool_p2p_propagator_client .expect_add_transaction() .times(1) - .with(predicate::eq(rpc_tx)) + .with(predicate::eq(tx_args.tx)) .returning(|_| Ok(())); let mut mempool_wrapper = MempoolCommunicationWrapper::new(mempool, Arc::new(mock_mempool_p2p_propagator_client)); diff --git a/crates/starknet_mempool/src/test_utils.rs b/crates/starknet_mempool/src/test_utils.rs index 221c198ed22..89e2f945a2c 100644 --- a/crates/starknet_mempool/src/test_utils.rs +++ b/crates/starknet_mempool/src/test_utils.rs @@ -1,7 +1,7 @@ use std::collections::{HashMap, HashSet}; use pretty_assertions::assert_eq; -use starknet_api::executable_transaction::AccountTransaction; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_api::{contract_address, nonce, tx_hash}; use starknet_mempool_types::errors::MempoolError; use starknet_mempool_types::mempool_types::{AddTransactionArgs, CommitBlockArgs}; @@ -21,7 +21,7 @@ macro_rules! tx { ) => {{ use starknet_api::block::GasPrice; use starknet_api::{invoke_tx_args, tx_hash}; - use starknet_api::test_utils::invoke::executable_invoke_tx; + use starknet_api::test_utils::invoke::internal_invoke_tx; use starknet_api::transaction::fields::{ AllResourceBounds, ResourceBounds, @@ -37,7 +37,7 @@ macro_rules! tx { ..Default::default() }); - executable_invoke_tx(invoke_tx_args!{ + internal_invoke_tx(invoke_tx_args!{ tx_hash: tx_hash!($tx_hash), sender_address: contract_address!($address), nonce: nonce!($tx_nonce), @@ -256,7 +256,7 @@ pub fn commit_block( pub fn get_txs_and_assert_expected( mempool: &mut Mempool, n_txs: usize, - expected_txs: &[AccountTransaction], + expected_txs: &[InternalRpcTransaction], ) { let txs = mempool.get_txs(n_txs).unwrap(); assert_eq!(txs, expected_txs); diff --git a/crates/starknet_mempool/src/transaction_pool.rs b/crates/starknet_mempool/src/transaction_pool.rs index 7da94658dd8..b285c73869d 100644 --- a/crates/starknet_mempool/src/transaction_pool.rs +++ b/crates/starknet_mempool/src/transaction_pool.rs @@ -1,7 +1,7 @@ use std::collections::{hash_map, BTreeMap, HashMap}; use starknet_api::core::{ContractAddress, Nonce}; -use starknet_api::executable_transaction::AccountTransaction; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_api::transaction::TransactionHash; use starknet_mempool_types::errors::MempoolError; use starknet_mempool_types::mempool_types::{AccountState, MempoolResult}; @@ -9,7 +9,7 @@ use starknet_mempool_types::mempool_types::{AccountState, MempoolResult}; use crate::mempool::TransactionReference; use crate::utils::try_increment_nonce; -type HashToTransaction = HashMap; +type HashToTransaction = HashMap; /// Contains all transactions currently held in the mempool. /// Invariant: both data structures are consistent regarding the existence of transactions: @@ -26,7 +26,7 @@ pub struct TransactionPool { } impl TransactionPool { - pub fn insert(&mut self, tx: AccountTransaction) -> MempoolResult<()> { + pub fn insert(&mut self, tx: InternalRpcTransaction) -> MempoolResult<()> { let tx_reference = TransactionReference::new(&tx); let tx_hash = tx_reference.tx_hash; @@ -52,7 +52,7 @@ impl TransactionPool { Ok(()) } - pub fn remove(&mut self, tx_hash: TransactionHash) -> MempoolResult { + pub fn remove(&mut self, tx_hash: TransactionHash) -> MempoolResult { // Remove from pool. let tx = self.tx_pool.remove(&tx_hash).ok_or(MempoolError::TransactionNotFound { tx_hash })?; @@ -92,7 +92,10 @@ impl TransactionPool { self.txs_by_account.account_txs_sorted_by_nonce(address) } - pub fn get_by_tx_hash(&self, tx_hash: TransactionHash) -> MempoolResult<&AccountTransaction> { + pub fn get_by_tx_hash( + &self, + tx_hash: TransactionHash, + ) -> MempoolResult<&InternalRpcTransaction> { self.tx_pool.get(&tx_hash).ok_or(MempoolError::TransactionNotFound { tx_hash }) } diff --git a/crates/starknet_mempool_p2p/Cargo.toml b/crates/starknet_mempool_p2p/Cargo.toml index 71f7a074be2..f6cecb569d2 100644 --- a/crates/starknet_mempool_p2p/Cargo.toml +++ b/crates/starknet_mempool_p2p/Cargo.toml @@ -16,6 +16,7 @@ papyrus_network.workspace = true papyrus_protobuf.workspace = true serde.workspace = true starknet_api.workspace = true +starknet_class_manager_types.workspace = true starknet_gateway_types.workspace = true starknet_mempool_p2p_types.workspace = true starknet_sequencer_infra.workspace = true diff --git a/crates/starknet_mempool_p2p/src/lib.rs b/crates/starknet_mempool_p2p/src/lib.rs index 950d61b3cb7..c9f8765a00d 100644 --- a/crates/starknet_mempool_p2p/src/lib.rs +++ b/crates/starknet_mempool_p2p/src/lib.rs @@ -5,6 +5,8 @@ pub mod runner; use futures::FutureExt; use papyrus_network::gossipsub_impl::Topic; use papyrus_network::network_manager::{BroadcastTopicChannels, NetworkManager}; +use starknet_class_manager_types::transaction_converter::TransactionConverter; +use starknet_class_manager_types::SharedClassManagerClient; use starknet_gateway_types::communication::SharedGatewayClient; use crate::config::MempoolP2pConfig; @@ -16,7 +18,12 @@ pub const MEMPOOL_TOPIC: &str = "starknet_mempool_transaction_propagation/0.1.0" pub fn create_p2p_propagator_and_runner( mempool_p2p_config: MempoolP2pConfig, gateway_client: SharedGatewayClient, + class_manager_client: SharedClassManagerClient, ) -> (MempoolP2pPropagator, MempoolP2pRunner) { + let transaction_converter = TransactionConverter::new( + class_manager_client.clone(), + mempool_p2p_config.network_config.chain_id.clone(), + ); let mut network_manager = NetworkManager::new( mempool_p2p_config.network_config, // TODO(Shahak): Consider filling this once the sequencer node has a name. @@ -30,7 +37,8 @@ pub fn create_p2p_propagator_and_runner( ) .expect("Failed to register broadcast topic"); let network_future = network_manager.run(); - let mempool_p2p_propagator = MempoolP2pPropagator::new(broadcast_topic_client.clone()); + let mempool_p2p_propagator = + MempoolP2pPropagator::new(broadcast_topic_client.clone(), transaction_converter); let mempool_p2p_runner = MempoolP2pRunner::new( network_future.boxed(), broadcasted_messages_receiver, diff --git a/crates/starknet_mempool_p2p/src/propagator/mod.rs b/crates/starknet_mempool_p2p/src/propagator/mod.rs index 098f2e42960..9d05c5cdf1c 100644 --- a/crates/starknet_mempool_p2p/src/propagator/mod.rs +++ b/crates/starknet_mempool_p2p/src/propagator/mod.rs @@ -4,6 +4,10 @@ mod test; use async_trait::async_trait; use papyrus_network::network_manager::{BroadcastTopicClient, BroadcastTopicClientTrait}; use papyrus_protobuf::mempool::RpcTransactionWrapper; +use starknet_class_manager_types::transaction_converter::{ + TransactionConverter, + TransactionConverterTrait, +}; use starknet_mempool_p2p_types::communication::{ MempoolP2pPropagatorRequest, MempoolP2pPropagatorResponse, @@ -15,11 +19,15 @@ use tracing::warn; pub struct MempoolP2pPropagator { broadcast_topic_client: BroadcastTopicClient, + transaction_converter: TransactionConverter, } impl MempoolP2pPropagator { - pub fn new(broadcast_topic_client: BroadcastTopicClient) -> Self { - Self { broadcast_topic_client } + pub fn new( + broadcast_topic_client: BroadcastTopicClient, + transaction_converter: TransactionConverter, + ) -> Self { + Self { broadcast_topic_client, transaction_converter } } } @@ -33,6 +41,19 @@ impl ComponentRequestHandler MempoolP2pPropagatorResponse { match request { MempoolP2pPropagatorRequest::AddTransaction(transaction) => { + let transaction = match self + .transaction_converter + .convert_internal_rpc_tx_to_rpc_tx(transaction) + .await + { + Ok(transaction) => transaction, + Err(err) => { + return MempoolP2pPropagatorResponse::AddTransaction(Err( + MempoolP2pPropagatorError::TransactionConversionError(err.to_string()), + )); + } + }; + let result = self .broadcast_topic_client .broadcast_message(RpcTransactionWrapper(transaction)) diff --git a/crates/starknet_mempool_p2p/src/propagator/test.rs b/crates/starknet_mempool_p2p/src/propagator/test.rs index 155e8320606..8360b6bf697 100644 --- a/crates/starknet_mempool_p2p/src/propagator/test.rs +++ b/crates/starknet_mempool_p2p/src/propagator/test.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use futures::stream::StreamExt; use papyrus_network::network_manager::test_utils::{ mock_register_broadcast_topic, @@ -8,7 +10,13 @@ use papyrus_network::network_manager::BroadcastTopicChannels; use papyrus_network_types::network_types::BroadcastedMessageMetadata; use papyrus_protobuf::mempool::RpcTransactionWrapper; use papyrus_test_utils::{get_rng, GetTestInstance}; -use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::core::ChainId; +use starknet_api::rpc_transaction::InternalRpcTransaction; +use starknet_class_manager_types::transaction_converter::{ + TransactionConverter, + TransactionConverterTrait, +}; +use starknet_class_manager_types::EmptyClassManagerClient; use starknet_mempool_p2p_types::communication::MempoolP2pPropagatorRequest; use starknet_sequencer_infra::component_definitions::ComponentRequestHandler; use tokio::time::timeout; @@ -24,10 +32,16 @@ async fn process_handle_add_tx() { let BroadcastTopicChannels { broadcasted_messages_receiver: _, broadcast_topic_client } = subscriber_channels; let BroadcastNetworkMock { mut messages_to_broadcast_receiver, .. } = mock_network; - let rpc_transaction = RpcTransaction::get_test_instance(&mut get_rng()); - let mut mempool_p2p_propagator = MempoolP2pPropagator::new(broadcast_topic_client); + let internal_tx = InternalRpcTransaction::get_test_instance(&mut get_rng()); + // TODO(noamsp): use MockTransactionConverterTrait + let transaction_converter = + TransactionConverter::new(Arc::new(EmptyClassManagerClient), ChainId::create_for_testing()); + let rpc_transaction = + transaction_converter.convert_internal_rpc_tx_to_rpc_tx(internal_tx.clone()).await.unwrap(); + let mut mempool_p2p_propagator = + MempoolP2pPropagator::new(broadcast_topic_client, transaction_converter); mempool_p2p_propagator - .handle_request(MempoolP2pPropagatorRequest::AddTransaction(rpc_transaction.clone())) + .handle_request(MempoolP2pPropagatorRequest::AddTransaction(internal_tx)) .await; let message = timeout(TIMEOUT, messages_to_broadcast_receiver.next()).await.unwrap().unwrap(); assert_eq!(message, RpcTransactionWrapper(rpc_transaction)); @@ -41,7 +55,11 @@ async fn process_handle_continue_propagation() { subscriber_channels; let BroadcastNetworkMock { mut continue_propagation_receiver, .. } = mock_network; let propagation_metadata = BroadcastedMessageMetadata::get_test_instance(&mut get_rng()); - let mut mempool_p2p_propagator = MempoolP2pPropagator::new(broadcast_topic_client); + // TODO(noamsp): use MockTransactionConverterTrait + let transaction_converter = + TransactionConverter::new(Arc::new(EmptyClassManagerClient), ChainId::create_for_testing()); + let mut mempool_p2p_propagator = + MempoolP2pPropagator::new(broadcast_topic_client, transaction_converter); mempool_p2p_propagator .handle_request(MempoolP2pPropagatorRequest::ContinuePropagation( propagation_metadata.clone(), diff --git a/crates/starknet_mempool_p2p_types/src/communication.rs b/crates/starknet_mempool_p2p_types/src/communication.rs index 6ea5e313560..90e0a4df9d0 100644 --- a/crates/starknet_mempool_p2p_types/src/communication.rs +++ b/crates/starknet_mempool_p2p_types/src/communication.rs @@ -4,7 +4,7 @@ use async_trait::async_trait; use papyrus_network_types::network_types::BroadcastedMessageMetadata; use papyrus_proc_macros::handle_all_response_variants; use serde::{Deserialize, Serialize}; -use starknet_api::rpc_transaction::RpcTransaction; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_sequencer_infra::component_client::{ ClientError, LocalComponentClient, @@ -27,7 +27,7 @@ pub trait MempoolP2pPropagatorClient: Send + Sync { /// from other peers, use `continue_propagation`. async fn add_transaction( &self, - transaction: RpcTransaction, + transaction: InternalRpcTransaction, ) -> MempoolP2pPropagatorClientResult<()>; /// Continues the propagation of a transaction we've received from another peer. @@ -48,7 +48,7 @@ pub type MempoolP2pPropagatorRequestAndResponseSender = #[derive(Clone, Debug, Serialize, Deserialize)] pub enum MempoolP2pPropagatorRequest { - AddTransaction(RpcTransaction), + AddTransaction(InternalRpcTransaction), ContinuePropagation(BroadcastedMessageMetadata), } @@ -74,7 +74,7 @@ where { async fn add_transaction( &self, - transaction: RpcTransaction, + transaction: InternalRpcTransaction, ) -> MempoolP2pPropagatorClientResult<()> { let request = MempoolP2pPropagatorRequest::AddTransaction(transaction); handle_all_response_variants!( diff --git a/crates/starknet_mempool_p2p_types/src/errors.rs b/crates/starknet_mempool_p2p_types/src/errors.rs index 3037dd1ced2..6204f6beb7c 100644 --- a/crates/starknet_mempool_p2p_types/src/errors.rs +++ b/crates/starknet_mempool_p2p_types/src/errors.rs @@ -5,4 +5,6 @@ use thiserror::Error; pub enum MempoolP2pPropagatorError { #[error("Sender request error")] NetworkSendError, + #[error("Transaction conversion error: {0}")] + TransactionConversionError(String), } diff --git a/crates/starknet_mempool_types/src/communication.rs b/crates/starknet_mempool_types/src/communication.rs index 5f8e06e1535..cb4bb3788e4 100644 --- a/crates/starknet_mempool_types/src/communication.rs +++ b/crates/starknet_mempool_types/src/communication.rs @@ -7,7 +7,7 @@ use papyrus_network_types::network_types::BroadcastedMessageMetadata; use papyrus_proc_macros::handle_all_response_variants; use serde::{Deserialize, Serialize}; use starknet_api::core::ContractAddress; -use starknet_api::executable_transaction::AccountTransaction; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_sequencer_infra::component_client::{ ClientError, LocalComponentClient, @@ -45,7 +45,7 @@ pub trait MempoolClient: Send + Sync { // TODO(AlonH): Rename tx to transaction async fn add_tx(&self, args: AddTransactionArgsWrapper) -> MempoolClientResult<()>; async fn commit_block(&self, args: CommitBlockArgs) -> MempoolClientResult<()>; - async fn get_txs(&self, n_txs: usize) -> MempoolClientResult>; + async fn get_txs(&self, n_txs: usize) -> MempoolClientResult>; async fn contains_tx_from( &self, contract_address: ContractAddress, @@ -64,7 +64,7 @@ pub enum MempoolRequest { pub enum MempoolResponse { AddTransaction(MempoolResult<()>), CommitBlock(MempoolResult<()>), - GetTransactions(MempoolResult>), + GetTransactions(MempoolResult>), ContainsTransactionFrom(MempoolResult), } @@ -103,7 +103,7 @@ where ) } - async fn get_txs(&self, n_txs: usize) -> MempoolClientResult> { + async fn get_txs(&self, n_txs: usize) -> MempoolClientResult> { let request = MempoolRequest::GetTransactions(n_txs); handle_all_response_variants!( MempoolResponse, diff --git a/crates/starknet_mempool_types/src/mempool_types.rs b/crates/starknet_mempool_types/src/mempool_types.rs index 53163b31daa..485348c37a7 100644 --- a/crates/starknet_mempool_types/src/mempool_types.rs +++ b/crates/starknet_mempool_types/src/mempool_types.rs @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet}; use serde::{Deserialize, Serialize}; use starknet_api::core::{ContractAddress, Nonce}; -use starknet_api::executable_transaction::AccountTransaction; +use starknet_api::rpc_transaction::InternalRpcTransaction; use starknet_api::transaction::TransactionHash; use crate::errors::MempoolError; @@ -23,7 +23,7 @@ impl std::fmt::Display for AccountState { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct AddTransactionArgs { - pub tx: AccountTransaction, + pub tx: InternalRpcTransaction, pub account_state: AccountState, } diff --git a/crates/starknet_sequencer_node/src/components.rs b/crates/starknet_sequencer_node/src/components.rs index f03fe4c3c0e..43c5b4c94e4 100644 --- a/crates/starknet_sequencer_node/src/components.rs +++ b/crates/starknet_sequencer_node/src/components.rs @@ -57,7 +57,14 @@ pub fn create_node_components( let l1_provider_client = clients .get_l1_provider_shared_client() .expect("L1 Provider Client should be available"); - Some(create_batcher(config.batcher_config.clone(), mempool_client, l1_provider_client)) + // TODO(noamsp): Remove this and use the real client instead once implemented. + let class_manager_client = Arc::new(EmptyClassManagerClient); + Some(create_batcher( + config.batcher_config.clone(), + mempool_client, + l1_provider_client, + class_manager_client, + )) } ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => None, }; @@ -84,12 +91,13 @@ pub fn create_node_components( let state_sync_client = clients .get_state_sync_shared_client() .expect("State Sync Client should be available"); - + // TODO: Remove this and use the real client instead once implemented. + let class_manager_client = Arc::new(EmptyClassManagerClient); Some(create_gateway( config.gateway_config.clone(), state_sync_client, - config.compiler_config.clone(), mempool_client, + class_manager_client, )) } ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => None, @@ -104,23 +112,26 @@ pub fn create_node_components( ActiveComponentExecutionMode::Disabled => None, }; - let (mempool_p2p_propagator, mempool_p2p_runner) = match config - .components - .mempool_p2p - .execution_mode - { - ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled - | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { - let gateway_client = - clients.get_gateway_shared_client().expect("Gateway Client should be available"); - let (mempool_p2p_propagator, mempool_p2p_runner) = - create_p2p_propagator_and_runner(config.mempool_p2p_config.clone(), gateway_client); - (Some(mempool_p2p_propagator), Some(mempool_p2p_runner)) - } - ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => { - (None, None) - } - }; + let (mempool_p2p_propagator, mempool_p2p_runner) = + match config.components.mempool_p2p.execution_mode { + ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled + | ReactiveComponentExecutionMode::LocalExecutionWithRemoteEnabled => { + let gateway_client = clients + .get_gateway_shared_client() + .expect("Gateway Client should be available"); + // TODO: Remove this and use the real client instead once implemented. + let class_manager_client = Arc::new(EmptyClassManagerClient); + let (mempool_p2p_propagator, mempool_p2p_runner) = create_p2p_propagator_and_runner( + config.mempool_p2p_config.clone(), + gateway_client, + class_manager_client, + ); + (Some(mempool_p2p_propagator), Some(mempool_p2p_runner)) + } + ReactiveComponentExecutionMode::Disabled | ReactiveComponentExecutionMode::Remote => { + (None, None) + } + }; let mempool = match config.components.mempool.execution_mode { ReactiveComponentExecutionMode::LocalExecutionWithRemoteDisabled