From c7fc216c372adecd7606dce1539f05b410e38d4f Mon Sep 17 00:00:00 2001 From: Arni Hod Date: Wed, 25 Dec 2024 13:43:35 +0200 Subject: [PATCH] feat(starknet_gateway): create transaction generator towards benchmarking --- Cargo.lock | 2 + crates/starknet_gateway/Cargo.toml | 2 +- .../starknet_gateway/bench/gateway_bench.rs | 17 ++- .../starknet_gateway/src/bench_test_utils.rs | 110 ++++++++++++++++++ crates/starknet_gateway/src/lib.rs | 2 +- .../src/state_reader_test_utils.rs | 6 +- 6 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 crates/starknet_gateway/src/bench_test_utils.rs diff --git a/Cargo.lock b/Cargo.lock index ed3bf5b5cf..bc14a3778a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2875,6 +2875,7 @@ dependencies = [ "ciborium", "clap", "criterion-plot", + "futures", "is-terminal", "itertools 0.10.5", "num-traits 0.2.19", @@ -2887,6 +2888,7 @@ dependencies = [ "serde_derive", "serde_json", "tinytemplate", + "tokio", "walkdir", ] diff --git a/crates/starknet_gateway/Cargo.toml b/crates/starknet_gateway/Cargo.toml index cce833a6fc..d4be031b63 100644 --- a/crates/starknet_gateway/Cargo.toml +++ b/crates/starknet_gateway/Cargo.toml @@ -39,7 +39,7 @@ validator.workspace = true [dev-dependencies] assert_matches.workspace = true cairo-lang-sierra-to-casm.workspace = true -criterion.workspace = true +criterion = { workspace = true, features = ["async_tokio"] } mockall.workspace = true mockito.workspace = true num-bigint.workspace = true diff --git a/crates/starknet_gateway/bench/gateway_bench.rs b/crates/starknet_gateway/bench/gateway_bench.rs index 3c0acf6360..bb57045b8f 100644 --- a/crates/starknet_gateway/bench/gateway_bench.rs +++ b/crates/starknet_gateway/bench/gateway_bench.rs @@ -9,10 +9,23 @@ //! //! Run the benchmarks using `cargo bench --bench gateway_bench`. -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use starknet_gateway::bench_test_utils::{BenchTestSetup, BenchTestSetupConfig}; fn invoke_benchmark(criterion: &mut Criterion) { - criterion.bench_function("invokes", |benchmark| benchmark.iter(|| {})); + let tx_generator_config = BenchTestSetupConfig::default(); + let n_txs = tx_generator_config.n_txs; + + let test_setup = BenchTestSetup::new(tx_generator_config); + criterion.bench_with_input( + BenchmarkId::new("invoke", n_txs), + &test_setup, + |bencher, test_setup| { + bencher + .to_async(tokio::runtime::Runtime::new().unwrap()) + .iter(|| test_setup.send_txs_to_gateway()); + }, + ); } criterion_group!(benches, invoke_benchmark); diff --git a/crates/starknet_gateway/src/bench_test_utils.rs b/crates/starknet_gateway/src/bench_test_utils.rs new file mode 100644 index 0000000000..5da8608821 --- /dev/null +++ b/crates/starknet_gateway/src/bench_test_utils.rs @@ -0,0 +1,110 @@ +use std::sync::Arc; + +use blockifier::context::ChainInfo; +use blockifier::test_utils::contracts::FeatureContract; +use blockifier::test_utils::{create_trivial_calldata, CairoVersion, RunnableCairo1}; +use mempool_test_utils::starknet_api_test_utils::test_valid_resource_bounds; +use starknet_api::core::ContractAddress; +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_mempool_types::communication::MockMempoolClient; +use starknet_sierra_compile::config::SierraToCasmCompilationConfig; + +use crate::compilation::GatewayCompiler; +use crate::config::GatewayConfig; +use crate::gateway::Gateway; +use crate::state_reader_test_utils::local_test_state_reader_factory; + +const N_TXS: usize = 100; + +// TODO(Arni): Use `AccountTransactionGenerator` from `starknet_api_test_utils`. +struct TransactionGenerator { + nonce_manager: NonceManager, + sender_address: ContractAddress, + test_contract_address: ContractAddress, +} + +impl TransactionGenerator { + fn new(cairo_version: CairoVersion) -> Self { + let account_contract = FeatureContract::AccountWithoutValidations(cairo_version); + let test_contract = FeatureContract::TestContract(cairo_version); + let sender_address = account_contract.get_instance_address(0); + let test_contract_address = test_contract.get_instance_address(0); + Self { nonce_manager: NonceManager::default(), sender_address, test_contract_address } + } + + fn generate_invoke(&mut self) -> RpcTransaction { + let invoke_args = invoke_tx_args!( + nonce: self.nonce_manager.next(self.sender_address), + sender_address: self.sender_address, + resource_bounds: test_valid_resource_bounds(), + calldata: create_trivial_calldata(self.test_contract_address), + ); + rpc_invoke_tx(invoke_args) + } +} + +pub struct BenchTestSetupConfig { + pub n_txs: usize, + pub gateway_config: GatewayConfig, + pub compiler_config: SierraToCasmCompilationConfig, +} + +impl Default for BenchTestSetupConfig { + fn default() -> Self { + Self { + n_txs: N_TXS, + gateway_config: GatewayConfig { + chain_info: ChainInfo::create_for_testing(), + ..Default::default() + }, + compiler_config: SierraToCasmCompilationConfig::default(), + } + } +} + +pub struct BenchTestSetup { + gateway: Gateway, + txs: Vec, +} + +impl BenchTestSetup { + pub fn new(config: BenchTestSetupConfig) -> Self { + let cairo_version = CairoVersion::Cairo1(RunnableCairo1::Casm); + let mut tx_generator = TransactionGenerator::new(cairo_version); + + let mut txs: Vec = Vec::with_capacity(config.n_txs); + for _ in 0..config.n_txs { + txs.push(tx_generator. + // TODO(Arni): Do something smarter than generate raw invoke. + generate_invoke()); + } + + 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(); + 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), + ); + + Self { gateway: gateway_business_logic, txs } + } + + pub async fn send_txs_to_gateway(&self) { + for tx in &self.txs { + let _tx_hash = self + .gateway + .add_tx(tx.clone(), None) + .await + .expect("Some txs has failed in the gateway."); + } + } +} diff --git a/crates/starknet_gateway/src/lib.rs b/crates/starknet_gateway/src/lib.rs index 248c30d58f..9707375e2e 100644 --- a/crates/starknet_gateway/src/lib.rs +++ b/crates/starknet_gateway/src/lib.rs @@ -1,3 +1,4 @@ +pub mod bench_test_utils; pub mod communication; pub mod compilation; mod compiler_version; @@ -9,7 +10,6 @@ pub mod rpc_state_reader; #[cfg(test)] mod rpc_state_reader_test; pub mod state_reader; -#[cfg(test)] mod state_reader_test_utils; mod stateful_transaction_validator; mod stateless_transaction_validator; diff --git a/crates/starknet_gateway/src/state_reader_test_utils.rs b/crates/starknet_gateway/src/state_reader_test_utils.rs index 9b505af103..f81e15a8b0 100644 --- a/crates/starknet_gateway/src/state_reader_test_utils.rs +++ b/crates/starknet_gateway/src/state_reader_test_utils.rs @@ -16,7 +16,7 @@ use starknet_types_core::felt::Felt; use crate::state_reader::{MempoolStateReader, StateReaderFactory}; #[derive(Clone)] -pub struct TestStateReader { +pub(crate) struct TestStateReader { pub block_info: BlockInfo, pub blockifier_state_reader: DictStateReader, } @@ -53,7 +53,7 @@ impl BlockifierStateReader for TestStateReader { } } -pub struct TestStateReaderFactory { +pub(crate) struct TestStateReaderFactory { pub state_reader: TestStateReader, } @@ -69,7 +69,7 @@ impl StateReaderFactory for TestStateReaderFactory { } } -pub fn local_test_state_reader_factory( +pub(crate) fn local_test_state_reader_factory( cairo_version: CairoVersion, zero_balance: bool, ) -> TestStateReaderFactory {