From c29dae7226262a6b255ca1cb5bd9000fd4886d3c Mon Sep 17 00:00:00 2001 From: Mitch Turner Date: Sun, 29 Dec 2024 11:48:04 -0700 Subject: [PATCH] Add tests for cost recording --- crates/fuel-core/src/service.rs | 12 +- .../gas_price_service/src/v1/service.rs | 87 +++++++++++++- tests/tests/gas_price.rs | 111 +++++++++++++++--- 3 files changed, 186 insertions(+), 24 deletions(-) diff --git a/crates/fuel-core/src/service.rs b/crates/fuel-core/src/service.rs index 676b3f506f6..6b4f82aee8d 100644 --- a/crates/fuel-core/src/service.rs +++ b/crates/fuel-core/src/service.rs @@ -467,13 +467,6 @@ impl RunnableTask for Task { #[allow(non_snake_case)] #[cfg(test)] mod tests { - use std::{ - thread::sleep, - time::Duration, - }; - - use fuel_core_services::State; - use crate::{ service::{ Config, @@ -481,6 +474,11 @@ mod tests { }, ShutdownListener, }; + use fuel_core_services::State; + use std::{ + thread::sleep, + time::Duration, + }; #[tokio::test] async fn stop_sub_service_shutdown_all_services() { diff --git a/crates/services/gas_price_service/src/v1/service.rs b/crates/services/gas_price_service/src/v1/service.rs index 1c773c3a7e0..602b086539b 100644 --- a/crates/services/gas_price_service/src/v1/service.rs +++ b/crates/services/gas_price_service/src/v1/service.rs @@ -263,7 +263,7 @@ where TaskNextAction::always_continue(res) } da_block_costs_res = self.da_source_channel.recv() => { - tracing::debug!("Received DA block costs: {:?}", da_block_costs_res); + tracing::error!("Received DA block costs: {:?}", da_block_costs_res); match da_block_costs_res { Ok(da_block_costs) => { self.da_block_costs_buffer.push(da_block_costs); @@ -369,6 +369,7 @@ mod tests { fuel_core_storage_adapter::storage::{ GasPriceColumn, GasPriceColumn::UnrecordedBlocks, + GasPriceMetadata, RecordedHeights, UnrecordedBlocksTable, }, @@ -393,6 +394,7 @@ mod tests { metadata::{ updater_from_config, V1AlgorithmConfig, + V1Metadata, }, service::{ initialize_algorithm, @@ -709,4 +711,87 @@ mod tests { service.shutdown().await.unwrap(); } + + #[tokio::test] + async fn run__stores_correct_amount_for_costs() { + // given + let recorded_block_height = 100; + let block_height = 200; + let l2_block = BlockInfo::Block { + height: block_height, + gas_used: 60, + block_gas_capacity: 100, + block_bytes: 100, + block_fees: 100, + }; + + let (l2_block_sender, l2_block_receiver) = mpsc::channel(1); + let l2_block_source = FakeL2BlockSource { + l2_block: l2_block_receiver, + }; + + let metadata_storage = FakeMetadata::empty(); + // Configured so exec gas price doesn't change, only da gas price + let config = arbitrary_v1_algorithm_config(); + let mut inner = database(); + let mut tx = inner.write_transaction(); + tx.storage_as_mut::() + .insert(&BlockHeight::from(1), &100) + .unwrap(); + tx.commit().unwrap(); + let mut algo_updater = updater_from_config(&config); + let shared_algo = + SharedGasPriceAlgo::new_with_algorithm(algo_updater.algorithm()); + algo_updater.l2_block_height = block_height - 1; + algo_updater.last_profit = 10_000; + algo_updater.new_scaled_da_gas_price = 10_000_000; + + let notifier = Arc::new(tokio::sync::Notify::new()); + let blob_cost_wei = 9000; + let da_source = DaSourceService::new( + DummyDaBlockCosts::new( + Ok(DaBlockCosts { + bundle_id: 8765, + l2_blocks: 1..=recorded_block_height, + blob_cost_wei, + bundle_size_bytes: 3000, + }), + notifier.clone(), + ), + Some(Duration::from_millis(1)), + ); + let mut watcher = StateWatcher::started(); + let da_service_runner = ServiceRunner::new(da_source); + da_service_runner.start_and_await().await.unwrap(); + + let mut service = GasPriceServiceV1::new( + l2_block_source, + shared_algo, + algo_updater, + da_service_runner, + inner, + ); + let read_algo = service.next_block_algorithm(); + let initial_price = read_algo.next_gas_price(); + + service.run(&mut watcher).await; + tokio::time::sleep(Duration::from_millis(100)).await; + l2_block_sender.send(l2_block).await.unwrap(); + + // when + service.run(&mut watcher).await; + tokio::time::sleep(Duration::from_millis(100)).await; + + // then + let metadata: V1Metadata = service + .storage_tx_provider + .storage::() + .get(&block_height.into()) + .unwrap() + .and_then(|x| x.v1().cloned()) + .unwrap(); + assert_eq!(metadata.latest_known_total_da_cost_excess, blob_cost_wei); + + service.shutdown().await.unwrap(); + } } diff --git a/tests/tests/gas_price.rs b/tests/tests/gas_price.rs index 0092cc19823..a86c5d5a67d 100644 --- a/tests/tests/gas_price.rs +++ b/tests/tests/gas_price.rs @@ -724,21 +724,7 @@ fn run__if_metadata_is_behind_l2_then_will_catch_up() { // }); } -#[test] -fn produce_block__algorithm_recovers_from_divergent_profit() { - _produce_block__algorithm_recovers_from_divergent_profit(110); -} - -fn _produce_block__algorithm_recovers_from_divergent_profit(block_delay: usize) { - let _ = tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - .try_init(); - let mut rng = rand::rngs::StdRng::seed_from_u64(2322u64); - - // given - let mut mock = FakeServer::new(); - let url = mock.url(); - let rt = tokio::runtime::Runtime::new().unwrap(); +fn node_config_with_da_committer_url(url: &str) -> Config { let block_gas_limit = 3_000_000; let chain_config = ChainConfig { consensus_parameters: ConsensusParameters::V1(ConsensusParametersV1 { @@ -754,13 +740,29 @@ fn _produce_block__algorithm_recovers_from_divergent_profit(block_delay: usize) node_config.min_da_gas_price = starting_gas_price; node_config.max_da_gas_price_change_percent = 15; node_config.block_production = Trigger::Never; - node_config.da_committer_url = Some(url.clone()); + node_config.da_committer_url = Some(url.to_string()); node_config.da_poll_interval = Some(100); node_config.da_p_component = 224_000; node_config.da_d_component = 2_690_000; // node_config.da_p_component = 1; // node_config.da_d_component = 10; node_config.block_activity_threshold = 0; + node_config +} + +#[test] +fn produce_block__algorithm_recovers_from_divergent_profit() { + let _ = tracing_subscriber::fmt() + .with_max_level(tracing::Level::INFO) + .try_init(); + let mut rng = rand::rngs::StdRng::seed_from_u64(2322u64); + + // given + let mut mock = FakeServer::new(); + let url = mock.url(); + let rt = tokio::runtime::Runtime::new().unwrap(); + let node_config = node_config_with_da_committer_url(&url); + let block_delay = 110; let (srv, client) = rt.block_on(async { let srv = FuelService::new_node(node_config.clone()).await.unwrap(); @@ -892,3 +894,80 @@ async fn produce_a_block(client: &FuelClient, rng: &mu } let _ = client.produce_blocks(1, None).await.unwrap(); } + +#[test] +fn produce_block__costs_from_da_are_properly_recorded_in_metadata() { + let _ = tracing_subscriber::fmt() + .with_max_level(tracing::Level::ERROR) + .try_init(); + let mut rng = rand::rngs::StdRng::seed_from_u64(2322u64); + + // given + let mut mock = FakeServer::new(); + let url = mock.url(); + let rt = tokio::runtime::Runtime::new().unwrap(); + let node_config = node_config_with_da_committer_url(&url); + let l2_blocks = 1000; + let da_blocks = l2_blocks / 2; + + let (srv, client) = rt.block_on(async { + let srv = FuelService::new_node(node_config.clone()).await.unwrap(); + let client = FuelClient::from(srv.bound_address); + + for _b in 0..l2_blocks { + produce_a_block(&client, &mut rng).await; + } + let _ = client.produce_blocks(1, None).await.unwrap(); + + let height = srv.shared.database.gas_price().latest_height().unwrap(); + let metadata = srv + .shared + .database + .gas_price() + .get_metadata(&height) + .unwrap() + .and_then(|x| x.v1().cloned()) + .unwrap(); + tracing::info!("metadata: {:?}", metadata); + assert_eq!(metadata.latest_known_total_da_cost_excess, 0); + (srv, client) + }); + + // Add multiple cost responses that add up to `da_cost` + let blob_count = 5; + let mut total_cost = 0; + for i in 0..blob_count { + let blob_size = da_blocks / blob_count; + let cost = rng.gen_range(10_000_000..100_000_000); + let costs = RawDaBlockCosts { + id: i + 1, + start_height: blob_size * i + 1, + end_height: blob_size * i + blob_size, + da_block_height: DaBlockHeight(999999999 + i as u64), + cost, + size: 100, + }; + total_cost += cost; + mock.add_response(costs); + + rt.block_on(async { + tokio::time::sleep(Duration::from_millis(200)).await; + // when + let _ = client.produce_blocks(1, None).await.unwrap(); + tokio::time::sleep(Duration::from_millis(100)).await; + + let height = srv.shared.database.gas_price().latest_height().unwrap(); + let metadata = srv + .shared + .database + .gas_price() + .get_metadata(&height) + .unwrap() + .and_then(|x| x.v1().cloned()) + .unwrap(); + + // then + assert_eq!(metadata.latest_known_total_da_cost_excess, total_cost); + }); + } +}