From 5894c710c6aa6a86f17cf0090e1939be502cac51 Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Thu, 7 May 2026 12:16:16 +0300 Subject: [PATCH 1/9] Log tx/block ids as {:x} im the mempool --- mempool/src/pool/mod.rs | 12 ++++++------ mempool/src/pool/tx_pool/mod.rs | 14 ++++++++------ mempool/src/pool/tx_pool/reorg.rs | 14 +++++++------- mempool/src/pool/tx_pool/store/mod.rs | 4 ++-- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/mempool/src/pool/mod.rs b/mempool/src/pool/mod.rs index 35e26a6732..5a0d23413b 100644 --- a/mempool/src/pool/mod.rs +++ b/mempool/src/pool/mod.rs @@ -372,7 +372,7 @@ impl Mempool { log::trace!("Performing orphan processing work"); let orphan = state.work_queue.pick(|peer, orphan_id| { - log::debug!("Processing orphan tx {orphan_id:?} coming from peer {peer}"); + log::debug!("Processing orphan tx {orphan_id:x} coming from peer {peer}"); match state.orphans.entry(&orphan_id) { Some(orphan) if orphan.is_ready() => { @@ -386,7 +386,7 @@ impl Mempool { None => { // The orphan may have been kicked out of the pool in the meantime. // Return with `None` in that case to indicate we're not really doing any work. - log::debug!("Orphan tx {orphan_id:?} no longer in the pool"); + log::debug!("Orphan tx {orphan_id:x} no longer in the pool"); None } } @@ -396,12 +396,12 @@ impl Mempool { Some(Ok(orphan)) => { let orphan = orphan.map_origin(TxOrigin::from); let orphan_id = *orphan.tx_id(); - log::trace!("Re-processing orphan transaction {orphan_id:?}"); + log::trace!("Re-processing orphan transaction {orphan_id:x}"); if let Err(err) = state.add_transaction(orphan) { - log::debug!("Orphan transaction {orphan_id:?} evicted: {err}"); + log::debug!("Orphan transaction {orphan_id:x} evicted: {err}"); } } - Some(Err(orphan_id)) => log::trace!("Orphan tx {orphan_id:?} not ready"), + Some(Err(orphan_id)) => log::trace!("Orphan tx {orphan_id:x} not ready"), None => log::trace!("No orphan processing work left to do"), } } @@ -681,7 +681,7 @@ impl<'a> TxFinalizer<'a> { let orphan_id = *orphan.tx_id(); let peer_id = orphan.origin().peer_id(); if self.work_queue.insert(peer_id, orphan_id) { - log::trace!("Added orphan {orphan_id:?} to peer{peer_id}'s work queue"); + log::trace!("Added orphan {orphan_id:x} to peer{peer_id}'s work queue"); } } } diff --git a/mempool/src/pool/tx_pool/mod.rs b/mempool/src/pool/tx_pool/mod.rs index f877902f2f..2497ad088b 100644 --- a/mempool/src/pool/tx_pool/mod.rs +++ b/mempool/src/pool/tx_pool/mod.rs @@ -634,7 +634,7 @@ impl TxPool { let expired = now.saturating_sub(creation_time) > self.max_tx_age; if expired { log::trace!( - "Evicting tx {} which was created at {:?}. It is now {:?}", + "Evicting tx {:x} which was created at {:?}. It is now {:?}", tx_id, creation_time, now @@ -665,7 +665,7 @@ impl TxPool { let removed = self.store.txs_by_id.get(&removed_id).expect("tx with id should exist"); log::debug!( - "Mempool trim: Evicting tx {} which has a descendant score of {:?} and has size {}", + "Mempool trim: Evicting tx {:x} which has a descendant score of {:?} and has size {}", removed_id, removed.descendant_score(), removed.size() @@ -697,7 +697,9 @@ impl TxPool { // dependencies. However, it does not appear to be easy to extract that information // from the transaction verifier at the moment. To be addressed in the future. - log::error!("Disconnecting {disc_id} failed with '{err}' during eviction of {tx_id}"); + log::error!( + "Disconnecting {disc_id:x} failed with '{err}' during eviction of {tx_id:x}" + ); if let Err(refresh_err) = reorg::refresh_mempool(self, |_, _| ()) { log::error!("Refreshing mempool failed: {refresh_err}"); @@ -792,7 +794,7 @@ impl TxPool { self.check_preliminary_mempool_policy(&transaction)?; for attempt_no in 1..=config::MAX_TX_ADDITION_ATTEMPTS { - log::trace!("Adding {tx_id:?} attempt #{attempt_no}"); + log::trace!("Adding {tx_id:x} attempt #{attempt_no}"); transaction = match self.try_add_transaction(transaction)? { TxAdditionAttemptOutcome::Added => { let transaction = self.store.get_entry(&tx_id).expect("just added"); @@ -809,7 +811,7 @@ impl TxPool { current_tip, } => { log::debug!( - "Tip moved from {start_tip:?} to {current_tip:?} while verifying {tx_id:?}" + "Tip moved from {start_tip:x} to {current_tip:x} while verifying {tx_id:x}" ); transaction } @@ -872,7 +874,7 @@ impl TxPool { let mut tx_verifier = self.tx_verifier.derive_child(); log::trace!( - "Verifying {tx_id:?}, tip = {start_tip:?}, tx_verifier's best block for utxos = {:?}", + "Verifying {tx_id:x}, tip = {start_tip:x}, tx_verifier's best block for utxos = {:x}", tx_verifier.get_best_block_for_utxos()? ); diff --git a/mempool/src/pool/tx_pool/reorg.rs b/mempool/src/pool/tx_pool/reorg.rs index 8ace67c7e0..c54aa1c8dc 100644 --- a/mempool/src/pool/tx_pool/reorg.rs +++ b/mempool/src/pool/tx_pool/reorg.rs @@ -117,7 +117,7 @@ fn fetch_disconnected_txs( .get_best_block_for_utxos() .map_err(|_| ReorgError::BestBlockForUtxos)?; - log::debug!("Fetching disconnected txs, old_tip = {old_tip:?}"); + log::debug!("Fetching disconnected txs, old_tip = {old_tip:x}"); let now = tx_pool.clock.get_time(); @@ -148,7 +148,7 @@ pub fn handle_new_tip( if new_tip != actual_tip { log::debug!( - "Not updating mempool because actual tip differs: new_tip = {new_tip:?}, actual_tip = {actual_tip:?}" + "Not updating mempool because actual tip differs: new_tip = {new_tip:x}, actual_tip = {actual_tip:x}" ); return Ok(()); @@ -174,7 +174,7 @@ fn reorg_mempool_transactions( let old_transactions = tx_pool.reset(); log::debug!( - "Reorging mempool txs, tx_verifier's best block for utxos after mempool reset: {:?}", + "Reorging mempool txs, tx_verifier's best block for utxos after mempool reset: {:x}", tx_pool .tx_verifier .get_best_block_for_utxos() @@ -183,18 +183,18 @@ fn reorg_mempool_transactions( for tx in txs_to_insert { let tx_id = *tx.tx_id(); - log::trace!("Adding {tx_id} after reorg"); + log::trace!("Adding {tx_id:x} after reorg"); if let Err(e) = tx_pool.add_transaction(tx, &mut finalizer) { - log::debug!("Disconnected transaction {tx_id:?} no longer validates: {e:?}") + log::debug!("Disconnected transaction {tx_id:x} no longer validates: {e:?}") } } // Re-populate the verifier with transactions from mempool for tx in old_transactions { let tx_id = *tx.tx_id(); - log::trace!("Adding {tx_id} after reorg"); + log::trace!("Adding {tx_id:x} after reorg"); if let Err(e) = tx_pool.add_transaction(tx, &mut finalizer) { - log::debug!("Evicting {tx_id:?} from mempool: {e:?}") + log::debug!("Evicting {tx_id:x} from mempool: {e:?}") } } diff --git a/mempool/src/pool/tx_pool/store/mod.rs b/mempool/src/pool/tx_pool/store/mod.rs index 3a605ffe2b..862e333930 100644 --- a/mempool/src/pool/tx_pool/store/mod.rs +++ b/mempool/src/pool/tx_pool/store/mod.rs @@ -543,7 +543,7 @@ impl MempoolStore { tx_id: &Id, reason: MempoolRemovalReason, ) -> Option { - log::info!("remove_tx: {}", tx_id.to_hash()); + log::debug!("remove_tx: {:x}", tx_id.to_hash()); let entry = self.mem_tracker.modify(&mut self.txs_by_id, |by_id, _| by_id.remove(tx_id)); if let Some(entry) = entry { @@ -773,7 +773,7 @@ impl TxMempoolEntry { } pub fn ancestor_score(&self) -> AncestorScore { - log::debug!("ancestor score for {:?}", self.tx_id()); + log::debug!("ancestor score for {:x}", self.tx_id()); log::debug!( "fees with ancestors: {:?}, size_with_ancestors: {}, fee: {:?}, size: {}", self.fees_with_ancestors, From ce60df37c22f9d036b1793fa974b0f250df5e00a Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Tue, 12 May 2026 12:29:55 +0300 Subject: [PATCH 2/9] Blockprod tests refactor - chain_config is always passed to setup_blockprod_test --- .../src/detail/tests/collect_transactions.rs | 19 +-- .../tests/process_block_with_custom_id.rs | 12 +- .../src/detail/tests/produce_block/mod.rs | 119 +++++++++--------- .../tests/produce_block/tx_selection_mtp.rs | 21 ++-- blockprod/src/detail/tests/stop_jobs.rs | 42 ++++--- blockprod/src/tests/helpers.rs | 14 +-- blockprod/src/tests/mod.rs | 7 +- 7 files changed, 122 insertions(+), 112 deletions(-) diff --git a/blockprod/src/detail/tests/collect_transactions.rs b/blockprod/src/detail/tests/collect_transactions.rs index 7c4ef653da..f74d56e110 100644 --- a/blockprod/src/detail/tests/collect_transactions.rs +++ b/blockprod/src/detail/tests/collect_transactions.rs @@ -13,8 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::sync::Arc; + use common::{ - chain::block::timestamp::BlockTimestamp, + chain::{block::timestamp::BlockTimestamp, config::create_unit_test_config}, primitives::{H256, Id}, time_getter::TimeGetter, }; @@ -37,8 +39,9 @@ const DUMMY_TIMESTAMP: BlockTimestamp = BlockTimestamp::from_int_seconds(0u64); #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn collect_txs_failed() { - let (mut manager, chain_config, _chainstate, _mempool, _p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (mut manager, _chainstate, _mempool, _p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut mock_mempool = MockMempoolInterface::default(); mock_mempool.expect_collect_txs().return_once(|_, _, _| { @@ -79,8 +82,9 @@ async fn collect_txs_failed() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn subsystem_error() { - let (mut manager, chain_config, _chainstate, _mempool, _p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (mut manager, _chainstate, _mempool, _p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mock_mempool = MockMempoolInterface::default(); let mock_mempool_subsystem = manager.add_subsystem("mock-mempool", mock_mempool); @@ -123,8 +127,9 @@ async fn subsystem_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn succeeded() { - let (mut manager, chain_config, _chainstate, _mempool, _p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (mut manager, _chainstate, _mempool, _p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut mock_mempool = MockMempoolInterface::default(); diff --git a/blockprod/src/detail/tests/process_block_with_custom_id.rs b/blockprod/src/detail/tests/process_block_with_custom_id.rs index dc0a9a211c..05939516e5 100644 --- a/blockprod/src/detail/tests/process_block_with_custom_id.rs +++ b/blockprod/src/detail/tests/process_block_with_custom_id.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use rstest::rstest; -use common::time_getter::TimeGetter; +use common::{chain::config::create_unit_test_config, time_getter::TimeGetter}; use mempool::tx_accumulator::PackingStrategy; use randomness::RngExt as _; use test_utils::random::{Seed, make_seedable_rng}; @@ -35,8 +35,9 @@ use crate::{ #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_with_wait(#[case] seed: Seed) { - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); @@ -95,8 +96,9 @@ async fn multiple_jobs_with_wait(#[case] seed: Seed) { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_without_wait_same_jobkey(#[case] seed: Seed) { - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); diff --git a/blockprod/src/detail/tests/produce_block/mod.rs b/blockprod/src/detail/tests/produce_block/mod.rs index fa61912fc2..d4bdfa2e9d 100644 --- a/blockprod/src/detail/tests/produce_block/mod.rs +++ b/blockprod/src/detail/tests/produce_block/mod.rs @@ -77,8 +77,9 @@ use crate::{ #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn initial_block_download() { - let (mut manager, chain_config, _, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (mut manager, _, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let chainstate_subsystem: ChainstateHandle = { let mut mock_chainstate = MockChainstateInterface::new(); @@ -133,8 +134,9 @@ async fn initial_block_download() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn below_peer_count() { - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -180,8 +182,9 @@ async fn below_peer_count() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn pull_best_block_index_error() { - let (mut manager, chain_config, _, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (mut manager, _, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let chainstate_subsystem: ChainstateHandle = { let mut mock_chainstate = Box::new(MockChainstateInterface::new()); @@ -244,8 +247,9 @@ async fn pull_best_block_index_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn add_job_error() { - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -316,12 +320,9 @@ async fn overflow_tip_plus_one(#[case] seed: Seed) { &mut rng, ); - let (manager, chain_config, chainstate, mempool, p2p) = { - setup_blockprod_test( - Some(build_chain_config_for_pos(chain_config_builder)), - TimeGetter::default(), - ) - }; + let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -381,12 +382,12 @@ async fn overflow_max_blocktimestamp(#[case] seed: Seed) { genesis_vrf_private_key, create_genesis_pool_txoutput, ) = setup_pos(&time_getter, BlockHeight::new(1), &[], &mut rng); - let chain_config = build_chain_config_for_pos( + let chain_config = Arc::new(build_chain_config_for_pos( chain_config_builder.max_future_block_time_offset(Some(Duration::MAX)), - ); + )); - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(Some(chain_config), TimeGetter::default()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -446,10 +447,9 @@ async fn update_last_used_block_timestamp(#[case] seed: Seed) { create_genesis_pool_txoutput, ) = setup_pos(&time_getter, BlockHeight::new(1), &[], &mut rng); - let (manager, chain_config, chainstate, mempool, p2p) = setup_blockprod_test( - Some(build_chain_config_for_pos(chain_config_builder)), - time_getter, - ); + let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), time_getter); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -525,7 +525,7 @@ async fn try_again_later(#[case] seed: Seed) { &mut rng, ); - let chain_config = build_chain_config_for_pos(chain_config_builder); + let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); let time_getter = { let cur_time_secs = genesis_time .saturating_duration_sub(chain_config.max_future_block_time_offset(BlockHeight::zero())) @@ -534,8 +534,8 @@ async fn try_again_later(#[case] seed: Seed) { mocked_time_getter_seconds(time_value) }; - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(Some(chain_config), time_getter.clone()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), time_getter.clone()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -583,8 +583,9 @@ async fn try_again_later(#[case] seed: Seed) { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn pull_consensus_data_error() { - let (mut manager, chain_config, _, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (mut manager, _, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let chainstate_subsystem: ChainstateHandle = { let mut mock_chainstate = MockChainstateInterface::new(); @@ -652,8 +653,9 @@ async fn pull_consensus_data_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_source_mempool_error() { - let (mut manager, chain_config, chainstate, _mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (mut manager, chainstate, _mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut mock_mempool = MockMempoolInterface::default(); @@ -708,8 +710,9 @@ async fn transaction_source_mempool_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_source_mempool() { - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -754,8 +757,9 @@ async fn transaction_source_mempool() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_source_provided() { - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -803,7 +807,7 @@ async fn transaction_source_provided() { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn cancel_received(#[case] seed: Seed) { - let override_chain_config = { + let chain_config = { let net_upgrades = NetUpgrades::initialize(vec![( BlockHeight::new(0), ConsensusUpgrade::PoW { @@ -815,11 +819,11 @@ async fn cancel_received(#[case] seed: Seed) { )]) .expect("Net upgrade is valid"); - Builder::new(ChainType::Regtest).consensus_upgrades(net_upgrades).build() + Arc::new(Builder::new(ChainType::Regtest).consensus_upgrades(net_upgrades).build()) }; - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(Some(override_chain_config), TimeGetter::default()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -885,8 +889,9 @@ async fn cancel_received(#[case] seed: Seed) { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn solved_ignore_consensus() { - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -930,7 +935,7 @@ async fn solved_ignore_consensus() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn solved_pow_consensus() { - let override_chain_config = { + let chain_config = { let net_upgrades = NetUpgrades::initialize(vec![( BlockHeight::new(0), ConsensusUpgrade::PoW { @@ -939,11 +944,11 @@ async fn solved_pow_consensus() { )]) .expect("Net upgrade is valid"); - Builder::new(ChainType::Regtest).consensus_upgrades(net_upgrades).build() + Arc::new(Builder::new(ChainType::Regtest).consensus_upgrades(net_upgrades).build()) }; - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(Some(override_chain_config), TimeGetter::default()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -1001,10 +1006,9 @@ async fn solved_pos_consensus(#[case] seed: Seed) { create_genesis_pool_txoutput, ) = setup_pos(&time_getter, BlockHeight::new(1), &[], &mut rng); - let (manager, chain_config, chainstate, mempool, p2p) = setup_blockprod_test( - Some(build_chain_config_for_pos(chain_config_builder)), - time_getter, - ); + let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), time_getter); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -1094,7 +1098,7 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { let blocks_to_generate = rng.random_range(100..=1000); - let override_chain_config = { + let chain_config = { let genesis_block = Genesis::new( "blockprod-testing".into(), make_genesis_timestamp(&time_getter, &mut rng), @@ -1133,14 +1137,16 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { let net_upgrades = NetUpgrades::initialize(randomized_net_upgrades).expect("Net upgrades are valid"); - Builder::new(ChainType::Regtest) - .genesis_custom(genesis_block) - .consensus_upgrades(net_upgrades) - .build() + Arc::new( + Builder::new(ChainType::Regtest) + .genesis_custom(genesis_block) + .consensus_upgrades(net_upgrades) + .build(), + ) }; - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(Some(override_chain_config), time_getter); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), time_getter); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -1342,8 +1348,9 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_with_wait(#[case] seed: Seed) { - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); diff --git a/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs b/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs index e57ab581f6..3f9fb3bd13 100644 --- a/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs +++ b/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs @@ -37,10 +37,10 @@ use common::{ use consensus::{PoSGenerateBlockInputData, PoWGenerateBlockInputData}; use mempool::{TxOptions, tx_accumulator::PackingStrategy, tx_origin::LocalTxOrigin}; use test_utils::{ - mock_time_getter::mocked_time_getter_seconds, + BasicTestTimeGetter, random::{Seed, make_seedable_rng}, }; -use utils::{atomics::SeqCstAtomicU64, once_destructor::OnceDestructor}; +use utils::once_destructor::OnceDestructor; use crate::{ BlockProduction, @@ -81,8 +81,9 @@ async fn transaction_selection_mtp_test_impl( time_getter: TimeGetter, genesis_premint_output_index: u32, ) { - let (manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(Some(chain_config), time_getter.clone()); + let chain_config = Arc::new(chain_config); + let (manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), time_getter.clone()); let genesis_timestamp = chain_config.genesis_block().timestamp(); let expected_median_time_past = genesis_timestamp.add_int_seconds(9).unwrap(); @@ -243,9 +244,7 @@ async fn transaction_selection_mtp_test_impl( #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_selection_mtp_test_pos(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); - let initial_time_value_secs = TimeGetter::default().get_time().as_secs_since_epoch(); - let initial_time_value = Arc::new(SeqCstAtomicU64::new(initial_time_value_secs)); - let time_getter = mocked_time_getter_seconds(Arc::clone(&initial_time_value)); + let time_getter = BasicTestTimeGetter::new().get_time_getter(); let extra_genesis_txs = [TxOutput::Transfer( OutputValue::Coin(Amount::from_atoms(1000 * CoinUnit::ATOMS_PER_COIN)), @@ -285,9 +284,7 @@ async fn transaction_selection_mtp_test_pos(#[case] seed: Seed) { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_selection_mtp_test_pow(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); - let initial_time_value_secs = TimeGetter::default().get_time().as_secs_since_epoch(); - let initial_time_value = Arc::new(SeqCstAtomicU64::new(initial_time_value_secs)); - let time_getter = mocked_time_getter_seconds(Arc::clone(&initial_time_value)); + let time_getter = BasicTestTimeGetter::new().get_time_getter(); let extra_genesis_txs = vec![TxOutput::Transfer( OutputValue::Coin(Amount::from_atoms(1000 * CoinUnit::ATOMS_PER_COIN)), @@ -332,9 +329,7 @@ async fn transaction_selection_mtp_test_pow(#[case] seed: Seed) { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_selection_mtp_test_ignore_consensus(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); - let initial_time_value_secs = TimeGetter::default().get_time().as_secs_since_epoch(); - let initial_time_value = Arc::new(SeqCstAtomicU64::new(initial_time_value_secs)); - let time_getter = mocked_time_getter_seconds(Arc::clone(&initial_time_value)); + let time_getter = BasicTestTimeGetter::new().get_time_getter(); let extra_genesis_txs = vec![TxOutput::Transfer( OutputValue::Coin(Amount::from_atoms(1000 * CoinUnit::ATOMS_PER_COIN)), diff --git a/blockprod/src/detail/tests/stop_jobs.rs b/blockprod/src/detail/tests/stop_jobs.rs index 2e32cdb525..c9ba5e45bf 100644 --- a/blockprod/src/detail/tests/stop_jobs.rs +++ b/blockprod/src/detail/tests/stop_jobs.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use rstest::rstest; -use common::time_getter::TimeGetter; +use common::{chain::config::create_unit_test_config, time_getter::TimeGetter}; use randomness::RngExt as _; use test_utils::random::{Seed, make_seedable_rng}; @@ -36,8 +36,9 @@ mod stop_all_jobs { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn error() { - let (_manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (_manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut block_production = BlockProduction::new( chain_config, @@ -72,8 +73,9 @@ mod stop_all_jobs { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn ok(#[case] seed: Seed) { - let (_manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (_manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); @@ -114,8 +116,9 @@ mod stop_all_jobs { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn mocked_ok(#[case] seed: Seed) { - let (_manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (_manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut block_production = BlockProduction::new( chain_config, @@ -153,8 +156,9 @@ mod stop_job { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn error(#[case] seed: Seed) { - let (_manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (_manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut block_production = BlockProduction::new( chain_config, @@ -192,8 +196,9 @@ mod stop_job { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn existing_job_ok(#[case] seed: Seed) { - let (_manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (_manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); @@ -234,8 +239,9 @@ mod stop_job { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_ok(#[case] seed: Seed) { - let (_manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (_manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); @@ -291,8 +297,9 @@ mod stop_job { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn non_existent_job_ok(#[case] seed: Seed) { - let (_manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (_manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); @@ -328,8 +335,9 @@ mod stop_job { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn mocked_ok(#[case] seed: Seed) { - let (_manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, TimeGetter::default()); + let chain_config = Arc::new(create_unit_test_config()); + let (_manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut block_production = BlockProduction::new( chain_config, diff --git a/blockprod/src/tests/helpers.rs b/blockprod/src/tests/helpers.rs index 99db18aaa4..50dc896e91 100644 --- a/blockprod/src/tests/helpers.rs +++ b/blockprod/src/tests/helpers.rs @@ -111,21 +111,13 @@ pub async fn assert_process_block( } pub fn setup_blockprod_test( - chain_config: Option, + chain_config: Arc, time_getter: TimeGetter, -) -> ( - Manager, - Arc, - ChainstateHandle, - MempoolHandle, - P2pHandle, -) { +) -> (Manager, ChainstateHandle, MempoolHandle, P2pHandle) { let manager_config = subsystem::ManagerConfig::new("blockprod-unit-test").enable_signal_handlers(); let mut manager = Manager::new_with_config(manager_config); - let chain_config = Arc::new(chain_config.unwrap_or_else(create_unit_test_config)); - let chainstate_config = ChainstateConfig { max_tip_age: Duration::from_secs(60 * 60 * 24 * 365 * 100).into(), // There is at least one long test in blockprod that gets significantly slowed down @@ -179,7 +171,7 @@ pub fn setup_blockprod_test( .expect("P2p initialization was successful") .add_to_manager("p2p", &mut manager); - (manager, chain_config, chainstate, mempool, p2p) + (manager, chainstate, mempool, p2p) } pub fn make_genesis_timestamp(time_getter: &TimeGetter, rng: &mut impl Rng) -> BlockTimestamp { diff --git a/blockprod/src/tests/mod.rs b/blockprod/src/tests/mod.rs index 40979c3268..d690bb5e63 100644 --- a/blockprod/src/tests/mod.rs +++ b/blockprod/src/tests/mod.rs @@ -17,15 +17,16 @@ pub mod helpers; use std::sync::Arc; -use common::time_getter::TimeGetter; +use common::{chain::config::create_unit_test_config, time_getter::TimeGetter}; use crate::{make_blockproduction, test_blockprod_config, tests::helpers::setup_blockprod_test}; #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_make_blockproduction() { let time_getter = TimeGetter::default(); - let (mut manager, chain_config, chainstate, mempool, p2p) = - setup_blockprod_test(None, time_getter.clone()); + let chain_config = Arc::new(create_unit_test_config()); + let (mut manager, chainstate, mempool, p2p) = + setup_blockprod_test(Arc::clone(&chain_config), time_getter.clone()); let blockprod = make_blockproduction( Arc::clone(&chain_config), From 1a77b700b5b05ce1f09ef5d5fcb8defc50bc34e2 Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Tue, 12 May 2026 12:28:37 +0300 Subject: [PATCH 3/9] Blockprod tests refactor - setup_pos/setup_pos_with_genesis_timestamp now accept a chain config builder and return ChainConfig. --- .../src/detail/tests/produce_block/mod.rs | 33 ++++++++++--------- .../tests/produce_block/tx_selection_mtp.rs | 30 +++++++++-------- blockprod/src/tests/helpers.rs | 24 +++++++++++--- 3 files changed, 52 insertions(+), 35 deletions(-) diff --git a/blockprod/src/detail/tests/produce_block/mod.rs b/blockprod/src/detail/tests/produce_block/mod.rs index d4bdfa2e9d..2acafe6e1b 100644 --- a/blockprod/src/detail/tests/produce_block/mod.rs +++ b/blockprod/src/detail/tests/produce_block/mod.rs @@ -70,7 +70,7 @@ use crate::{ }, prepare_thread_pool, test_blockprod_config, tests::helpers::{ - assert_process_block, build_chain_config_for_pos, make_genesis_timestamp, + assert_process_block, make_chain_config_builder, make_genesis_timestamp, setup_blockprod_test, setup_pos, setup_pos_with_genesis_timestamp, }, }; @@ -309,7 +309,7 @@ async fn overflow_tip_plus_one(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let ( - chain_config_builder, + chain_config, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_txoutput, @@ -317,10 +317,10 @@ async fn overflow_tip_plus_one(#[case] seed: Seed) { BlockTimestamp::from_int_seconds(u64::MAX), BlockHeight::new(1), &[], + None, &mut rng, ); - let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); let (manager, chainstate, mempool, p2p) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); @@ -377,14 +377,17 @@ async fn overflow_max_blocktimestamp(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let time_getter = TimeGetter::default(); let ( - chain_config_builder, + chain_config, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_txoutput, - ) = setup_pos(&time_getter, BlockHeight::new(1), &[], &mut rng); - let chain_config = Arc::new(build_chain_config_for_pos( - chain_config_builder.max_future_block_time_offset(Some(Duration::MAX)), - )); + ) = setup_pos( + &time_getter, + BlockHeight::new(1), + &[], + Some(make_chain_config_builder().max_future_block_time_offset(Some(Duration::MAX))), + &mut rng, + ); let (manager, chainstate, mempool, p2p) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); @@ -441,13 +444,12 @@ async fn update_last_used_block_timestamp(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let time_getter = TimeGetter::default(); let ( - chain_config_builder, + chain_config, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_txoutput, - ) = setup_pos(&time_getter, BlockHeight::new(1), &[], &mut rng); + ) = setup_pos(&time_getter, BlockHeight::new(1), &[], None, &mut rng); - let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); let (manager, chainstate, mempool, p2p) = setup_blockprod_test(Arc::clone(&chain_config), time_getter); @@ -514,7 +516,7 @@ async fn try_again_later(#[case] seed: Seed) { let genesis_time = default_time_getter.get_time(); let ( - chain_config_builder, + chain_config, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_txoutput, @@ -522,10 +524,10 @@ async fn try_again_later(#[case] seed: Seed) { BlockTimestamp::from_time(genesis_time), BlockHeight::new(1), &[], + None, &mut rng, ); - let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); let time_getter = { let cur_time_secs = genesis_time .saturating_duration_sub(chain_config.max_future_block_time_offset(BlockHeight::zero())) @@ -1000,13 +1002,12 @@ async fn solved_pos_consensus(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let time_getter = TimeGetter::default(); let ( - chain_config_builder, + chain_config, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_txoutput, - ) = setup_pos(&time_getter, BlockHeight::new(1), &[], &mut rng); + ) = setup_pos(&time_getter, BlockHeight::new(1), &[], None, &mut rng); - let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); let (manager, chainstate, mempool, p2p) = setup_blockprod_test(Arc::clone(&chain_config), time_getter); diff --git a/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs b/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs index 3f9fb3bd13..49652b90a9 100644 --- a/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs +++ b/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs @@ -47,8 +47,7 @@ use crate::{ detail::{GenerateBlockInputData, tests::produce_block::assert_job_count}, prepare_thread_pool, test_blockprod_config, tests::helpers::{ - assert_process_block, build_chain_config_for_pos, make_genesis_timestamp, - setup_blockprod_test, setup_pos, + assert_process_block, make_genesis_timestamp, setup_blockprod_test, setup_pos, }, }; @@ -76,12 +75,11 @@ const_assert!(TRANSACTION_SELECTION_MTP_TESTS_BLOCK_HEIGHT > chainstate::MEDIAN_ // b) The block contains the main tx and all dependent txs up to and including the one at // the "median time past" time. async fn transaction_selection_mtp_test_impl( - chain_config: ChainConfig, + chain_config: Arc, input_data: GenerateBlockInputData, time_getter: TimeGetter, genesis_premint_output_index: u32, ) { - let chain_config = Arc::new(chain_config); let (manager, chainstate, mempool, p2p) = setup_blockprod_test(Arc::clone(&chain_config), time_getter.clone()); @@ -252,7 +250,7 @@ async fn transaction_selection_mtp_test_pos(#[case] seed: Seed) { )]; let ( - chain_config_builder, + chain_config, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_txoutput, @@ -260,9 +258,9 @@ async fn transaction_selection_mtp_test_pos(#[case] seed: Seed) { &time_getter, BlockHeight::new(TRANSACTION_SELECTION_MTP_TESTS_BLOCK_HEIGHT as u64), &extra_genesis_txs, + None, &mut rng, ); - let chain_config = build_chain_config_for_pos(chain_config_builder); let input_data = GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( genesis_stake_private_key, @@ -310,10 +308,12 @@ async fn transaction_selection_mtp_test_pow(#[case] seed: Seed) { ]) .unwrap(); - Builder::new(ChainType::Regtest) - .genesis_custom(genesis) - .consensus_upgrades(net_upgrades) - .build() + Arc::new( + Builder::new(ChainType::Regtest) + .genesis_custom(genesis) + .consensus_upgrades(net_upgrades) + .build(), + ) }; let input_data = GenerateBlockInputData::PoW(Box::new(PoWGenerateBlockInputData::new( @@ -350,10 +350,12 @@ async fn transaction_selection_mtp_test_ignore_consensus(#[case] seed: Seed) { )]) .unwrap(); - Builder::new(ChainType::Regtest) - .genesis_custom(genesis) - .consensus_upgrades(net_upgrades) - .build() + Arc::new( + Builder::new(ChainType::Regtest) + .genesis_custom(genesis) + .consensus_upgrades(net_upgrades) + .build(), + ) }; transaction_selection_mtp_test_impl(chain_config, GenerateBlockInputData::None, time_getter, 0) diff --git a/blockprod/src/tests/helpers.rs b/blockprod/src/tests/helpers.rs index 50dc896e91..64a3fc2359 100644 --- a/blockprod/src/tests/helpers.rs +++ b/blockprod/src/tests/helpers.rs @@ -261,22 +261,34 @@ pub fn create_genesis_for_pos_tests( ) } +pub fn make_chain_config_builder() -> chain::config::Builder { + chain::config::Builder::new(ChainType::Regtest) +} + pub fn setup_pos( time_getter: &TimeGetter, switch_to_pos_at: BlockHeight, extra_genesis_txs: &[TxOutput], + chain_config_builder: Option, rng: &mut impl CryptoRng, -) -> (chain::config::Builder, PrivateKey, VRFPrivateKey, TxOutput) { +) -> (Arc, PrivateKey, VRFPrivateKey, TxOutput) { let genesis_timestamp = make_genesis_timestamp(time_getter, rng); - setup_pos_with_genesis_timestamp(genesis_timestamp, switch_to_pos_at, extra_genesis_txs, rng) + setup_pos_with_genesis_timestamp( + genesis_timestamp, + switch_to_pos_at, + extra_genesis_txs, + chain_config_builder, + rng, + ) } pub fn setup_pos_with_genesis_timestamp( genesis_timestamp: BlockTimestamp, switch_to_pos_at: BlockHeight, extra_genesis_txs: &[TxOutput], + chain_config_builder: Option, rng: &mut impl CryptoRng, -) -> (chain::config::Builder, PrivateKey, VRFPrivateKey, TxOutput) { +) -> (Arc, PrivateKey, VRFPrivateKey, TxOutput) { let initial_target = pos_initial_difficulty(ChainType::Regtest); let (genesis, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_txoutput) = @@ -294,12 +306,14 @@ pub fn setup_pos_with_genesis_timestamp( ]) .expect("Net upgrades are valid"); - let chain_config_builder = chain::config::Builder::new(ChainType::Regtest) + let chain_config_builder = chain_config_builder + .unwrap_or_else(make_chain_config_builder) .genesis_custom(genesis) .consensus_upgrades(net_upgrades); + let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); ( - chain_config_builder, + chain_config, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_txoutput, From c402a8f89cb402dd4d936ef6fdb5e05c3e056c28 Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Tue, 12 May 2026 12:27:56 +0300 Subject: [PATCH 4/9] Blockprod tests refactor - setup_pos/setup_pos_with_genesis_timestamp/setup_blockprod_test now return structs instead of tuples; introduce TestBlockProdBuilder --- .../src/detail/tests/collect_transactions.rs | 6 +- .../tests/process_block_with_custom_id.rs | 29 +- .../src/detail/tests/produce_block/mod.rs | 384 +++++------------- .../tests/produce_block/tx_selection_mtp.rs | 46 +-- blockprod/src/detail/tests/stop_jobs.rs | 107 +---- blockprod/src/tests/helpers.rs | 104 ++++- blockprod/src/tests/mod.rs | 14 +- 7 files changed, 248 insertions(+), 442 deletions(-) diff --git a/blockprod/src/detail/tests/collect_transactions.rs b/blockprod/src/detail/tests/collect_transactions.rs index f74d56e110..ee79578508 100644 --- a/blockprod/src/detail/tests/collect_transactions.rs +++ b/blockprod/src/detail/tests/collect_transactions.rs @@ -40,7 +40,7 @@ const DUMMY_TIMESTAMP: BlockTimestamp = BlockTimestamp::from_int_seconds(0u64); #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn collect_txs_failed() { let chain_config = Arc::new(create_unit_test_config()); - let (mut manager, _chainstate, _mempool, _p2p) = + let (_blockprod_setup, mut manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut mock_mempool = MockMempoolInterface::default(); @@ -83,7 +83,7 @@ async fn collect_txs_failed() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn subsystem_error() { let chain_config = Arc::new(create_unit_test_config()); - let (mut manager, _chainstate, _mempool, _p2p) = + let (_blockprod_setup, mut manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mock_mempool = MockMempoolInterface::default(); @@ -128,7 +128,7 @@ async fn subsystem_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn succeeded() { let chain_config = Arc::new(create_unit_test_config()); - let (mut manager, _chainstate, _mempool, _p2p) = + let (_blockprod_setup, mut manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut mock_mempool = MockMempoolInterface::default(); diff --git a/blockprod/src/detail/tests/process_block_with_custom_id.rs b/blockprod/src/detail/tests/process_block_with_custom_id.rs index 05939516e5..9be8795644 100644 --- a/blockprod/src/detail/tests/process_block_with_custom_id.rs +++ b/blockprod/src/detail/tests/process_block_with_custom_id.rs @@ -24,9 +24,8 @@ use test_utils::random::{Seed, make_seedable_rng}; use utils::once_destructor::OnceDestructor; use crate::{ - BlockProduction, BlockProductionError, + BlockProductionError, detail::{GenerateBlockInputData, job_manager::JobManagerError}, - prepare_thread_pool, test_blockprod_config, tests::helpers::setup_blockprod_test, }; @@ -36,23 +35,14 @@ use crate::{ #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_with_wait(#[case] seed: Seed) { let chain_config = Arc::new(create_unit_test_config()); - let (manager, chainstate, mempool, p2p) = + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); let jobs_to_create = rng.random_range(1..=20); - let block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -97,23 +87,14 @@ async fn multiple_jobs_with_wait(#[case] seed: Seed) { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_without_wait_same_jobkey(#[case] seed: Seed) { let chain_config = Arc::new(create_unit_test_config()); - let (manager, chainstate, mempool, p2p) = + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); let jobs_to_create = 10 + rng.random_range(1..=20); - let block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); diff --git a/blockprod/src/detail/tests/produce_block/mod.rs b/blockprod/src/detail/tests/produce_block/mod.rs index 2acafe6e1b..3a7c1e8bb0 100644 --- a/blockprod/src/detail/tests/produce_block/mod.rs +++ b/blockprod/src/detail/tests/produce_block/mod.rs @@ -24,8 +24,7 @@ use tokio::{ }; use chainstate::{ - ChainstateError, ChainstateHandle, GenBlockIndex, PropertyQueryError, - chainstate_interface::ChainstateInterface, + ChainstateError, GenBlockIndex, PropertyQueryError, chainstate_interface::ChainstateInterface, }; use common::{ Uint256, @@ -68,20 +67,20 @@ use crate::{ CustomId, GenerateBlockInputData, job_manager::{JobManagerError, JobManagerImpl, tests::MockJobManager}, }, - prepare_thread_pool, test_blockprod_config, + test_blockprod_config, tests::helpers::{ - assert_process_block, make_chain_config_builder, make_genesis_timestamp, - setup_blockprod_test, setup_pos, setup_pos_with_genesis_timestamp, + make_chain_config_builder, make_genesis_timestamp, setup_blockprod_test, setup_pos, + setup_pos_with_genesis_timestamp, }, }; #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn initial_block_download() { let chain_config = Arc::new(create_unit_test_config()); - let (mut manager, _, mempool, p2p) = + let (blockprod_setup, mut manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); - let chainstate_subsystem: ChainstateHandle = { + let mock_chainstate = { let mut mock_chainstate = MockChainstateInterface::new(); mock_chainstate.expect_is_initial_block_download().returning(|| true); @@ -101,16 +100,10 @@ async fn initial_block_download() { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate_subsystem, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup + .make_blockprod_builder() + .with_chainstate(mock_chainstate) + .build(); let result = block_production .produce_block( @@ -135,7 +128,7 @@ async fn initial_block_download() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn below_peer_count() { let chain_config = Arc::new(create_unit_test_config()); - let (manager, chainstate, mempool, p2p) = + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ @@ -149,16 +142,10 @@ async fn below_peer_count() { let mut blockprod_config = test_blockprod_config(); blockprod_config.min_peers_to_produce_blocks = 100; - let block_production = BlockProduction::new( - chain_config, - Arc::new(blockprod_config), - chainstate, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup + .make_blockprod_builder() + .with_blockprod_config(blockprod_config) + .build(); let result = block_production .produce_block( @@ -183,10 +170,10 @@ async fn below_peer_count() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn pull_best_block_index_error() { let chain_config = Arc::new(create_unit_test_config()); - let (mut manager, _, mempool, p2p) = + let (blockprod_setup, mut manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); - let chainstate_subsystem: ChainstateHandle = { + let mock_chainstate = { let mut mock_chainstate = Box::new(MockChainstateInterface::new()); mock_chainstate .expect_subscribe_to_subsystem_events() @@ -212,16 +199,10 @@ async fn pull_best_block_index_error() { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate_subsystem, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup + .make_blockprod_builder() + .with_chainstate(mock_chainstate) + .build(); let result = block_production .produce_block( @@ -248,7 +229,7 @@ async fn pull_best_block_index_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn add_job_error() { let chain_config = Arc::new(create_unit_test_config()); - let (manager, chainstate, mempool, p2p) = + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ @@ -259,16 +240,7 @@ async fn add_job_error() { shutdown_trigger.initiate(); }); - let mut block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let mut block_production = blockprod_setup.make_blockprod_builder().build(); let mut mock_job_manager = Box::new(MockJobManager::new()); @@ -308,12 +280,7 @@ async fn add_job_error() { async fn overflow_tip_plus_one(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); - let ( - chain_config, - genesis_stake_private_key, - genesis_vrf_private_key, - create_genesis_pool_txoutput, - ) = setup_pos_with_genesis_timestamp( + let pos_setup = setup_pos_with_genesis_timestamp( BlockTimestamp::from_int_seconds(u64::MAX), BlockHeight::new(1), &[], @@ -321,8 +288,8 @@ async fn overflow_tip_plus_one(#[case] seed: Seed) { &mut rng, ); - let (manager, chainstate, mempool, p2p) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = + setup_blockprod_test(Arc::clone(&pos_setup.chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -333,26 +300,17 @@ async fn overflow_tip_plus_one(#[case] seed: Seed) { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - Arc::clone(&chain_config), - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let input_data = GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( - genesis_stake_private_key, - genesis_vrf_private_key, + pos_setup.genesis_stake_private_key, + pos_setup.genesis_vrf_private_key, PoolId::new(H256::zero()), vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(chain_config.genesis_block_id()), + OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), 0, )], - vec![create_genesis_pool_txoutput], + vec![pos_setup.create_genesis_pool_utxo], ))); let result = block_production @@ -376,12 +334,7 @@ async fn overflow_tip_plus_one(#[case] seed: Seed) { async fn overflow_max_blocktimestamp(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let time_getter = TimeGetter::default(); - let ( - chain_config, - genesis_stake_private_key, - genesis_vrf_private_key, - create_genesis_pool_txoutput, - ) = setup_pos( + let pos_setup = setup_pos( &time_getter, BlockHeight::new(1), &[], @@ -389,8 +342,8 @@ async fn overflow_max_blocktimestamp(#[case] seed: Seed) { &mut rng, ); - let (manager, chainstate, mempool, p2p) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = + setup_blockprod_test(Arc::clone(&pos_setup.chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -400,26 +353,17 @@ async fn overflow_max_blocktimestamp(#[case] seed: Seed) { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - Arc::clone(&chain_config), - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let input_data = GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( - genesis_stake_private_key, - genesis_vrf_private_key, + pos_setup.genesis_stake_private_key, + pos_setup.genesis_vrf_private_key, PoolId::new(H256::zero()), vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(chain_config.genesis_block_id()), + OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), 0, )], - vec![create_genesis_pool_txoutput], + vec![pos_setup.create_genesis_pool_utxo], ))); let result = block_production @@ -443,15 +387,10 @@ async fn overflow_max_blocktimestamp(#[case] seed: Seed) { async fn update_last_used_block_timestamp(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let time_getter = TimeGetter::default(); - let ( - chain_config, - genesis_stake_private_key, - genesis_vrf_private_key, - create_genesis_pool_txoutput, - ) = setup_pos(&time_getter, BlockHeight::new(1), &[], None, &mut rng); + let pos_setup = setup_pos(&time_getter, BlockHeight::new(1), &[], None, &mut rng); - let (manager, chainstate, mempool, p2p) = - setup_blockprod_test(Arc::clone(&chain_config), time_getter); + let (blockprod_setup, manager) = + setup_blockprod_test(Arc::clone(&pos_setup.chain_config), time_getter); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -461,26 +400,17 @@ async fn update_last_used_block_timestamp(#[case] seed: Seed) { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config.clone(), - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let input_data = GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( - genesis_stake_private_key, - genesis_vrf_private_key, + pos_setup.genesis_stake_private_key, + pos_setup.genesis_vrf_private_key, PoolId::new(H256::zero()), vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(chain_config.genesis_block_id()), + OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), 0, )], - vec![create_genesis_pool_txoutput], + vec![pos_setup.create_genesis_pool_utxo], ))); let _ = block_production @@ -515,12 +445,7 @@ async fn try_again_later(#[case] seed: Seed) { let default_time_getter = TimeGetter::default(); let genesis_time = default_time_getter.get_time(); - let ( - chain_config, - genesis_stake_private_key, - genesis_vrf_private_key, - create_genesis_pool_txoutput, - ) = setup_pos_with_genesis_timestamp( + let pos_setup = setup_pos_with_genesis_timestamp( BlockTimestamp::from_time(genesis_time), BlockHeight::new(1), &[], @@ -530,14 +455,16 @@ async fn try_again_later(#[case] seed: Seed) { let time_getter = { let cur_time_secs = genesis_time - .saturating_duration_sub(chain_config.max_future_block_time_offset(BlockHeight::zero())) + .saturating_duration_sub( + pos_setup.chain_config.max_future_block_time_offset(BlockHeight::zero()), + ) .as_secs_since_epoch(); let time_value = Arc::new(SeqCstAtomicU64::new(cur_time_secs)); mocked_time_getter_seconds(time_value) }; - let (manager, chainstate, mempool, p2p) = - setup_blockprod_test(Arc::clone(&chain_config), time_getter.clone()); + let (blockprod_setup, manager) = + setup_blockprod_test(Arc::clone(&pos_setup.chain_config), time_getter.clone()); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -547,26 +474,17 @@ async fn try_again_later(#[case] seed: Seed) { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - Arc::clone(&chain_config), - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool, - p2p, - time_getter, - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let input_data = GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( - genesis_stake_private_key, - genesis_vrf_private_key, + pos_setup.genesis_stake_private_key, + pos_setup.genesis_vrf_private_key, PoolId::new(H256::zero()), vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(chain_config.genesis_block_id()), + OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), 0, )], - vec![create_genesis_pool_txoutput], + vec![pos_setup.create_genesis_pool_utxo], ))); let result = block_production @@ -586,10 +504,10 @@ async fn try_again_later(#[case] seed: Seed) { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn pull_consensus_data_error() { let chain_config = Arc::new(create_unit_test_config()); - let (mut manager, _, mempool, p2p) = + let (blockprod_setup, mut manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); - let chainstate_subsystem: ChainstateHandle = { + let mock_chainstate = { let mut mock_chainstate = MockChainstateInterface::new(); mock_chainstate .expect_subscribe_to_subsystem_events() @@ -620,16 +538,10 @@ async fn pull_consensus_data_error() { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate_subsystem, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup + .make_blockprod_builder() + .with_chainstate(mock_chainstate) + .build(); let result = block_production .produce_block( @@ -656,18 +568,20 @@ async fn pull_consensus_data_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_source_mempool_error() { let chain_config = Arc::new(create_unit_test_config()); - let (mut manager, chainstate, _mempool, p2p) = + let (blockprod_setup, mut manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); - let mut mock_mempool = MockMempoolInterface::default(); + let mock_mempool = { + let mut mock_mempool = MockMempoolInterface::default(); - mock_mempool.expect_collect_txs().return_once(|_, _, _| { - Err(BlockConstructionError::Validity( - TxValidationError::SubsystemCallError(ResponseError::NoResponse.into()), - )) - }); + mock_mempool.expect_collect_txs().return_once(|_, _, _| { + Err(BlockConstructionError::Validity( + TxValidationError::SubsystemCallError(ResponseError::NoResponse.into()), + )) + }); - let mempool_subsystem = manager.add_subsystem("mock-mempool", mock_mempool); + manager.add_subsystem("mock-mempool", mock_mempool) + }; let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -677,16 +591,8 @@ async fn transaction_source_mempool_error() { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool_subsystem, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = + blockprod_setup.make_blockprod_builder().with_mempool(mock_mempool).build(); let result = block_production .produce_block( @@ -713,7 +619,7 @@ async fn transaction_source_mempool_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_source_mempool() { let chain_config = Arc::new(create_unit_test_config()); - let (manager, chainstate, mempool, p2p) = + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ @@ -724,16 +630,7 @@ async fn transaction_source_mempool() { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool.clone(), - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let (new_block, job_finished_receiver) = block_production // TODO: Add transactions to the mempool @@ -749,7 +646,7 @@ async fn transaction_source_mempool() { job_finished_receiver.await.expect("Job finished receiver closed"); assert_job_count(&block_production, 0).await; - assert_process_block(&chainstate, &mempool, new_block).await; + blockprod_setup.assert_process_block(new_block).await; } }); @@ -760,7 +657,7 @@ async fn transaction_source_mempool() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_source_provided() { let chain_config = Arc::new(create_unit_test_config()); - let (manager, chainstate, mempool, p2p) = + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ @@ -771,16 +668,7 @@ async fn transaction_source_provided() { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool.clone(), - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let (new_block, job_finished_receiver) = block_production // TODO: Add transactions to the parameters @@ -796,7 +684,7 @@ async fn transaction_source_provided() { job_finished_receiver.await.expect("Job finished receiver closed"); assert_job_count(&block_production, 0).await; - assert_process_block(&chainstate, &mempool, new_block).await; + blockprod_setup.assert_process_block(new_block).await; } }); @@ -824,7 +712,7 @@ async fn cancel_received(#[case] seed: Seed) { Arc::new(Builder::new(ChainType::Regtest).consensus_upgrades(net_upgrades).build()) }; - let (manager, chainstate, mempool, p2p) = + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ @@ -835,16 +723,7 @@ async fn cancel_received(#[case] seed: Seed) { shutdown_trigger.initiate(); }); - let mut block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let mut block_production = blockprod_setup.make_blockprod_builder().build(); let mut mock_job_manager = Box::::default(); @@ -892,7 +771,7 @@ async fn cancel_received(#[case] seed: Seed) { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn solved_ignore_consensus() { let chain_config = Arc::new(create_unit_test_config()); - let (manager, chainstate, mempool, p2p) = + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ @@ -903,16 +782,7 @@ async fn solved_ignore_consensus() { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool.clone(), - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let (new_block, job_finished_receiver) = block_production .produce_block( @@ -927,7 +797,7 @@ async fn solved_ignore_consensus() { job_finished_receiver.await.expect("Job finished receiver closed"); assert_job_count(&block_production, 0).await; - assert_process_block(&chainstate, &mempool, new_block).await; + blockprod_setup.assert_process_block(new_block).await; } }); @@ -949,7 +819,7 @@ async fn solved_pow_consensus() { Arc::new(Builder::new(ChainType::Regtest).consensus_upgrades(net_upgrades).build()) }; - let (manager, chainstate, mempool, p2p) = + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ @@ -960,16 +830,7 @@ async fn solved_pow_consensus() { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool.clone(), - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let (new_block, job_finished_receiver) = block_production .produce_block( @@ -986,7 +847,7 @@ async fn solved_pow_consensus() { job_finished_receiver.await.expect("Job finished receiver closed"); assert_job_count(&block_production, 0).await; - assert_process_block(&chainstate, &mempool, new_block).await; + blockprod_setup.assert_process_block(new_block).await; } }); @@ -1001,15 +862,10 @@ async fn solved_pow_consensus() { async fn solved_pos_consensus(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let time_getter = TimeGetter::default(); - let ( - chain_config, - genesis_stake_private_key, - genesis_vrf_private_key, - create_genesis_pool_txoutput, - ) = setup_pos(&time_getter, BlockHeight::new(1), &[], None, &mut rng); + let pos_setup = setup_pos(&time_getter, BlockHeight::new(1), &[], None, &mut rng); - let (manager, chainstate, mempool, p2p) = - setup_blockprod_test(Arc::clone(&chain_config), time_getter); + let (blockprod_setup, manager) = + setup_blockprod_test(Arc::clone(&pos_setup.chain_config), time_getter); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -1019,26 +875,17 @@ async fn solved_pos_consensus(#[case] seed: Seed) { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config.clone(), - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool.clone(), - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let input_data = Box::new(PoSGenerateBlockInputData::new( - genesis_stake_private_key, - genesis_vrf_private_key, + pos_setup.genesis_stake_private_key, + pos_setup.genesis_vrf_private_key, PoolId::new(H256::zero()), vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(chain_config.genesis_block_id()), + OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), 0, )], - vec![create_genesis_pool_txoutput], + vec![pos_setup.create_genesis_pool_utxo], )); let (new_block, job_finished_receiver) = block_production @@ -1054,7 +901,7 @@ async fn solved_pos_consensus(#[case] seed: Seed) { job_finished_receiver.await.expect("Job finished receiver closed"); assert_job_count(&block_production, 0).await; - assert_process_block(&chainstate, &mempool, new_block).await; + blockprod_setup.assert_process_block(new_block).await; } }); @@ -1146,8 +993,7 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { ) }; - let (manager, chainstate, mempool, p2p) = - setup_blockprod_test(Arc::clone(&chain_config), time_getter); + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), time_getter); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -1157,16 +1003,7 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { shutdown_trigger.initiate(); }); - let mut block_production = BlockProduction::new( - chain_config.clone(), - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool.clone(), - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let mut block_production = blockprod_setup.make_blockprod_builder().build(); let no_chainstate_job_manager = Box::new(JobManagerImpl::new(None)); block_production.set_job_manager(no_chainstate_job_manager); @@ -1207,7 +1044,7 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { job_finished_receiver.await.expect("Job finished receiver closed"); - assert_process_block(&chainstate, &mempool, new_block.clone()).await; + blockprod_setup.assert_process_block(new_block.clone()).await; } RequiredConsensus::PoS(_) => { // Try no input data for PoS consensus @@ -1264,7 +1101,7 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { job_finished_receiver.await.expect("Job finished receiver closed"); - let result = assert_process_block(&chainstate, &mempool, new_block).await; + let result = blockprod_setup.assert_process_block(new_block).await; // Update kernel input parameters for future PoS blocks @@ -1333,7 +1170,7 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { job_finished_receiver.await.expect("Job finished receiver closed"); - assert_process_block(&chainstate, &mempool, new_block.clone()).await; + blockprod_setup.assert_process_block(new_block.clone()).await; } } } @@ -1350,7 +1187,7 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_with_wait(#[case] seed: Seed) { let chain_config = Arc::new(create_unit_test_config()); - let (manager, chainstate, mempool, p2p) = + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let join_handle = tokio::spawn({ @@ -1361,16 +1198,7 @@ async fn multiple_jobs_with_wait(#[case] seed: Seed) { shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let block_production = blockprod_setup.make_blockprod_builder().build(); let mut rng = make_seedable_rng(seed); let jobs_to_create = rng.random_range(1..=20); diff --git a/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs b/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs index 49652b90a9..532958ecc2 100644 --- a/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs +++ b/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs @@ -43,12 +43,8 @@ use test_utils::{ use utils::once_destructor::OnceDestructor; use crate::{ - BlockProduction, detail::{GenerateBlockInputData, tests::produce_block::assert_job_count}, - prepare_thread_pool, test_blockprod_config, - tests::helpers::{ - assert_process_block, make_genesis_timestamp, setup_blockprod_test, setup_pos, - }, + tests::helpers::{make_genesis_timestamp, setup_blockprod_test, setup_pos}, }; // The height at which the transaction_selection_mtp_xxx tests will create their test block. @@ -80,7 +76,7 @@ async fn transaction_selection_mtp_test_impl( time_getter: TimeGetter, genesis_premint_output_index: u32, ) { - let (manager, chainstate, mempool, p2p) = + let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), time_getter.clone()); let genesis_timestamp = chain_config.genesis_block().timestamp(); @@ -94,16 +90,7 @@ async fn transaction_selection_mtp_test_impl( shutdown_trigger.initiate(); }); - let block_production = BlockProduction::new( - chain_config.clone(), - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool.clone(), - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .unwrap(); + let block_production = blockprod_setup.make_blockprod_builder().build(); for i in 1..TRANSACTION_SELECTION_MTP_TESTS_BLOCK_HEIGHT { let (new_block, job_finished_receiver) = block_production @@ -122,10 +109,11 @@ async fn transaction_selection_mtp_test_impl( assert_eq!(new_block.timestamp(), expected_timestamp); assert_job_count(&block_production, 0).await; - assert_process_block(&chainstate, &mempool, new_block).await; + blockprod_setup.assert_process_block(new_block).await; } - let median_time_past = chainstate + let median_time_past = blockprod_setup + .chainstate .call(|cs| cs.calculate_median_time_past(&cs.get_best_block_id().unwrap())) .await .unwrap() @@ -181,7 +169,8 @@ async fn transaction_selection_mtp_test_impl( txs }; - mempool + blockprod_setup + .mempool .call_mut({ let dependent_txs = dependent_txs.clone(); |mp| { @@ -220,7 +209,7 @@ async fn transaction_selection_mtp_test_impl( assert_job_count(&block_production, 0).await; // First ensure that the produced block is actually correct. - assert_process_block(&chainstate, &mempool, new_block).await; + blockprod_setup.assert_process_block(new_block).await; // Now check the transaction ids. let expected_tx_ids = dependent_txs[..=timestamp_offsets_count as usize] @@ -249,12 +238,7 @@ async fn transaction_selection_mtp_test_pos(#[case] seed: Seed) { Destination::AnyoneCanSpend, )]; - let ( - chain_config, - genesis_stake_private_key, - genesis_vrf_private_key, - create_genesis_pool_txoutput, - ) = setup_pos( + let pos_setup = setup_pos( &time_getter, BlockHeight::new(TRANSACTION_SELECTION_MTP_TESTS_BLOCK_HEIGHT as u64), &extra_genesis_txs, @@ -263,17 +247,17 @@ async fn transaction_selection_mtp_test_pos(#[case] seed: Seed) { ); let input_data = GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( - genesis_stake_private_key, - genesis_vrf_private_key, + pos_setup.genesis_stake_private_key, + pos_setup.genesis_vrf_private_key, PoolId::new(H256::zero()), vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(chain_config.genesis_block_id()), + OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), 0, )], - vec![create_genesis_pool_txoutput], + vec![pos_setup.create_genesis_pool_utxo], ))); - transaction_selection_mtp_test_impl(chain_config, input_data, time_getter, 1).await; + transaction_selection_mtp_test_impl(pos_setup.chain_config, input_data, time_getter, 1).await; } #[rstest] diff --git a/blockprod/src/detail/tests/stop_jobs.rs b/blockprod/src/detail/tests/stop_jobs.rs index c9ba5e45bf..f0a5e85eaf 100644 --- a/blockprod/src/detail/tests/stop_jobs.rs +++ b/blockprod/src/detail/tests/stop_jobs.rs @@ -22,12 +22,11 @@ use randomness::RngExt as _; use test_utils::random::{Seed, make_seedable_rng}; use crate::{ - BlockProduction, BlockProductionError, JobKey, + BlockProductionError, JobKey, detail::{ CustomId, job_manager::{JobManagerError, tests::MockJobManager}, }, - prepare_thread_pool, test_blockprod_config, tests::helpers::setup_blockprod_test, }; @@ -37,19 +36,10 @@ mod stop_all_jobs { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn error() { let chain_config = Arc::new(create_unit_test_config()); - let (_manager, chainstate, mempool, p2p) = + let (blockprod_setup, _manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); - let mut block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let mut block_production = blockprod_setup.make_blockprod_builder().build(); let mut mock_job_manager = Box::::default(); @@ -74,21 +64,12 @@ mod stop_all_jobs { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn ok(#[case] seed: Seed) { let chain_config = Arc::new(create_unit_test_config()); - let (_manager, chainstate, mempool, p2p) = + let (blockprod_setup, _manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); - let mut block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let mut block_production = blockprod_setup.make_blockprod_builder().build(); let (_other_job_key, _other_last_used_block_timestamp, _other_job_cancel_receiver) = block_production @@ -117,19 +98,10 @@ mod stop_all_jobs { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn mocked_ok(#[case] seed: Seed) { let chain_config = Arc::new(create_unit_test_config()); - let (_manager, chainstate, mempool, p2p) = + let (blockprod_setup, _manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); - let mut block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let mut block_production = blockprod_setup.make_blockprod_builder().build(); let mut mock_job_manager = Box::::default(); let return_value = make_seedable_rng(seed).random_range(0..=usize::MAX); @@ -157,19 +129,10 @@ mod stop_job { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn error(#[case] seed: Seed) { let chain_config = Arc::new(create_unit_test_config()); - let (_manager, chainstate, mempool, p2p) = + let (blockprod_setup, _manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); - let mut block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let mut block_production = blockprod_setup.make_blockprod_builder().build(); let mut mock_job_manager = Box::::default(); @@ -197,21 +160,12 @@ mod stop_job { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn existing_job_ok(#[case] seed: Seed) { let chain_config = Arc::new(create_unit_test_config()); - let (_manager, chainstate, mempool, p2p) = + let (blockprod_setup, _manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); - let mut block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let mut block_production = blockprod_setup.make_blockprod_builder().build(); let (_other_job_key, _other_last_used_block_timestamp, _other_job_cancel_receiver) = block_production @@ -240,21 +194,12 @@ mod stop_job { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_ok(#[case] seed: Seed) { let chain_config = Arc::new(create_unit_test_config()); - let (_manager, chainstate, mempool, p2p) = + let (blockprod_setup, _manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); - let mut block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let mut block_production = blockprod_setup.make_blockprod_builder().build(); let mut job_keys = Vec::new(); let jobs_to_create = rng.random_range(1..=20); @@ -298,21 +243,12 @@ mod stop_job { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn non_existent_job_ok(#[case] seed: Seed) { let chain_config = Arc::new(create_unit_test_config()); - let (_manager, chainstate, mempool, p2p) = + let (blockprod_setup, _manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); let mut rng = make_seedable_rng(seed); - let mut block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate, - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let mut block_production = blockprod_setup.make_blockprod_builder().build(); let (_other_job_key, _other_last_used_block_timestamp, _other_job_cancel_receiver) = block_production @@ -336,19 +272,10 @@ mod stop_job { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn mocked_ok(#[case] seed: Seed) { let chain_config = Arc::new(create_unit_test_config()); - let (_manager, chainstate, mempool, p2p) = + let (blockprod_setup, _manager) = setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); - let mut block_production = BlockProduction::new( - chain_config, - Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool, - p2p, - Default::default(), - prepare_thread_pool(1), - ) - .expect("Error initializing blockprod"); + let mut block_production = blockprod_setup.make_blockprod_builder().build(); let mut mock_job_manager = Box::::default(); diff --git a/blockprod/src/tests/helpers.rs b/blockprod/src/tests/helpers.rs index 64a3fc2359..71360779f0 100644 --- a/blockprod/src/tests/helpers.rs +++ b/blockprod/src/tests/helpers.rs @@ -50,6 +50,83 @@ use randomness::{CryptoRng, Rng, RngExt as _}; use storage_inmemory::InMemory; use subsystem::Manager; +use crate::{ + config::BlockProdConfig, detail::BlockProduction, prepare_thread_pool, test_blockprod_config, +}; + +pub struct BlockProdTestSetup { + pub chain_config: Arc, + pub time_getter: TimeGetter, + pub chainstate: ChainstateHandle, + pub mempool: MempoolHandle, + pub p2p: P2pHandle, +} + +impl BlockProdTestSetup { + pub async fn assert_process_block(&self, new_block: Block) -> BlockIndex { + assert_process_block(&self.chainstate, &self.mempool, new_block).await + } +} + +impl BlockProdTestSetup { + pub fn make_blockprod_builder(&self) -> TestBlockProdBuilder<'_> { + TestBlockProdBuilder { + blockprod_setup: self, + blockprod_config: None, + chainstate: None, + mempool: None, + } + } +} + +pub struct PosTestSetup { + pub chain_config: Arc, + pub genesis_stake_private_key: PrivateKey, + pub genesis_vrf_private_key: VRFPrivateKey, + pub create_genesis_pool_utxo: TxOutput, +} + +pub struct TestBlockProdBuilder<'a> { + blockprod_setup: &'a BlockProdTestSetup, + blockprod_config: Option, + chainstate: Option, + mempool: Option, +} + +impl<'a> TestBlockProdBuilder<'a> { + pub fn with_blockprod_config(mut self, blockprod_config: BlockProdConfig) -> Self { + self.blockprod_config = Some(blockprod_config); + self + } + + pub fn with_chainstate(mut self, chainstate: ChainstateHandle) -> Self { + self.chainstate = Some(chainstate); + self + } + + pub fn with_mempool(mut self, mempool: MempoolHandle) -> Self { + self.mempool = Some(mempool); + self + } + + pub fn build(self) -> BlockProduction { + let blockprod_config = self.blockprod_config.unwrap_or_else(test_blockprod_config); + let chainstate = self.chainstate.unwrap_or_else(|| self.blockprod_setup.chainstate.clone()); + let mempool = self.mempool.unwrap_or_else(|| self.blockprod_setup.mempool.clone()); + + BlockProduction::new( + Arc::clone(&self.blockprod_setup.chain_config), + Arc::new(blockprod_config), + chainstate, + mempool, + self.blockprod_setup.p2p.clone(), + self.blockprod_setup.time_getter.clone(), + prepare_thread_pool(1), + ) + .unwrap() + } +} + pub async fn assert_process_block( chainstate: &ChainstateHandle, mempool: &MempoolHandle, @@ -113,7 +190,7 @@ pub async fn assert_process_block( pub fn setup_blockprod_test( chain_config: Arc, time_getter: TimeGetter, -) -> (Manager, ChainstateHandle, MempoolHandle, P2pHandle) { +) -> (BlockProdTestSetup, Manager) { let manager_config = subsystem::ManagerConfig::new("blockprod-unit-test").enable_signal_handlers(); let mut manager = Manager::new_with_config(manager_config); @@ -164,14 +241,23 @@ pub fn setup_blockprod_test( Arc::new(p2p_config), subsystem::Handle::clone(&chainstate), mempool.clone(), - time_getter, + time_getter.clone(), MonotonicTimeGetter::default(), PeerDbStorageImpl::new(InMemory::new()).unwrap(), ) .expect("P2p initialization was successful") .add_to_manager("p2p", &mut manager); - (manager, chainstate, mempool, p2p) + ( + BlockProdTestSetup { + chain_config, + time_getter, + chainstate, + mempool, + p2p, + }, + manager, + ) } pub fn make_genesis_timestamp(time_getter: &TimeGetter, rng: &mut impl Rng) -> BlockTimestamp { @@ -271,7 +357,7 @@ pub fn setup_pos( extra_genesis_txs: &[TxOutput], chain_config_builder: Option, rng: &mut impl CryptoRng, -) -> (Arc, PrivateKey, VRFPrivateKey, TxOutput) { +) -> PosTestSetup { let genesis_timestamp = make_genesis_timestamp(time_getter, rng); setup_pos_with_genesis_timestamp( genesis_timestamp, @@ -288,10 +374,10 @@ pub fn setup_pos_with_genesis_timestamp( extra_genesis_txs: &[TxOutput], chain_config_builder: Option, rng: &mut impl CryptoRng, -) -> (Arc, PrivateKey, VRFPrivateKey, TxOutput) { +) -> PosTestSetup { let initial_target = pos_initial_difficulty(ChainType::Regtest); - let (genesis, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_txoutput) = + let (genesis, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_utxo) = create_genesis_for_pos_tests(genesis_timestamp, extra_genesis_txs, rng); let net_upgrades = NetUpgrades::initialize(vec![ @@ -312,12 +398,12 @@ pub fn setup_pos_with_genesis_timestamp( .consensus_upgrades(net_upgrades); let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); - ( + PosTestSetup { chain_config, genesis_stake_private_key, genesis_vrf_private_key, - create_genesis_pool_txoutput, - ) + create_genesis_pool_utxo, + } } pub fn build_chain_config_for_pos(builder: chain::config::Builder) -> ChainConfig { diff --git a/blockprod/src/tests/mod.rs b/blockprod/src/tests/mod.rs index d690bb5e63..3d79396bae 100644 --- a/blockprod/src/tests/mod.rs +++ b/blockprod/src/tests/mod.rs @@ -25,16 +25,16 @@ use crate::{make_blockproduction, test_blockprod_config, tests::helpers::setup_b async fn test_make_blockproduction() { let time_getter = TimeGetter::default(); let chain_config = Arc::new(create_unit_test_config()); - let (mut manager, chainstate, mempool, p2p) = - setup_blockprod_test(Arc::clone(&chain_config), time_getter.clone()); + let (blockprod_setup, mut manager) = + setup_blockprod_test(Arc::clone(&chain_config), time_getter); let blockprod = make_blockproduction( - Arc::clone(&chain_config), + Arc::clone(&blockprod_setup.chain_config), Arc::new(test_blockprod_config()), - chainstate.clone(), - mempool.clone(), - p2p.clone(), - time_getter, + blockprod_setup.chainstate.clone(), + blockprod_setup.mempool.clone(), + blockprod_setup.p2p.clone(), + blockprod_setup.time_getter, ) .expect("Error initializing blockprod"); From a4dff2a758ccfa20844c67549f727a2e4bd52aa0 Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Thu, 7 May 2026 20:48:12 +0300 Subject: [PATCH 5/9] Blockprod tests refactor - replace useless "expect"s with "unwrap". --- .../src/detail/tests/collect_transactions.rs | 2 +- .../src/detail/tests/produce_block/mod.rs | 41 +++++++++---------- blockprod/src/tests/helpers.rs | 23 +++++------ blockprod/src/tests/mod.rs | 4 +- 4 files changed, 33 insertions(+), 37 deletions(-) diff --git a/blockprod/src/detail/tests/collect_transactions.rs b/blockprod/src/detail/tests/collect_transactions.rs index ee79578508..eb219e8713 100644 --- a/blockprod/src/detail/tests/collect_transactions.rs +++ b/blockprod/src/detail/tests/collect_transactions.rs @@ -122,7 +122,7 @@ async fn subsystem_error() { }; }) .await - .expect("Subsystem error thread failed"); + .unwrap(); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] diff --git a/blockprod/src/detail/tests/produce_block/mod.rs b/blockprod/src/detail/tests/produce_block/mod.rs index 3a7c1e8bb0..61a0f1263a 100644 --- a/blockprod/src/detail/tests/produce_block/mod.rs +++ b/blockprod/src/detail/tests/produce_block/mod.rs @@ -641,9 +641,9 @@ async fn transaction_source_mempool() { PackingStrategy::FillSpaceFromMempool, ) .await - .expect("Failed to produce a block: {:?}"); + .unwrap(); - job_finished_receiver.await.expect("Job finished receiver closed"); + job_finished_receiver.await.unwrap(); assert_job_count(&block_production, 0).await; blockprod_setup.assert_process_block(new_block).await; @@ -679,9 +679,9 @@ async fn transaction_source_provided() { PackingStrategy::LeaveEmptySpace, ) .await - .expect("Failed to produce a block: {:?}"); + .unwrap(); - job_finished_receiver.await.expect("Job finished receiver closed"); + job_finished_receiver.await.unwrap(); assert_job_count(&block_production, 0).await; blockprod_setup.assert_process_block(new_block).await; @@ -707,7 +707,7 @@ async fn cancel_received(#[case] seed: Seed) { initial_difficulty: Uint256::ZERO.into(), }, )]) - .expect("Net upgrade is valid"); + .unwrap(); Arc::new(Builder::new(ChainType::Regtest).consensus_upgrades(net_upgrades).build()) }; @@ -792,9 +792,9 @@ async fn solved_ignore_consensus() { PackingStrategy::LeaveEmptySpace, ) .await - .expect("Failed to produce a block: {:?}"); + .unwrap(); - job_finished_receiver.await.expect("Job finished receiver closed"); + job_finished_receiver.await.unwrap(); assert_job_count(&block_production, 0).await; blockprod_setup.assert_process_block(new_block).await; @@ -814,7 +814,7 @@ async fn solved_pow_consensus() { initial_difficulty: Uint256::MAX.into(), }, )]) - .expect("Net upgrade is valid"); + .unwrap(); Arc::new(Builder::new(ChainType::Regtest).consensus_upgrades(net_upgrades).build()) }; @@ -842,9 +842,9 @@ async fn solved_pow_consensus() { PackingStrategy::LeaveEmptySpace, ) .await - .expect("Failed to produce a block: {:?}"); + .unwrap(); - job_finished_receiver.await.expect("Job finished receiver closed"); + job_finished_receiver.await.unwrap(); assert_job_count(&block_production, 0).await; blockprod_setup.assert_process_block(new_block).await; @@ -896,9 +896,9 @@ async fn solved_pos_consensus(#[case] seed: Seed) { PackingStrategy::LeaveEmptySpace, ) .await - .expect("Failed to produce a block: {:?}"); + .unwrap(); - job_finished_receiver.await.expect("Job finished receiver closed"); + job_finished_receiver.await.unwrap(); assert_job_count(&block_production, 0).await; blockprod_setup.assert_process_block(new_block).await; @@ -938,7 +938,7 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { Destination::PublicKey(genesis_stake_public_key.clone()), genesis_vrf_public_key, Destination::PublicKey(genesis_stake_public_key.clone()), - PerThousand::new(1000).expect("Valid per thousand"), + PerThousand::new(1000).unwrap(), Amount::ZERO, )), ) @@ -982,8 +982,7 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { next_height_consensus_change += rng.random_range(1..50); } - let net_upgrades = - NetUpgrades::initialize(randomized_net_upgrades).expect("Net upgrades are valid"); + let net_upgrades = NetUpgrades::initialize(randomized_net_upgrades).unwrap(); Arc::new( Builder::new(ChainType::Regtest) @@ -1040,9 +1039,9 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { PackingStrategy::LeaveEmptySpace, ) .await - .expect("Failed to produce a block: {:?}"); + .unwrap(); - job_finished_receiver.await.expect("Job finished receiver closed"); + job_finished_receiver.await.unwrap(); blockprod_setup.assert_process_block(new_block.clone()).await; } @@ -1097,9 +1096,9 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { PackingStrategy::LeaveEmptySpace, ) .await - .expect("Failed to produce a job: {:?}"); + .unwrap(); - job_finished_receiver.await.expect("Job finished receiver closed"); + job_finished_receiver.await.unwrap(); let result = blockprod_setup.assert_process_block(new_block).await; @@ -1166,9 +1165,9 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { PackingStrategy::LeaveEmptySpace, ) .await - .expect("Failed to produce a block: {:?}"); + .unwrap(); - job_finished_receiver.await.expect("Job finished receiver closed"); + job_finished_receiver.await.unwrap(); blockprod_setup.assert_process_block(new_block.clone()).await; } diff --git a/blockprod/src/tests/helpers.rs b/blockprod/src/tests/helpers.rs index 71360779f0..a0312434f5 100644 --- a/blockprod/src/tests/helpers.rs +++ b/blockprod/src/tests/helpers.rs @@ -157,10 +157,8 @@ pub async fn assert_process_block( let block_index = chainstate .call_mut(move |this| { - let new_block_index = this - .process_block(new_block.clone(), BlockSource::Local) - .expect("Failed to process block") - .expect("Failed to activate best chain"); + let new_block_index = + this.process_block(new_block.clone(), BlockSource::Local).unwrap().unwrap(); assert_eq!( new_block.header().header().block_id(), @@ -168,8 +166,7 @@ pub async fn assert_process_block( "The new block's Id is different to the new block index's block Id", ); - let best_block_index = - this.get_best_block_index().expect("Failed to get best block index"); + let best_block_index = this.get_best_block_index().unwrap(); assert_eq!( new_block_index.clone().into_gen_block_index().block_id(), @@ -180,7 +177,7 @@ pub async fn assert_process_block( new_block_index }) .await - .expect("New block is not the new tip"); + .unwrap(); tip_rx.await.unwrap(); @@ -213,13 +210,13 @@ pub fn setup_blockprod_test( let chainstate = chainstate::make_chainstate( Arc::clone(&chain_config), chainstate_config, - Store::new_empty().expect("Error initializing empty store"), + Store::new_empty().unwrap(), DefaultTransactionVerificationStrategy::new(), None, time_getter.clone(), None, ) - .expect("Error initializing chainstate"); + .unwrap(); let chainstate = manager.add_subsystem("chainstate", chainstate); @@ -245,7 +242,7 @@ pub fn setup_blockprod_test( MonotonicTimeGetter::default(), PeerDbStorageImpl::new(InMemory::new()).unwrap(), ) - .expect("P2p initialization was successful") + .unwrap() .add_to_manager("p2p", &mut manager); ( @@ -268,7 +265,7 @@ pub fn make_genesis_timestamp(time_getter: &TimeGetter, rng: &mut impl Rng) -> B rng.random_range(60 * 60 * 24..60 * 60 * 24 * 14), 0, )) - .expect("No time underflow") + .unwrap() .as_secs_since_epoch(), ) } @@ -328,7 +325,7 @@ pub fn create_genesis_for_pos_tests( Destination::PublicKey(stake_public_key.clone()), vrf_public_key, Destination::PublicKey(stake_public_key), - PerThousand::new(1000).expect("Valid per thousand"), + PerThousand::new(1000).unwrap(), Amount::ZERO, )), ) @@ -390,7 +387,7 @@ pub fn setup_pos_with_genesis_timestamp( }, ), ]) - .expect("Net upgrades are valid"); + .unwrap(); let chain_config_builder = chain_config_builder .unwrap_or_else(make_chain_config_builder) diff --git a/blockprod/src/tests/mod.rs b/blockprod/src/tests/mod.rs index 3d79396bae..7956cd93fb 100644 --- a/blockprod/src/tests/mod.rs +++ b/blockprod/src/tests/mod.rs @@ -36,7 +36,7 @@ async fn test_make_blockproduction() { blockprod_setup.p2p.clone(), blockprod_setup.time_getter, ) - .expect("Error initializing blockprod"); + .unwrap(); let blockprod = manager.add_direct_subsystem("blockprod", blockprod); let shutdown = manager.make_shutdown_trigger(); @@ -56,7 +56,7 @@ async fn test_make_blockproduction() { }) }) .await - .expect("Error initializing block production"); + .unwrap(); }); manager.main().await; From 9f80254eb2b1d6ddab3dfa787bfe5274c9a1849c Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Tue, 12 May 2026 12:27:09 +0300 Subject: [PATCH 6/9] Blockprod tests refactor - replace explicit match+panic with assert_matches or assert_eq. --- .../src/detail/tests/collect_transactions.rs | 9 +- .../src/detail/tests/produce_block/mod.rs | 131 +++++++++--------- blockprod/src/detail/tests/stop_jobs.rs | 15 +- 3 files changed, 77 insertions(+), 78 deletions(-) diff --git a/blockprod/src/detail/tests/collect_transactions.rs b/blockprod/src/detail/tests/collect_transactions.rs index eb219e8713..9af0865280 100644 --- a/blockprod/src/detail/tests/collect_transactions.rs +++ b/blockprod/src/detail/tests/collect_transactions.rs @@ -26,6 +26,7 @@ use mempool::{ }; use mocks::MockMempoolInterface; use subsystem::error::ResponseError; +use test_utils::assert_matches; use utils::once_destructor::OnceDestructor; use crate::{ @@ -67,12 +68,12 @@ async fn collect_txs_failed() { ) .await; - match transactions { + assert_matches!( + transactions, Err(BlockProductionError::MempoolBlockConstruction( BlockConstructionError::Validity(TxValidationError::SubsystemCallError(_)), - )) => {} - _ => panic!("Expected collect_tx() to fail"), - }; + )) + ); shutdown.initiate(); }); diff --git a/blockprod/src/detail/tests/produce_block/mod.rs b/blockprod/src/detail/tests/produce_block/mod.rs index 61a0f1263a..c365f94fb4 100644 --- a/blockprod/src/detail/tests/produce_block/mod.rs +++ b/blockprod/src/detail/tests/produce_block/mod.rs @@ -105,19 +105,17 @@ async fn initial_block_download() { .with_chainstate(mock_chainstate) .build(); - let result = block_production + let err = block_production .produce_block( GenerateBlockInputData::None, vec![], vec![], PackingStrategy::FillSpaceFromMempool, ) - .await; + .await + .unwrap_err(); - match result { - Err(BlockProductionError::ChainstateWaitForSync) => {} - _ => panic!("Unexpected return value"), - } + assert_eq!(err, BlockProductionError::ChainstateWaitForSync); } }); @@ -147,19 +145,20 @@ async fn below_peer_count() { .with_blockprod_config(blockprod_config) .build(); - let result = block_production + let err = block_production .produce_block( GenerateBlockInputData::None, vec![], vec![], PackingStrategy::LeaveEmptySpace, ) - .await; + .await + .unwrap_err(); - match result { - Err(BlockProductionError::PeerCountBelowRequiredThreshold(0, 100)) => {} - _ => panic!("Unexpected return value"), - } + assert_eq!( + err, + BlockProductionError::PeerCountBelowRequiredThreshold(0, 100) + ); } }); @@ -213,12 +212,12 @@ async fn pull_best_block_index_error() { ) .await; - match result { + assert_matches!( + result, Err(BlockProductionError::ChainstateError( consensus::ChainstateError::FailedToObtainBestBlockIndex(_), - )) => {} - _ => panic!("Unexpected return value"), - } + )) + ); } }); @@ -251,21 +250,20 @@ async fn add_job_error() { block_production.set_job_manager(mock_job_manager); - let result = block_production + let err = block_production .produce_block( GenerateBlockInputData::None, vec![], vec![], PackingStrategy::LeaveEmptySpace, ) - .await; + .await + .unwrap_err(); - match result { - Err(BlockProductionError::JobManagerError( - JobManagerError::FailedToSendNewJobEvent, - )) => {} - _ => panic!("Unexpected return value"), - } + assert_eq!( + err, + BlockProductionError::JobManagerError(JobManagerError::FailedToSendNewJobEvent,) + ); } }); @@ -487,11 +485,12 @@ async fn try_again_later(#[case] seed: Seed) { vec![pos_setup.create_genesis_pool_utxo], ))); - let result = block_production + let err = block_production .produce_block(input_data, vec![], vec![], PackingStrategy::LeaveEmptySpace) - .await; + .await + .unwrap_err(); - assert_matches!(result, Err(BlockProductionError::TryAgainLater)); + assert_eq!(err, BlockProductionError::TryAgainLater); assert_job_count(&block_production, 0).await; } @@ -603,12 +602,12 @@ async fn transaction_source_mempool_error() { ) .await; - match result { + assert_matches!( + result, Err(BlockProductionError::MempoolBlockConstruction( BlockConstructionError::Validity(TxValidationError::SubsystemCallError(_)), - )) => {} - _ => panic!("Unexpected return value: {result:?}"), - } + )) + ); } }); @@ -746,7 +745,7 @@ async fn cancel_received(#[case] seed: Seed) { block_production.set_job_manager(mock_job_manager); - let result = block_production + let err = block_production .produce_block( GenerateBlockInputData::PoW(Box::new(PoWGenerateBlockInputData::new( Destination::AnyoneCanSpend, @@ -755,12 +754,10 @@ async fn cancel_received(#[case] seed: Seed) { vec![], PackingStrategy::LeaveEmptySpace, ) - .await; + .await + .unwrap_err(); - match result { - Err(BlockProductionError::Cancelled) => {} - _ => panic!("Unexpected return value"), - } + assert_eq!(err, BlockProductionError::Cancelled); } }); @@ -1048,43 +1045,45 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { RequiredConsensus::PoS(_) => { // Try no input data for PoS consensus - let input_data_none_result = block_production + let input_data_none_err = block_production .produce_block( GenerateBlockInputData::None, vec![], vec![], PackingStrategy::LeaveEmptySpace, ) - .await; + .await + .unwrap_err(); - match input_data_none_result { - Err(BlockProductionError::FailedConsensusInitialization( + assert_eq!( + input_data_none_err, + BlockProductionError::FailedConsensusInitialization( ConsensusCreationError::StakingError( ConsensusPoSError::NoInputDataProvided, ), - )) => {} - _ => panic!("Unexpected return value"), - } + ) + ); // Try PoW input data for PoS consensus - let input_data_pow_result = block_production + let input_data_pow_err = block_production .produce_block( input_data_pow, vec![], vec![], PackingStrategy::LeaveEmptySpace, ) - .await; + .await + .unwrap_err(); - match input_data_pow_result { - Err(BlockProductionError::FailedConsensusInitialization( + assert_eq!( + input_data_pow_err, + BlockProductionError::FailedConsensusInitialization( ConsensusCreationError::StakingError( ConsensusPoSError::PoWInputDataProvided, ), - )) => {} - _ => panic!("Unexpected return value"), - } + ) + ); // Try PoS input data for PoS consensus @@ -1117,43 +1116,45 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { RequiredConsensus::PoW(_) => { // Try no input data for PoW consensus - let input_data_none_result = block_production + let input_data_none_err = block_production .produce_block( GenerateBlockInputData::None, vec![], vec![], PackingStrategy::LeaveEmptySpace, ) - .await; + .await + .unwrap_err(); - match input_data_none_result { - Err(BlockProductionError::FailedConsensusInitialization( + assert_eq!( + input_data_none_err, + BlockProductionError::FailedConsensusInitialization( ConsensusCreationError::MiningError( ConsensusPoWError::NoInputDataProvided, ), - )) => {} - _ => panic!("Unexpected return value"), - } + ) + ); // Try PoS input data for PoW consensus - let input_data_pos_result = block_production + let input_data_pos_err = block_production .produce_block( input_data_pos, vec![], vec![], PackingStrategy::LeaveEmptySpace, ) - .await; + .await + .unwrap_err(); - match input_data_pos_result { - Err(BlockProductionError::FailedConsensusInitialization( + assert_eq!( + input_data_pos_err, + BlockProductionError::FailedConsensusInitialization( ConsensusCreationError::MiningError( ConsensusPoWError::PoSInputDataProvided, ), - )) => {} - _ => panic!("Unexpected return value"), - } + ) + ); // Try PoW input data for PoW consensus diff --git a/blockprod/src/detail/tests/stop_jobs.rs b/blockprod/src/detail/tests/stop_jobs.rs index f0a5e85eaf..7d4082cc92 100644 --- a/blockprod/src/detail/tests/stop_jobs.rs +++ b/blockprod/src/detail/tests/stop_jobs.rs @@ -19,7 +19,10 @@ use rstest::rstest; use common::{chain::config::create_unit_test_config, time_getter::TimeGetter}; use randomness::RngExt as _; -use test_utils::random::{Seed, make_seedable_rng}; +use test_utils::{ + assert_matches, + random::{Seed, make_seedable_rng}, +}; use crate::{ BlockProductionError, JobKey, @@ -52,10 +55,7 @@ mod stop_all_jobs { let result = block_production.stop_all_jobs().await; - match result { - Err(BlockProductionError::JobManagerError(_)) => {} - _ => panic!("Unexpected return value"), - } + assert_matches!(result, Err(BlockProductionError::JobManagerError(_))); } #[rstest] @@ -148,10 +148,7 @@ mod stop_job { let result = block_production.stop_job(job_key).await; - match result { - Err(BlockProductionError::JobManagerError(_)) => {} - _ => panic!("Unexpected return value"), - } + assert_matches!(result, Err(BlockProductionError::JobManagerError(_))); } #[rstest] From f0df88564205fcae5b9e41435aa7933276c78f8b Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Tue, 12 May 2026 12:26:18 +0300 Subject: [PATCH 7/9] Blockprod tests refactor: replace setup_blockprod_test with BlockprodTestSetupBuilder --- .../src/detail/tests/collect_transactions.rs | 25 +-- .../tests/process_block_with_custom_id.rs | 13 +- .../src/detail/tests/produce_block/mod.rs | 88 ++++----- .../tests/produce_block/tx_selection_mtp.rs | 8 +- blockprod/src/detail/tests/stop_jobs.rs | 37 +--- blockprod/src/tests/helpers.rs | 183 ++++++++++-------- blockprod/src/tests/mod.rs | 11 +- 7 files changed, 177 insertions(+), 188 deletions(-) diff --git a/blockprod/src/detail/tests/collect_transactions.rs b/blockprod/src/detail/tests/collect_transactions.rs index 9af0865280..b0913371cd 100644 --- a/blockprod/src/detail/tests/collect_transactions.rs +++ b/blockprod/src/detail/tests/collect_transactions.rs @@ -13,12 +13,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::Arc; - use common::{ - chain::{block::timestamp::BlockTimestamp, config::create_unit_test_config}, + chain::block::timestamp::BlockTimestamp, primitives::{H256, Id}, - time_getter::TimeGetter, }; use mempool::{ error::{BlockConstructionError, TxValidationError}, @@ -30,7 +27,7 @@ use test_utils::assert_matches; use utils::once_destructor::OnceDestructor; use crate::{ - BlockProductionError, detail::collect_transactions, tests::helpers::setup_blockprod_test, + BlockProductionError, detail::collect_transactions, tests::helpers::BlockprodTestSetupBuilder, }; // A dummy timestamp for tests where the block timestamp is irrelevant @@ -40,9 +37,7 @@ const DUMMY_TIMESTAMP: BlockTimestamp = BlockTimestamp::from_int_seconds(0u64); #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn collect_txs_failed() { - let chain_config = Arc::new(create_unit_test_config()); - let (_blockprod_setup, mut manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, mut manager) = BlockprodTestSetupBuilder::new().build(); let mut mock_mempool = MockMempoolInterface::default(); mock_mempool.expect_collect_txs().return_once(|_, _, _| { @@ -59,7 +54,7 @@ async fn collect_txs_failed() { let tester = tokio::spawn(async move { let transactions = collect_transactions( &mock_mempool_subsystem, - &chain_config, + &blockprod_setup.chain_config, current_tip, DUMMY_TIMESTAMP, vec![], @@ -83,9 +78,7 @@ async fn collect_txs_failed() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn subsystem_error() { - let chain_config = Arc::new(create_unit_test_config()); - let (_blockprod_setup, mut manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, mut manager) = BlockprodTestSetupBuilder::new().build(); let mock_mempool = MockMempoolInterface::default(); let mock_mempool_subsystem = manager.add_subsystem("mock-mempool", mock_mempool); @@ -107,7 +100,7 @@ async fn subsystem_error() { tokio::spawn(async move { let transactions = collect_transactions( &mock_mempool_subsystem, - &chain_config, + &blockprod_setup.chain_config, current_tip, DUMMY_TIMESTAMP, vec![], @@ -128,9 +121,7 @@ async fn subsystem_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn succeeded() { - let chain_config = Arc::new(create_unit_test_config()); - let (_blockprod_setup, mut manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, mut manager) = BlockprodTestSetupBuilder::new().build(); let mut mock_mempool = MockMempoolInterface::default(); @@ -159,7 +150,7 @@ async fn succeeded() { let transactions = collect_transactions( &mock_mempool_subsystem, - &chain_config, + &blockprod_setup.chain_config, current_tip, DUMMY_TIMESTAMP, vec![], diff --git a/blockprod/src/detail/tests/process_block_with_custom_id.rs b/blockprod/src/detail/tests/process_block_with_custom_id.rs index 9be8795644..1e1ac4373f 100644 --- a/blockprod/src/detail/tests/process_block_with_custom_id.rs +++ b/blockprod/src/detail/tests/process_block_with_custom_id.rs @@ -13,11 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::Arc; - use rstest::rstest; -use common::{chain::config::create_unit_test_config, time_getter::TimeGetter}; use mempool::tx_accumulator::PackingStrategy; use randomness::RngExt as _; use test_utils::random::{Seed, make_seedable_rng}; @@ -26,7 +23,7 @@ use utils::once_destructor::OnceDestructor; use crate::{ BlockProductionError, detail::{GenerateBlockInputData, job_manager::JobManagerError}, - tests::helpers::setup_blockprod_test, + tests::helpers::BlockprodTestSetupBuilder, }; #[rstest] @@ -34,9 +31,7 @@ use crate::{ #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_with_wait(#[case] seed: Seed) { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new().build(); let mut rng = make_seedable_rng(seed); @@ -86,9 +81,7 @@ async fn multiple_jobs_with_wait(#[case] seed: Seed) { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_without_wait_same_jobkey(#[case] seed: Seed) { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new().build(); let mut rng = make_seedable_rng(seed); diff --git a/blockprod/src/detail/tests/produce_block/mod.rs b/blockprod/src/detail/tests/produce_block/mod.rs index c365f94fb4..f89d12cbd9 100644 --- a/blockprod/src/detail/tests/produce_block/mod.rs +++ b/blockprod/src/detail/tests/produce_block/mod.rs @@ -69,16 +69,14 @@ use crate::{ }, test_blockprod_config, tests::helpers::{ - make_chain_config_builder, make_genesis_timestamp, setup_blockprod_test, setup_pos, + BlockprodTestSetupBuilder, make_chain_config_builder, make_genesis_timestamp, setup_pos, setup_pos_with_genesis_timestamp, }, }; #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn initial_block_download() { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, mut manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, mut manager) = BlockprodTestSetupBuilder::new().build(); let mock_chainstate = { let mut mock_chainstate = MockChainstateInterface::new(); @@ -125,9 +123,7 @@ async fn initial_block_download() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn below_peer_count() { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new().build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -168,9 +164,7 @@ async fn below_peer_count() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn pull_best_block_index_error() { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, mut manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, mut manager) = BlockprodTestSetupBuilder::new().build(); let mock_chainstate = { let mut mock_chainstate = Box::new(MockChainstateInterface::new()); @@ -227,9 +221,7 @@ async fn pull_best_block_index_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn add_job_error() { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new().build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -286,8 +278,9 @@ async fn overflow_tip_plus_one(#[case] seed: Seed) { &mut rng, ); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&pos_setup.chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() + .with_chain_config(Arc::clone(&pos_setup.chain_config)) + .build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -340,8 +333,10 @@ async fn overflow_max_blocktimestamp(#[case] seed: Seed) { &mut rng, ); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&pos_setup.chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() + .with_chain_config(Arc::clone(&pos_setup.chain_config)) + .with_time_getter(time_getter) + .build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -387,8 +382,10 @@ async fn update_last_used_block_timestamp(#[case] seed: Seed) { let time_getter = TimeGetter::default(); let pos_setup = setup_pos(&time_getter, BlockHeight::new(1), &[], None, &mut rng); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&pos_setup.chain_config), time_getter); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() + .with_chain_config(Arc::clone(&pos_setup.chain_config)) + .with_time_getter(time_getter) + .build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -461,8 +458,10 @@ async fn try_again_later(#[case] seed: Seed) { mocked_time_getter_seconds(time_value) }; - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&pos_setup.chain_config), time_getter.clone()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() + .with_chain_config(Arc::clone(&pos_setup.chain_config)) + .with_time_getter(time_getter) + .build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -502,9 +501,7 @@ async fn try_again_later(#[case] seed: Seed) { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn pull_consensus_data_error() { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, mut manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, mut manager) = BlockprodTestSetupBuilder::new().build(); let mock_chainstate = { let mut mock_chainstate = MockChainstateInterface::new(); @@ -515,7 +512,7 @@ async fn pull_consensus_data_error() { mock_chainstate.expect_is_initial_block_download().returning(|| false); let mut expected_return_values = vec![ - Ok(GenBlockIndex::genesis(&chain_config)), + Ok(GenBlockIndex::genesis(&blockprod_setup.chain_config)), Err(ChainstateError::FailedToReadProperty( PropertyQueryError::BestBlockIndexNotFound, )), @@ -566,9 +563,7 @@ async fn pull_consensus_data_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_source_mempool_error() { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, mut manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, mut manager) = BlockprodTestSetupBuilder::new().build(); let mock_mempool = { let mut mock_mempool = MockMempoolInterface::default(); @@ -617,9 +612,7 @@ async fn transaction_source_mempool_error() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_source_mempool() { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new().build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -655,9 +648,7 @@ async fn transaction_source_mempool() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn transaction_source_provided() { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new().build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -711,8 +702,9 @@ async fn cancel_received(#[case] seed: Seed) { Arc::new(Builder::new(ChainType::Regtest).consensus_upgrades(net_upgrades).build()) }; - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() + .with_chain_config(Arc::clone(&chain_config)) + .build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -767,9 +759,7 @@ async fn cancel_received(#[case] seed: Seed) { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn solved_ignore_consensus() { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new().build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -816,8 +806,9 @@ async fn solved_pow_consensus() { Arc::new(Builder::new(ChainType::Regtest).consensus_upgrades(net_upgrades).build()) }; - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() + .with_chain_config(Arc::clone(&chain_config)) + .build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -861,8 +852,10 @@ async fn solved_pos_consensus(#[case] seed: Seed) { let time_getter = TimeGetter::default(); let pos_setup = setup_pos(&time_getter, BlockHeight::new(1), &[], None, &mut rng); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&pos_setup.chain_config), time_getter); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() + .with_chain_config(Arc::clone(&pos_setup.chain_config)) + .with_time_getter(time_getter) + .build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -989,7 +982,10 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { ) }; - let (blockprod_setup, manager) = setup_blockprod_test(Arc::clone(&chain_config), time_getter); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() + .with_chain_config(Arc::clone(&chain_config)) + .with_time_getter(time_getter) + .build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); @@ -1186,9 +1182,7 @@ async fn solve_lots_of_blocks_with_differing_consensus(#[case] seed: Seed) { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_with_wait(#[case] seed: Seed) { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new().build(); let join_handle = tokio::spawn({ let shutdown_trigger = manager.make_shutdown_trigger(); diff --git a/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs b/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs index 532958ecc2..3f86330d82 100644 --- a/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs +++ b/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs @@ -44,7 +44,7 @@ use utils::once_destructor::OnceDestructor; use crate::{ detail::{GenerateBlockInputData, tests::produce_block::assert_job_count}, - tests::helpers::{make_genesis_timestamp, setup_blockprod_test, setup_pos}, + tests::helpers::{BlockprodTestSetupBuilder, make_genesis_timestamp, setup_pos}, }; // The height at which the transaction_selection_mtp_xxx tests will create their test block. @@ -76,8 +76,10 @@ async fn transaction_selection_mtp_test_impl( time_getter: TimeGetter, genesis_premint_output_index: u32, ) { - let (blockprod_setup, manager) = - setup_blockprod_test(Arc::clone(&chain_config), time_getter.clone()); + let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() + .with_chain_config(Arc::clone(&chain_config)) + .with_time_getter(time_getter.clone()) + .build(); let genesis_timestamp = chain_config.genesis_block().timestamp(); let expected_median_time_past = genesis_timestamp.add_int_seconds(9).unwrap(); diff --git a/blockprod/src/detail/tests/stop_jobs.rs b/blockprod/src/detail/tests/stop_jobs.rs index 7d4082cc92..aaee3085e6 100644 --- a/blockprod/src/detail/tests/stop_jobs.rs +++ b/blockprod/src/detail/tests/stop_jobs.rs @@ -13,11 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::Arc; - use rstest::rstest; -use common::{chain::config::create_unit_test_config, time_getter::TimeGetter}; use randomness::RngExt as _; use test_utils::{ assert_matches, @@ -30,7 +27,7 @@ use crate::{ CustomId, job_manager::{JobManagerError, tests::MockJobManager}, }, - tests::helpers::setup_blockprod_test, + tests::helpers::BlockprodTestSetupBuilder, }; mod stop_all_jobs { @@ -38,9 +35,7 @@ mod stop_all_jobs { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn error() { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, _manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, _manager) = BlockprodTestSetupBuilder::new().build(); let mut block_production = blockprod_setup.make_blockprod_builder().build(); @@ -63,9 +58,7 @@ mod stop_all_jobs { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn ok(#[case] seed: Seed) { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, _manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, _manager) = BlockprodTestSetupBuilder::new().build(); let mut rng = make_seedable_rng(seed); @@ -97,9 +90,7 @@ mod stop_all_jobs { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn mocked_ok(#[case] seed: Seed) { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, _manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, _manager) = BlockprodTestSetupBuilder::new().build(); let mut block_production = blockprod_setup.make_blockprod_builder().build(); @@ -128,9 +119,7 @@ mod stop_job { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn error(#[case] seed: Seed) { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, _manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, _manager) = BlockprodTestSetupBuilder::new().build(); let mut block_production = blockprod_setup.make_blockprod_builder().build(); @@ -156,9 +145,7 @@ mod stop_job { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn existing_job_ok(#[case] seed: Seed) { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, _manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, _manager) = BlockprodTestSetupBuilder::new().build(); let mut rng = make_seedable_rng(seed); @@ -190,9 +177,7 @@ mod stop_job { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn multiple_jobs_ok(#[case] seed: Seed) { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, _manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, _manager) = BlockprodTestSetupBuilder::new().build(); let mut rng = make_seedable_rng(seed); @@ -239,9 +224,7 @@ mod stop_job { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn non_existent_job_ok(#[case] seed: Seed) { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, _manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, _manager) = BlockprodTestSetupBuilder::new().build(); let mut rng = make_seedable_rng(seed); @@ -268,9 +251,7 @@ mod stop_job { #[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn mocked_ok(#[case] seed: Seed) { - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, _manager) = - setup_blockprod_test(Arc::clone(&chain_config), TimeGetter::default()); + let (blockprod_setup, _manager) = BlockprodTestSetupBuilder::new().build(); let mut block_production = blockprod_setup.make_blockprod_builder().build(); diff --git a/blockprod/src/tests/helpers.rs b/blockprod/src/tests/helpers.rs index a0312434f5..b7ecf86e4d 100644 --- a/blockprod/src/tests/helpers.rs +++ b/blockprod/src/tests/helpers.rs @@ -54,7 +54,12 @@ use crate::{ config::BlockProdConfig, detail::BlockProduction, prepare_thread_pool, test_blockprod_config, }; -pub struct BlockProdTestSetup { +/// A collection of objects needed to run a blockprod test. +/// +/// Note that the subsystem manager is not a part of it; this is because in most tests +/// the test setup object will be moved into a separate tokio task where BlockProduction +/// will be created and tested, while the manager object has to remain outside the task. +pub struct BlockprodTestSetup { pub chain_config: Arc, pub time_getter: TimeGetter, pub chainstate: ChainstateHandle, @@ -62,16 +67,16 @@ pub struct BlockProdTestSetup { pub p2p: P2pHandle, } -impl BlockProdTestSetup { +impl BlockprodTestSetup { pub async fn assert_process_block(&self, new_block: Block) -> BlockIndex { assert_process_block(&self.chainstate, &self.mempool, new_block).await } } -impl BlockProdTestSetup { +impl BlockprodTestSetup { pub fn make_blockprod_builder(&self) -> TestBlockProdBuilder<'_> { TestBlockProdBuilder { - blockprod_setup: self, + test_setup: self, blockprod_config: None, chainstate: None, mempool: None, @@ -86,8 +91,9 @@ pub struct PosTestSetup { pub create_genesis_pool_utxo: TxOutput, } +/// A builder that produces `BlockProduction` from `BlockprodTestSetup` with some optional overrides. pub struct TestBlockProdBuilder<'a> { - blockprod_setup: &'a BlockProdTestSetup, + test_setup: &'a BlockprodTestSetup, blockprod_config: Option, chainstate: Option, mempool: Option, @@ -111,16 +117,16 @@ impl<'a> TestBlockProdBuilder<'a> { pub fn build(self) -> BlockProduction { let blockprod_config = self.blockprod_config.unwrap_or_else(test_blockprod_config); - let chainstate = self.chainstate.unwrap_or_else(|| self.blockprod_setup.chainstate.clone()); - let mempool = self.mempool.unwrap_or_else(|| self.blockprod_setup.mempool.clone()); + let chainstate = self.chainstate.unwrap_or_else(|| self.test_setup.chainstate.clone()); + let mempool = self.mempool.unwrap_or_else(|| self.test_setup.mempool.clone()); BlockProduction::new( - Arc::clone(&self.blockprod_setup.chain_config), + Arc::clone(&self.test_setup.chain_config), Arc::new(blockprod_config), chainstate, mempool, - self.blockprod_setup.p2p.clone(), - self.blockprod_setup.time_getter.clone(), + self.test_setup.p2p.clone(), + self.test_setup.time_getter.clone(), prepare_thread_pool(1), ) .unwrap() @@ -184,77 +190,102 @@ pub async fn assert_process_block( block_index } -pub fn setup_blockprod_test( - chain_config: Arc, - time_getter: TimeGetter, -) -> (BlockProdTestSetup, Manager) { - let manager_config = - subsystem::ManagerConfig::new("blockprod-unit-test").enable_signal_handlers(); - let mut manager = Manager::new_with_config(manager_config); - - let chainstate_config = ChainstateConfig { - max_tip_age: Duration::from_secs(60 * 60 * 24 * 365 * 100).into(), - // There is at least one long test in blockprod that gets significantly slowed down - // by the heavy checks in chainstate. But since the checks are not very useful in blockprod - // tests in general, we disable them globally. - enable_heavy_checks: Some(false), - - max_db_commit_attempts: Default::default(), - enable_db_reckless_mode_in_ibd: Default::default(), - max_orphan_blocks: Default::default(), - allow_checkpoints_mismatch: Default::default(), - }; +/// A builder that produces `BlockprodTestSetup`. +pub struct BlockprodTestSetupBuilder { + chain_config: Option>, + time_getter: Option, +} - let mempool_config = MempoolConfig::new(); +impl BlockprodTestSetupBuilder { + pub fn new() -> Self { + Self { + chain_config: None, + time_getter: None, + } + } - let chainstate = chainstate::make_chainstate( - Arc::clone(&chain_config), - chainstate_config, - Store::new_empty().unwrap(), - DefaultTransactionVerificationStrategy::new(), - None, - time_getter.clone(), - None, - ) - .unwrap(); + pub fn with_chain_config(mut self, chain_config: Arc) -> Self { + self.chain_config = Some(chain_config); + self + } - let chainstate = manager.add_subsystem("chainstate", chainstate); + pub fn with_time_getter(mut self, time_getter: TimeGetter) -> Self { + self.time_getter = Some(time_getter); + self + } - let mempool_init = MempoolInit::new( - Arc::clone(&chain_config), - mempool_config, - subsystem::Handle::clone(&chainstate), - time_getter.clone(), - ) - .unwrap(); - let mempool = manager.add_custom_subsystem("mempool", |hdl, _| mempool_init.init(hdl)); - - let mut p2p_config = test_p2p_config(); - p2p_config.bind_addresses = vec![SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0).into()]; - - let p2p = p2p::make_p2p( - true, - Arc::clone(&chain_config), - Arc::new(p2p_config), - subsystem::Handle::clone(&chainstate), - mempool.clone(), - time_getter.clone(), - MonotonicTimeGetter::default(), - PeerDbStorageImpl::new(InMemory::new()).unwrap(), - ) - .unwrap() - .add_to_manager("p2p", &mut manager); + pub fn build(self) -> (BlockprodTestSetup, Manager) { + let chain_config = self.chain_config.unwrap_or_else(|| Arc::new(create_unit_test_config())); + let time_getter = self.time_getter.unwrap_or_else(TimeGetter::default); + + let manager_config = + subsystem::ManagerConfig::new("blockprod-unit-test").enable_signal_handlers(); + let mut manager = Manager::new_with_config(manager_config); + + let chainstate_config = ChainstateConfig { + max_tip_age: Duration::from_secs(60 * 60 * 24 * 365 * 100).into(), + // There is at least one long test in blockprod that gets significantly slowed down + // by the heavy checks in chainstate. But since the checks are not very useful in blockprod + // tests in general, we disable them globally. + enable_heavy_checks: Some(false), + + max_db_commit_attempts: Default::default(), + enable_db_reckless_mode_in_ibd: Default::default(), + max_orphan_blocks: Default::default(), + allow_checkpoints_mismatch: Default::default(), + }; - ( - BlockProdTestSetup { - chain_config, - time_getter, - chainstate, - mempool, - p2p, - }, - manager, - ) + let mempool_config = MempoolConfig::new(); + + let chainstate = chainstate::make_chainstate( + Arc::clone(&chain_config), + chainstate_config, + Store::new_empty().unwrap(), + DefaultTransactionVerificationStrategy::new(), + None, + time_getter.clone(), + None, + ) + .unwrap(); + + let chainstate = manager.add_subsystem("chainstate", chainstate); + + let mempool_init = MempoolInit::new( + Arc::clone(&chain_config), + mempool_config, + subsystem::Handle::clone(&chainstate), + time_getter.clone(), + ) + .unwrap(); + let mempool = manager.add_custom_subsystem("mempool", |hdl, _| mempool_init.init(hdl)); + + let mut p2p_config = test_p2p_config(); + p2p_config.bind_addresses = vec![SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0).into()]; + + let p2p = p2p::make_p2p( + true, + Arc::clone(&chain_config), + Arc::new(p2p_config), + subsystem::Handle::clone(&chainstate), + mempool.clone(), + time_getter.clone(), + MonotonicTimeGetter::default(), + PeerDbStorageImpl::new(InMemory::new()).unwrap(), + ) + .unwrap() + .add_to_manager("p2p", &mut manager); + + ( + BlockprodTestSetup { + chain_config, + time_getter, + chainstate, + mempool, + p2p, + }, + manager, + ) + } } pub fn make_genesis_timestamp(time_getter: &TimeGetter, rng: &mut impl Rng) -> BlockTimestamp { diff --git a/blockprod/src/tests/mod.rs b/blockprod/src/tests/mod.rs index 7956cd93fb..f100a53e8a 100644 --- a/blockprod/src/tests/mod.rs +++ b/blockprod/src/tests/mod.rs @@ -17,16 +17,13 @@ pub mod helpers; use std::sync::Arc; -use common::{chain::config::create_unit_test_config, time_getter::TimeGetter}; - -use crate::{make_blockproduction, test_blockprod_config, tests::helpers::setup_blockprod_test}; +use crate::{ + make_blockproduction, test_blockprod_config, tests::helpers::BlockprodTestSetupBuilder, +}; #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_make_blockproduction() { - let time_getter = TimeGetter::default(); - let chain_config = Arc::new(create_unit_test_config()); - let (blockprod_setup, mut manager) = - setup_blockprod_test(Arc::clone(&chain_config), time_getter); + let (blockprod_setup, mut manager) = BlockprodTestSetupBuilder::new().build(); let blockprod = make_blockproduction( Arc::clone(&blockprod_setup.chain_config), From 2f3dce75654295c4fb696d364415f96cfbb1b430 Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Tue, 12 May 2026 12:24:47 +0300 Subject: [PATCH 8/9] Blockprod tests refactor: replace setup_pos and setup_pos_with_genesis_timestamp with PoSTestSetupBuilder; put GenerateBlockInputData creation to PoSTestSetup::make_first_pos_block_input_data --- .../src/detail/tests/produce_block/mod.rs | 107 +---- .../tests/produce_block/tx_selection_mtp.rs | 34 +- blockprod/src/tests/helpers.rs | 366 ++++++++++-------- 3 files changed, 234 insertions(+), 273 deletions(-) diff --git a/blockprod/src/detail/tests/produce_block/mod.rs b/blockprod/src/detail/tests/produce_block/mod.rs index f89d12cbd9..ec855b278a 100644 --- a/blockprod/src/detail/tests/produce_block/mod.rs +++ b/blockprod/src/detail/tests/produce_block/mod.rs @@ -69,8 +69,8 @@ use crate::{ }, test_blockprod_config, tests::helpers::{ - BlockprodTestSetupBuilder, make_chain_config_builder, make_genesis_timestamp, setup_pos, - setup_pos_with_genesis_timestamp, + BlockprodTestSetupBuilder, PoSTestSetupBuilder, make_chain_config_builder, + make_genesis_timestamp, }, }; @@ -270,13 +270,8 @@ async fn add_job_error() { async fn overflow_tip_plus_one(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); - let pos_setup = setup_pos_with_genesis_timestamp( - BlockTimestamp::from_int_seconds(u64::MAX), - BlockHeight::new(1), - &[], - None, - &mut rng, - ); + let pos_setup = + PoSTestSetupBuilder::new().build(BlockTimestamp::from_int_seconds(u64::MAX), &mut rng); let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() .with_chain_config(Arc::clone(&pos_setup.chain_config)) @@ -292,17 +287,7 @@ async fn overflow_tip_plus_one(#[case] seed: Seed) { }); let block_production = blockprod_setup.make_blockprod_builder().build(); - - let input_data = GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( - pos_setup.genesis_stake_private_key, - pos_setup.genesis_vrf_private_key, - PoolId::new(H256::zero()), - vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), - 0, - )], - vec![pos_setup.create_genesis_pool_utxo], - ))); + let input_data = pos_setup.make_first_pos_block_input_data(); let result = block_production .produce_block(input_data, vec![], vec![], PackingStrategy::LeaveEmptySpace) @@ -325,13 +310,11 @@ async fn overflow_tip_plus_one(#[case] seed: Seed) { async fn overflow_max_blocktimestamp(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let time_getter = TimeGetter::default(); - let pos_setup = setup_pos( - &time_getter, - BlockHeight::new(1), - &[], - Some(make_chain_config_builder().max_future_block_time_offset(Some(Duration::MAX))), - &mut rng, - ); + let pos_setup = PoSTestSetupBuilder::new() + .with_chain_config_builder( + make_chain_config_builder().max_future_block_time_offset(Some(Duration::MAX)), + ) + .build(make_genesis_timestamp(&time_getter, &mut rng), &mut rng); let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() .with_chain_config(Arc::clone(&pos_setup.chain_config)) @@ -347,17 +330,7 @@ async fn overflow_max_blocktimestamp(#[case] seed: Seed) { }); let block_production = blockprod_setup.make_blockprod_builder().build(); - - let input_data = GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( - pos_setup.genesis_stake_private_key, - pos_setup.genesis_vrf_private_key, - PoolId::new(H256::zero()), - vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), - 0, - )], - vec![pos_setup.create_genesis_pool_utxo], - ))); + let input_data = pos_setup.make_first_pos_block_input_data(); let result = block_production .produce_block(input_data, vec![], vec![], PackingStrategy::LeaveEmptySpace) @@ -380,7 +353,8 @@ async fn overflow_max_blocktimestamp(#[case] seed: Seed) { async fn update_last_used_block_timestamp(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let time_getter = TimeGetter::default(); - let pos_setup = setup_pos(&time_getter, BlockHeight::new(1), &[], None, &mut rng); + let pos_setup = + PoSTestSetupBuilder::new().build(make_genesis_timestamp(&time_getter, &mut rng), &mut rng); let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() .with_chain_config(Arc::clone(&pos_setup.chain_config)) @@ -396,17 +370,7 @@ async fn update_last_used_block_timestamp(#[case] seed: Seed) { }); let block_production = blockprod_setup.make_blockprod_builder().build(); - - let input_data = GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( - pos_setup.genesis_stake_private_key, - pos_setup.genesis_vrf_private_key, - PoolId::new(H256::zero()), - vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), - 0, - )], - vec![pos_setup.create_genesis_pool_utxo], - ))); + let input_data = pos_setup.make_first_pos_block_input_data(); let _ = block_production .job_manager_handle @@ -440,13 +404,8 @@ async fn try_again_later(#[case] seed: Seed) { let default_time_getter = TimeGetter::default(); let genesis_time = default_time_getter.get_time(); - let pos_setup = setup_pos_with_genesis_timestamp( - BlockTimestamp::from_time(genesis_time), - BlockHeight::new(1), - &[], - None, - &mut rng, - ); + let pos_setup = + PoSTestSetupBuilder::new().build(BlockTimestamp::from_time(genesis_time), &mut rng); let time_getter = { let cur_time_secs = genesis_time @@ -472,17 +431,7 @@ async fn try_again_later(#[case] seed: Seed) { }); let block_production = blockprod_setup.make_blockprod_builder().build(); - - let input_data = GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( - pos_setup.genesis_stake_private_key, - pos_setup.genesis_vrf_private_key, - PoolId::new(H256::zero()), - vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), - 0, - )], - vec![pos_setup.create_genesis_pool_utxo], - ))); + let input_data = pos_setup.make_first_pos_block_input_data(); let err = block_production .produce_block(input_data, vec![], vec![], PackingStrategy::LeaveEmptySpace) @@ -850,7 +799,8 @@ async fn solved_pow_consensus() { async fn solved_pos_consensus(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let time_getter = TimeGetter::default(); - let pos_setup = setup_pos(&time_getter, BlockHeight::new(1), &[], None, &mut rng); + let pos_setup = + PoSTestSetupBuilder::new().build(make_genesis_timestamp(&time_getter, &mut rng), &mut rng); let (blockprod_setup, manager) = BlockprodTestSetupBuilder::new() .with_chain_config(Arc::clone(&pos_setup.chain_config)) @@ -866,25 +816,10 @@ async fn solved_pos_consensus(#[case] seed: Seed) { }); let block_production = blockprod_setup.make_blockprod_builder().build(); - - let input_data = Box::new(PoSGenerateBlockInputData::new( - pos_setup.genesis_stake_private_key, - pos_setup.genesis_vrf_private_key, - PoolId::new(H256::zero()), - vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), - 0, - )], - vec![pos_setup.create_genesis_pool_utxo], - )); + let input_data = pos_setup.make_first_pos_block_input_data(); let (new_block, job_finished_receiver) = block_production - .produce_block( - GenerateBlockInputData::PoS(input_data), - vec![], - vec![], - PackingStrategy::LeaveEmptySpace, - ) + .produce_block(input_data, vec![], vec![], PackingStrategy::LeaveEmptySpace) .await .unwrap(); diff --git a/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs b/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs index 3f86330d82..342615ad4a 100644 --- a/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs +++ b/blockprod/src/detail/tests/produce_block/tx_selection_mtp.rs @@ -23,7 +23,7 @@ use common::{ Uint256, chain::{ ChainConfig, CoinUnit, ConsensusUpgrade, Destination, Genesis, NetUpgrades, - OutPointSourceId, PoolId, TxOutput, + OutPointSourceId, TxOutput, block::timestamp::BlockTimestamp, config::{Builder, ChainType}, output_value::OutputValue, @@ -31,10 +31,10 @@ use common::{ timelock::OutputTimeLock, transaction::TxInput, }, - primitives::{Amount, BlockHeight, H256, Idable}, + primitives::{Amount, BlockHeight, Idable}, time_getter::TimeGetter, }; -use consensus::{PoSGenerateBlockInputData, PoWGenerateBlockInputData}; +use consensus::PoWGenerateBlockInputData; use mempool::{TxOptions, tx_accumulator::PackingStrategy, tx_origin::LocalTxOrigin}; use test_utils::{ BasicTestTimeGetter, @@ -44,7 +44,7 @@ use utils::once_destructor::OnceDestructor; use crate::{ detail::{GenerateBlockInputData, tests::produce_block::assert_job_count}, - tests::helpers::{BlockprodTestSetupBuilder, make_genesis_timestamp, setup_pos}, + tests::helpers::{BlockprodTestSetupBuilder, PoSTestSetupBuilder, make_genesis_timestamp}, }; // The height at which the transaction_selection_mtp_xxx tests will create their test block. @@ -235,29 +235,19 @@ async fn transaction_selection_mtp_test_pos(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let time_getter = BasicTestTimeGetter::new().get_time_getter(); - let extra_genesis_txs = [TxOutput::Transfer( + let extra_genesis_txos = vec![TxOutput::Transfer( OutputValue::Coin(Amount::from_atoms(1000 * CoinUnit::ATOMS_PER_COIN)), Destination::AnyoneCanSpend, )]; - let pos_setup = setup_pos( - &time_getter, - BlockHeight::new(TRANSACTION_SELECTION_MTP_TESTS_BLOCK_HEIGHT as u64), - &extra_genesis_txs, - None, - &mut rng, - ); + let pos_setup = PoSTestSetupBuilder::new() + .with_extra_genesis_txos(extra_genesis_txos) + .with_pos_switch_height(BlockHeight::new( + TRANSACTION_SELECTION_MTP_TESTS_BLOCK_HEIGHT as u64, + )) + .build(make_genesis_timestamp(&time_getter, &mut rng), &mut rng); - let input_data = GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( - pos_setup.genesis_stake_private_key, - pos_setup.genesis_vrf_private_key, - PoolId::new(H256::zero()), - vec![TxInput::from_utxo( - OutPointSourceId::BlockReward(pos_setup.chain_config.genesis_block_id()), - 0, - )], - vec![pos_setup.create_genesis_pool_utxo], - ))); + let input_data = pos_setup.make_first_pos_block_input_data(); transaction_selection_mtp_test_impl(pos_setup.chain_config, input_data, time_getter, 1).await; } diff --git a/blockprod/src/tests/helpers.rs b/blockprod/src/tests/helpers.rs index b7ecf86e4d..fcbf72ae3e 100644 --- a/blockprod/src/tests/helpers.rs +++ b/blockprod/src/tests/helpers.rs @@ -27,8 +27,8 @@ use chainstate_storage::inmemory::Store; use common::{ Uint256, Uint512, chain::{ - self, Block, ConsensusUpgrade, Destination, Genesis, NetUpgrades, PoSChainConfigBuilder, - TxOutput, + self, Block, ConsensusUpgrade, Destination, Genesis, NetUpgrades, OutPointSourceId, + PoSChainConfigBuilder, PoolId, TxInput, TxOutput, block::timestamp::BlockTimestamp, config::{ChainConfig, ChainType, create_unit_test_config}, pos_initial_difficulty, @@ -37,7 +37,10 @@ use common::{ primitives::{Amount, BlockHeight, H256, Idable, per_thousand::PerThousand}, time_getter::{MonotonicTimeGetter, TimeGetter}, }; -use consensus::{calculate_effective_pool_balance, compact_target_to_target}; +use consensus::{ + GenerateBlockInputData, PoSGenerateBlockInputData, calculate_effective_pool_balance, + compact_target_to_target, +}; use crypto::{ key::{KeyKind, PrivateKey}, vrf::{VRFKeyKind, VRFPrivateKey}, @@ -84,11 +87,102 @@ impl BlockprodTestSetup { } } -pub struct PosTestSetup { - pub chain_config: Arc, - pub genesis_stake_private_key: PrivateKey, - pub genesis_vrf_private_key: VRFPrivateKey, - pub create_genesis_pool_utxo: TxOutput, +/// A builder that produces `BlockprodTestSetup` and the subsystem manager. +pub struct BlockprodTestSetupBuilder { + chain_config: Option>, + time_getter: Option, +} + +impl BlockprodTestSetupBuilder { + pub fn new() -> Self { + Self { + chain_config: None, + time_getter: None, + } + } + + pub fn with_chain_config(mut self, chain_config: Arc) -> Self { + self.chain_config = Some(chain_config); + self + } + + pub fn with_time_getter(mut self, time_getter: TimeGetter) -> Self { + self.time_getter = Some(time_getter); + self + } + + pub fn build(self) -> (BlockprodTestSetup, Manager) { + let chain_config = self.chain_config.unwrap_or_else(|| Arc::new(create_unit_test_config())); + let time_getter = self.time_getter.unwrap_or_else(TimeGetter::default); + + let manager_config = + subsystem::ManagerConfig::new("blockprod-unit-test").enable_signal_handlers(); + let mut manager = Manager::new_with_config(manager_config); + + let chainstate_config = ChainstateConfig { + max_tip_age: Duration::from_secs(60 * 60 * 24 * 365 * 100).into(), + // There is at least one long test in blockprod that gets significantly slowed down + // by the heavy checks in chainstate. But since the checks are not very useful in blockprod + // tests in general, we disable them globally. + enable_heavy_checks: Some(false), + + max_db_commit_attempts: Default::default(), + enable_db_reckless_mode_in_ibd: Default::default(), + max_orphan_blocks: Default::default(), + allow_checkpoints_mismatch: Default::default(), + }; + + let mempool_config = MempoolConfig::new(); + + let chainstate = chainstate::make_chainstate( + Arc::clone(&chain_config), + chainstate_config, + Store::new_empty().unwrap(), + DefaultTransactionVerificationStrategy::new(), + None, + time_getter.clone(), + None, + ) + .unwrap(); + + let chainstate = manager.add_subsystem("chainstate", chainstate); + + let mempool_init = MempoolInit::new( + Arc::clone(&chain_config), + mempool_config, + subsystem::Handle::clone(&chainstate), + time_getter.clone(), + ) + .unwrap(); + let mempool = manager.add_custom_subsystem("mempool", |hdl, _| mempool_init.init(hdl)); + + let mut p2p_config = test_p2p_config(); + p2p_config.bind_addresses = vec![SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0).into()]; + + let p2p = p2p::make_p2p( + true, + Arc::clone(&chain_config), + Arc::new(p2p_config), + subsystem::Handle::clone(&chainstate), + mempool.clone(), + time_getter.clone(), + MonotonicTimeGetter::default(), + PeerDbStorageImpl::new(InMemory::new()).unwrap(), + ) + .unwrap() + .add_to_manager("p2p", &mut manager); + + ( + BlockprodTestSetup { + chain_config, + time_getter, + chainstate, + mempool, + p2p, + }, + manager, + ) + } } /// A builder that produces `BlockProduction` from `BlockprodTestSetup` with some optional overrides. @@ -133,6 +227,101 @@ impl<'a> TestBlockProdBuilder<'a> { } } +/// A bunch of data specific to PoS tests. +pub struct PoSTestSetup { + pub chain_config: Arc, + pub genesis_stake_private_key: PrivateKey, + pub genesis_vrf_private_key: VRFPrivateKey, + pub create_genesis_pool_utxo: TxOutput, +} + +impl PoSTestSetup { + pub fn make_first_pos_block_input_data(&self) -> GenerateBlockInputData { + GenerateBlockInputData::PoS(Box::new(PoSGenerateBlockInputData::new( + self.genesis_stake_private_key.clone(), + self.genesis_vrf_private_key.clone(), + PoolId::new(H256::zero()), + vec![TxInput::from_utxo( + OutPointSourceId::BlockReward(self.chain_config.genesis_block_id()), + 0, + )], + vec![self.create_genesis_pool_utxo.clone()], + ))) + } +} + +/// A builder that produces `PoSTestSetup`. +pub struct PoSTestSetupBuilder { + chain_config_builder: Option, + extra_genesis_txos: Vec, + pos_switch_height: BlockHeight, +} + +impl PoSTestSetupBuilder { + pub fn new() -> Self { + Self { + chain_config_builder: None, + extra_genesis_txos: Vec::new(), + pos_switch_height: BlockHeight::new(1), + } + } + + pub fn with_chain_config_builder( + mut self, + chain_config_builder: chain::config::Builder, + ) -> Self { + self.chain_config_builder = Some(chain_config_builder); + self + } + + pub fn with_extra_genesis_txos(mut self, extra_genesis_txos: Vec) -> Self { + self.extra_genesis_txos = extra_genesis_txos; + self + } + + pub fn with_pos_switch_height(mut self, pos_switch_height: BlockHeight) -> Self { + self.pos_switch_height = pos_switch_height; + self + } + + pub fn build( + self, + genesis_timestamp: BlockTimestamp, + rng: &mut impl CryptoRng, + ) -> PoSTestSetup { + let initial_target = pos_initial_difficulty(ChainType::Regtest); + + let (genesis, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_utxo) = + create_genesis_for_pos_tests(genesis_timestamp, &self.extra_genesis_txos, rng); + + let net_upgrades = NetUpgrades::initialize(vec![ + (BlockHeight::new(0), ConsensusUpgrade::IgnoreConsensus), + ( + self.pos_switch_height, + ConsensusUpgrade::PoS { + initial_difficulty: Some(initial_target.into()), + config: PoSChainConfigBuilder::new_for_unit_test().build(), + }, + ), + ]) + .unwrap(); + + let chain_config_builder = self + .chain_config_builder + .unwrap_or_else(make_chain_config_builder) + .genesis_custom(genesis) + .consensus_upgrades(net_upgrades); + let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); + + PoSTestSetup { + chain_config, + genesis_stake_private_key, + genesis_vrf_private_key, + create_genesis_pool_utxo, + } + } +} + pub async fn assert_process_block( chainstate: &ChainstateHandle, mempool: &MempoolHandle, @@ -190,104 +379,6 @@ pub async fn assert_process_block( block_index } -/// A builder that produces `BlockprodTestSetup`. -pub struct BlockprodTestSetupBuilder { - chain_config: Option>, - time_getter: Option, -} - -impl BlockprodTestSetupBuilder { - pub fn new() -> Self { - Self { - chain_config: None, - time_getter: None, - } - } - - pub fn with_chain_config(mut self, chain_config: Arc) -> Self { - self.chain_config = Some(chain_config); - self - } - - pub fn with_time_getter(mut self, time_getter: TimeGetter) -> Self { - self.time_getter = Some(time_getter); - self - } - - pub fn build(self) -> (BlockprodTestSetup, Manager) { - let chain_config = self.chain_config.unwrap_or_else(|| Arc::new(create_unit_test_config())); - let time_getter = self.time_getter.unwrap_or_else(TimeGetter::default); - - let manager_config = - subsystem::ManagerConfig::new("blockprod-unit-test").enable_signal_handlers(); - let mut manager = Manager::new_with_config(manager_config); - - let chainstate_config = ChainstateConfig { - max_tip_age: Duration::from_secs(60 * 60 * 24 * 365 * 100).into(), - // There is at least one long test in blockprod that gets significantly slowed down - // by the heavy checks in chainstate. But since the checks are not very useful in blockprod - // tests in general, we disable them globally. - enable_heavy_checks: Some(false), - - max_db_commit_attempts: Default::default(), - enable_db_reckless_mode_in_ibd: Default::default(), - max_orphan_blocks: Default::default(), - allow_checkpoints_mismatch: Default::default(), - }; - - let mempool_config = MempoolConfig::new(); - - let chainstate = chainstate::make_chainstate( - Arc::clone(&chain_config), - chainstate_config, - Store::new_empty().unwrap(), - DefaultTransactionVerificationStrategy::new(), - None, - time_getter.clone(), - None, - ) - .unwrap(); - - let chainstate = manager.add_subsystem("chainstate", chainstate); - - let mempool_init = MempoolInit::new( - Arc::clone(&chain_config), - mempool_config, - subsystem::Handle::clone(&chainstate), - time_getter.clone(), - ) - .unwrap(); - let mempool = manager.add_custom_subsystem("mempool", |hdl, _| mempool_init.init(hdl)); - - let mut p2p_config = test_p2p_config(); - p2p_config.bind_addresses = vec![SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0).into()]; - - let p2p = p2p::make_p2p( - true, - Arc::clone(&chain_config), - Arc::new(p2p_config), - subsystem::Handle::clone(&chainstate), - mempool.clone(), - time_getter.clone(), - MonotonicTimeGetter::default(), - PeerDbStorageImpl::new(InMemory::new()).unwrap(), - ) - .unwrap() - .add_to_manager("p2p", &mut manager); - - ( - BlockprodTestSetup { - chain_config, - time_getter, - chainstate, - mempool, - p2p, - }, - manager, - ) - } -} - pub fn make_genesis_timestamp(time_getter: &TimeGetter, rng: &mut impl Rng) -> BlockTimestamp { BlockTimestamp::from_int_seconds( (time_getter.get_time() @@ -328,7 +419,7 @@ pub fn ensure_reasonable_initial_target_for_pos_tests( pub fn create_genesis_for_pos_tests( timestamp: BlockTimestamp, - extra_txs: &[TxOutput], + extra_txos: &[TxOutput], rng: &mut impl CryptoRng, ) -> ( Genesis, @@ -362,10 +453,10 @@ pub fn create_genesis_for_pos_tests( ) }; - let mut txs = vec![create_pool_txoutput.clone()]; - txs.extend_from_slice(extra_txs); + let mut txos = vec![create_pool_txoutput.clone()]; + txos.extend_from_slice(extra_txos); - let genesis = Genesis::new("blockprod-testing".into(), timestamp, txs); + let genesis = Genesis::new("blockprod-testing".into(), timestamp, txos); ( genesis, @@ -379,61 +470,6 @@ pub fn make_chain_config_builder() -> chain::config::Builder { chain::config::Builder::new(ChainType::Regtest) } -pub fn setup_pos( - time_getter: &TimeGetter, - switch_to_pos_at: BlockHeight, - extra_genesis_txs: &[TxOutput], - chain_config_builder: Option, - rng: &mut impl CryptoRng, -) -> PosTestSetup { - let genesis_timestamp = make_genesis_timestamp(time_getter, rng); - setup_pos_with_genesis_timestamp( - genesis_timestamp, - switch_to_pos_at, - extra_genesis_txs, - chain_config_builder, - rng, - ) -} - -pub fn setup_pos_with_genesis_timestamp( - genesis_timestamp: BlockTimestamp, - switch_to_pos_at: BlockHeight, - extra_genesis_txs: &[TxOutput], - chain_config_builder: Option, - rng: &mut impl CryptoRng, -) -> PosTestSetup { - let initial_target = pos_initial_difficulty(ChainType::Regtest); - - let (genesis, genesis_stake_private_key, genesis_vrf_private_key, create_genesis_pool_utxo) = - create_genesis_for_pos_tests(genesis_timestamp, extra_genesis_txs, rng); - - let net_upgrades = NetUpgrades::initialize(vec![ - (BlockHeight::new(0), ConsensusUpgrade::IgnoreConsensus), - ( - switch_to_pos_at, - ConsensusUpgrade::PoS { - initial_difficulty: Some(initial_target.into()), - config: PoSChainConfigBuilder::new_for_unit_test().build(), - }, - ), - ]) - .unwrap(); - - let chain_config_builder = chain_config_builder - .unwrap_or_else(make_chain_config_builder) - .genesis_custom(genesis) - .consensus_upgrades(net_upgrades); - let chain_config = Arc::new(build_chain_config_for_pos(chain_config_builder)); - - PosTestSetup { - chain_config, - genesis_stake_private_key, - genesis_vrf_private_key, - create_genesis_pool_utxo, - } -} - pub fn build_chain_config_for_pos(builder: chain::config::Builder) -> ChainConfig { let chain_config = builder.build(); From a5d14fcce235ae45c037d74330a98bed0997eb87 Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Tue, 26 May 2026 12:54:08 +0300 Subject: [PATCH 9/9] Minor cleanup, appease clippy --- blockprod/src/tests/helpers.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/blockprod/src/tests/helpers.rs b/blockprod/src/tests/helpers.rs index fcbf72ae3e..c0d377760e 100644 --- a/blockprod/src/tests/helpers.rs +++ b/blockprod/src/tests/helpers.rs @@ -74,9 +74,7 @@ impl BlockprodTestSetup { pub async fn assert_process_block(&self, new_block: Block) -> BlockIndex { assert_process_block(&self.chainstate, &self.mempool, new_block).await } -} -impl BlockprodTestSetup { pub fn make_blockprod_builder(&self) -> TestBlockProdBuilder<'_> { TestBlockProdBuilder { test_setup: self, @@ -113,7 +111,7 @@ impl BlockprodTestSetupBuilder { pub fn build(self) -> (BlockprodTestSetup, Manager) { let chain_config = self.chain_config.unwrap_or_else(|| Arc::new(create_unit_test_config())); - let time_getter = self.time_getter.unwrap_or_else(TimeGetter::default); + let time_getter = self.time_getter.unwrap_or_default(); let manager_config = subsystem::ManagerConfig::new("blockprod-unit-test").enable_signal_handlers(); @@ -329,8 +327,10 @@ pub async fn assert_process_block( ) -> BlockIndex { let block_id = new_block.get_id(); - // Wait for mempool to be up-to-date with the new block. The subscriptions are not cleaned - // up but hopefully it's not too bad just for testing. + // Subscribe to mempool events, so that we can wait for it to become up-to-date with + // the new block. + // Note that currently we don't have a mechanism to remove a subscription, so "dead" event + // handlers will accumulate each time this function is called. But it's not a big deal in tests. let (tip_sx, tip_rx) = tokio::sync::oneshot::channel(); let tip_sx = utils::sync::Mutex::new(Some(tip_sx)); mempool @@ -340,7 +340,7 @@ pub async fn assert_process_block( mempool::event::MempoolEvent::NewTip(tip) => { if let Some(tip_sx) = tip_sx.lock().unwrap().take() { assert_eq!(tip.block_id(), &block_id); - tip_sx.send(()).unwrap(); + let _ = tip_sx.send(()); } } mempool::event::MempoolEvent::TransactionProcessed(_) => (), @@ -358,7 +358,7 @@ pub async fn assert_process_block( assert_eq!( new_block.header().header().block_id(), *new_block_index.block_id(), - "The new block's Id is different to the new block index's block Id", + "The new block's id is different from the new block index's block id", ); let best_block_index = this.get_best_block_index().unwrap(); @@ -366,7 +366,7 @@ pub async fn assert_process_block( assert_eq!( new_block_index.clone().into_gen_block_index().block_id(), best_block_index.block_id(), - "The new block index not the best block index" + "The new block index is not the best block index" ); new_block_index