diff --git a/Cargo.lock b/Cargo.lock index 67a97f72c3e..33c27003ca7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3263,6 +3263,7 @@ dependencies = [ "ethnum", "fuel-core", "fuel-core-chain-config", + "fuel-core-client", "fuel-core-database", "fuel-core-services", "fuel-core-storage", diff --git a/benches/Cargo.toml b/benches/Cargo.toml index e4ee7db927b..d2546fd5876 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -23,6 +23,7 @@ fuel-core = { path = "../crates/fuel-core", default-features = false, features = "rocksdb-production", ] } fuel-core-chain-config = { workspace = true } +fuel-core-client = { path = "./../crates/client" } fuel-core-database = { path = "./../crates/database" } fuel-core-services = { path = "./../crates/services" } fuel-core-storage = { path = "./../crates/storage", features = ["smt"] } @@ -76,3 +77,7 @@ name = "transaction_throughput" [[bench]] harness = false name = "db_lookup_times" + +[[bench]] +harness = false +name = "end_to_end_query_times" diff --git a/benches/benches/end_to_end_query_times.rs b/benches/benches/end_to_end_query_times.rs new file mode 100644 index 00000000000..9707bafa96d --- /dev/null +++ b/benches/benches/end_to_end_query_times.rs @@ -0,0 +1,143 @@ +use fuel_core::service::{ + config::Trigger, + Config, + FuelService, +}; +use fuel_core_chain_config::{ + ChainConfig, + Randomize, + StateConfig, +}; +use fuel_core_client::client::{ + pagination::{ + PageDirection, + PaginationRequest, + }, + FuelClient, +}; + +use fuel_core_types::fuel_tx::Address; +use rand::{ + rngs::StdRng, + SeedableRng, +}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + println!("Setting up bench harness."); + let mut harness = Harness::new(StdRng::seed_from_u64(2322)).await?; + + println!("Populating storage with transactions."); + harness.produce_blocks_with_transactions().await?; + + println!("Querying transactions from storage."); + harness.query_transactions_multiple_times().await?; + + println!("Shutting down."); + harness.shutdown(); + + Ok(()) +} + +struct Harness { + rng: Rng, + params: Parameters, + client: FuelClient, + node: FuelService, + owner_address: Address, +} + +impl Harness { + async fn new(mut rng: Rng) -> anyhow::Result { + let params = Parameters::hard_coded(); + let node = FuelService::new_node(node_config()).await?; + let client = FuelClient::from(node.bound_address); + let owner_address = Address::randomize(&mut rng); + + Ok(Self { + rng, + params, + client, + node, + owner_address, + }) + } + + async fn produce_blocks_with_transactions(&mut self) -> anyhow::Result<()> { + for _ in 0..self.params.num_blocks { + for tx in (1..=self.params.tx_count_per_block).map(|i| { + let script_gas_limit = 26; // Cost of OP_RET * 2 + test_helpers::make_tx_with_recipient( + &mut self.rng, + i, + script_gas_limit, + self.owner_address, + ) + }) { + self.client.submit(&tx).await?; + } + self.client.produce_blocks(1, None).await?; + } + + Ok(()) + } + + async fn query_transactions_multiple_times(&self) -> anyhow::Result<()> { + for _ in 0..self.params.num_queries { + let request = PaginationRequest { + cursor: None, + results: self.params.num_results_per_query, + direction: PageDirection::Forward, + }; + + self.client + .transactions_by_owner(&self.owner_address, request) + .await?; + } + + Ok(()) + } + + fn shutdown(self) { + drop(self.node); + } +} + +fn node_config() -> Config { + let mut chain_config = ChainConfig::local_testnet(); + + chain_config + .consensus_parameters + .set_block_gas_limit(u64::MAX); + + chain_config + .consensus_parameters + .set_block_transaction_size_limit(u64::MAX) + .unwrap(); + + let state_config = StateConfig::local_testnet(); + + let mut config = Config::local_node_with_configs(chain_config, state_config); + config.block_production = Trigger::Never; + config.graphql_config.max_queries_complexity = usize::MAX; + + config +} + +struct Parameters { + num_queries: usize, + num_results_per_query: i32, + num_blocks: usize, + tx_count_per_block: u64, +} + +impl Parameters { + fn hard_coded() -> Self { + Self { + num_queries: 10, + num_results_per_query: 10_000, + num_blocks: 10, + tx_count_per_block: 1000, + } + } +} diff --git a/tests/test-helpers/src/lib.rs b/tests/test-helpers/src/lib.rs index 89e3f0c0616..7bac58dc5f3 100644 --- a/tests/test-helpers/src/lib.rs +++ b/tests/test-helpers/src/lib.rs @@ -9,6 +9,7 @@ use fuel_core_types::{ }, fuel_crypto::SecretKey, fuel_tx::{ + Address, Output, Transaction, TransactionBuilder, @@ -37,6 +38,16 @@ pub fn make_tx( rng: &mut (impl CryptoRng + RngCore), i: u64, max_gas_limit: u64, +) -> Transaction { + let recipient = rng.gen(); + make_tx_with_recipient(rng, i, max_gas_limit, recipient) +} + +pub fn make_tx_with_recipient( + rng: &mut (impl CryptoRng + RngCore), + i: u64, + max_gas_limit: u64, + recipient: Address, ) -> Transaction { TransactionBuilder::script( op::ret(RegId::ONE).to_bytes().into_iter().collect(), @@ -53,7 +64,7 @@ pub fn make_tx( .add_output(Output::Change { amount: 0, asset_id: Default::default(), - to: rng.gen(), + to: recipient, }) .finalize_as_transaction() }