diff --git a/banking-bench/src/main.rs b/banking-bench/src/main.rs index 40f9ab1ab7..75b39c3863 100644 --- a/banking-bench/src/main.rs +++ b/banking-bench/src/main.rs @@ -312,11 +312,10 @@ fn main() { tx_total_us += duration_as_us(&now.elapsed()); let mut poh_time = Measure::start("poh_time"); - poh_recorder.lock().unwrap().reset( - bank.last_blockhash(), - bank.slot(), - Some((bank.slot(), bank.slot() + 1)), - ); + poh_recorder + .lock() + .unwrap() + .reset(bank.clone(), Some((bank.slot(), bank.slot() + 1))); poh_time.stop(); let mut new_bank_time = Measure::start("new_bank"); diff --git a/core/src/banking_stage.rs b/core/src/banking_stage.rs index f52b31455d..a2a79bed79 100644 --- a/core/src/banking_stage.rs +++ b/core/src/banking_stage.rs @@ -1558,7 +1558,7 @@ mod tests { }; use solana_perf::packet::to_packets_chunked; use solana_poh::{ - poh_recorder::{create_test_recorder, Record, WorkingBank, WorkingBankEntry}, + poh_recorder::{create_test_recorder, Record, WorkingBankEntry}, poh_service::PohService, }; use solana_rpc::transaction_status_service::TransactionStatusService; @@ -1940,13 +1940,6 @@ mod tests { .. } = create_genesis_config(10_000); let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config)); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank: bank.clone(), - start, - min_tick_height: bank.tick_height(), - max_tick_height: std::u64::MAX, - }; let ledger_path = get_tmp_ledger_path!(); { let blockstore = Blockstore::open(&ledger_path) @@ -1955,7 +1948,7 @@ mod tests { // TODO use record_receiver bank.tick_height(), bank.last_blockhash(), - bank.slot(), + bank.clone(), None, bank.ticks_per_slot(), &Pubkey::default(), @@ -1969,7 +1962,7 @@ mod tests { let poh_simulator = simulate_poh(record_receiver, &poh_recorder); - poh_recorder.lock().unwrap().set_working_bank(working_bank); + poh_recorder.lock().unwrap().set_bank(&bank); let pubkey = solana_sdk::pubkey::new_rand(); let keypair2 = Keypair::new(); let pubkey2 = solana_sdk::pubkey::new_rand(); @@ -2011,8 +2004,9 @@ mod tests { // Once bank is set to a new bank (setting bank.slot() + 1 in record_transactions), // record_transactions should throw MaxHeightReached and return the set of retryable // txs + let next_slot = bank.slot() + 1; let (res, retryable) = - BankingStage::record_transactions(bank.slot() + 1, &txs, &results, &recorder); + BankingStage::record_transactions(next_slot, &txs, &results, &recorder); assert_matches!(res, Err(PohRecorderError::MaxHeightReached)); // The first result was an error so it's filtered out. The second result was Ok(), // so it should be marked as retryable @@ -2196,13 +2190,6 @@ mod tests { .unwrap(), ]; - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank: bank.clone(), - start, - min_tick_height: bank.tick_height(), - max_tick_height: bank.tick_height() + 1, - }; let ledger_path = get_tmp_ledger_path!(); { let blockstore = Blockstore::open(&ledger_path) @@ -2210,7 +2197,7 @@ mod tests { let (poh_recorder, entry_receiver, record_receiver) = PohRecorder::new( bank.tick_height(), bank.last_blockhash(), - bank.slot(), + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &pubkey, @@ -2224,7 +2211,7 @@ mod tests { let poh_simulator = simulate_poh(record_receiver, &poh_recorder); - poh_recorder.lock().unwrap().set_working_bank(working_bank); + poh_recorder.lock().unwrap().set_bank(&bank); let (gossip_vote_sender, _gossip_vote_receiver) = unbounded(); BankingStage::process_and_record_transactions( @@ -2237,7 +2224,11 @@ mod tests { ) .0 .unwrap(); - poh_recorder.lock().unwrap().tick(); + + // Tick up to max tick height + while poh_recorder.lock().unwrap().tick_height() != bank.max_tick_height() { + poh_recorder.lock().unwrap().tick(); + } let mut done = false; // read entries until I find mine, might be ticks... @@ -2332,13 +2323,6 @@ mod tests { .unwrap(), ]; - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank: bank.clone(), - start, - min_tick_height: bank.tick_height(), - max_tick_height: bank.tick_height() + 1, - }; let ledger_path = get_tmp_ledger_path!(); { let blockstore = Blockstore::open(&ledger_path) @@ -2346,7 +2330,7 @@ mod tests { let (poh_recorder, _entry_receiver, record_receiver) = PohRecorder::new( bank.tick_height(), bank.last_blockhash(), - bank.slot(), + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &pubkey, @@ -2358,7 +2342,7 @@ mod tests { let recorder = poh_recorder.recorder(); let poh_recorder = Arc::new(Mutex::new(poh_recorder)); - poh_recorder.lock().unwrap().set_working_bank(working_bank); + poh_recorder.lock().unwrap().set_bank(&bank); let poh_simulator = simulate_poh(record_receiver, &poh_recorder); @@ -2453,7 +2437,7 @@ mod tests { let (poh_recorder, _entry_receiver, record_receiver) = PohRecorder::new( bank.tick_height(), bank.last_blockhash(), - bank.slot(), + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &solana_sdk::pubkey::new_rand(), @@ -2527,13 +2511,6 @@ mod tests { ]; bank.transfer(4, &mint_keypair, &keypair1.pubkey()).unwrap(); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank: bank.clone(), - start, - min_tick_height: bank.tick_height(), - max_tick_height: bank.tick_height() + 1, - }; let ledger_path = get_tmp_ledger_path!(); { let blockstore = Blockstore::open(&ledger_path) @@ -2542,7 +2519,7 @@ mod tests { let (poh_recorder, _entry_receiver, record_receiver) = PohRecorder::new( bank.tick_height(), bank.last_blockhash(), - bank.slot(), + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &pubkey, @@ -2556,7 +2533,7 @@ mod tests { let poh_simulator = simulate_poh(record_receiver, &poh_recorder); - poh_recorder.lock().unwrap().set_working_bank(working_bank); + poh_recorder.lock().unwrap().set_bank(&bank); let shreds = entries_to_test_shreds(entries, bank.slot(), 0, true, 0); blockstore.insert_shreds(shreds, None, false).unwrap(); @@ -2643,7 +2620,7 @@ mod tests { let (poh_recorder, entry_receiver, record_receiver) = PohRecorder::new( bank.tick_height(), bank.last_blockhash(), - bank.slot(), + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &solana_sdk::pubkey::new_rand(), diff --git a/core/src/replay_stage.rs b/core/src/replay_stage.rs index af2ea5cc39..a41a4377b6 100644 --- a/core/src/replay_stage.rs +++ b/core/src/replay_stage.rs @@ -1930,7 +1930,7 @@ impl ReplayStage { poh_recorder .lock() .unwrap() - .reset(bank.last_blockhash(), bank.slot(), next_leader_slot); + .reset(bank.clone(), next_leader_slot); let next_leader_msg = if let Some(next_leader_slot) = next_leader_slot { format!("My next leader slot is {}", next_leader_slot.0) @@ -2978,7 +2978,7 @@ pub mod tests { PohRecorder::new( working_bank.tick_height(), working_bank.last_blockhash(), - working_bank.slot(), + working_bank.clone(), None, working_bank.ticks_per_slot(), &Pubkey::default(), @@ -5574,20 +5574,11 @@ pub mod tests { let my_vote_pubkey = my_vote_keypair[0].pubkey(); let bank0 = bank_forks.read().unwrap().get(0).unwrap().clone(); - fn fill_bank_with_ticks(bank: &Bank) { - let parent_distance = bank.slot() - bank.parent_slot(); - for _ in 0..parent_distance { - let last_blockhash = bank.last_blockhash(); - while bank.last_blockhash() == last_blockhash { - bank.register_tick(&Hash::new_unique()) - } - } - } let (voting_sender, voting_receiver) = channel(); // Simulate landing a vote for slot 0 landing in slot 1 let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1)); - fill_bank_with_ticks(&bank1); + bank1.fill_bank_with_ticks(); tower.record_bank_vote(&bank0, &my_vote_pubkey); ReplayStage::push_vote( &bank0, @@ -5625,7 +5616,7 @@ pub mod tests { // Trying to refresh the vote for bank 0 in bank 1 or bank 2 won't succeed because // the last vote has landed already let bank2 = Arc::new(Bank::new_from_parent(&bank1, &Pubkey::default(), 2)); - fill_bank_with_ticks(&bank2); + bank2.fill_bank_with_ticks(); bank2.freeze(); for refresh_bank in &[&bank1, &bank2] { ReplayStage::refresh_last_vote( @@ -5708,7 +5699,7 @@ pub mod tests { &Pubkey::default(), bank2.slot() + MAX_PROCESSING_AGE as Slot, )); - fill_bank_with_ticks(&expired_bank); + expired_bank.fill_bank_with_ticks(); expired_bank.freeze(); // Now trying to refresh the vote for slot 1 will succeed because the recent blockhash @@ -5770,7 +5761,7 @@ pub mod tests { vote_account.vote_state().as_ref().unwrap().tower(), vec![0, 1] ); - fill_bank_with_ticks(&expired_bank_child); + expired_bank_child.fill_bank_with_ticks(); expired_bank_child.freeze(); // Trying to refresh the vote on a sibling bank where: @@ -5782,7 +5773,7 @@ pub mod tests { &Pubkey::default(), expired_bank_child.slot() + 1, )); - fill_bank_with_ticks(&expired_bank_sibling); + expired_bank_sibling.fill_bank_with_ticks(); expired_bank_sibling.freeze(); // Set the last refresh to now, shouldn't refresh because the last refresh just happened. last_vote_refresh_time.last_refresh_time = Instant::now(); diff --git a/core/src/validator.rs b/core/src/validator.rs index 7e0c3172ca..7dd30aae1b 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -504,7 +504,7 @@ impl Validator { PohRecorder::new_with_clear_signal( bank.tick_height(), bank.last_blockhash(), - bank.slot(), + bank.clone(), leader_schedule_cache.next_leader_slot( &id, bank.slot(), diff --git a/poh/src/poh_recorder.rs b/poh/src/poh_recorder.rs index 3998eea188..d6387130b3 100644 --- a/poh/src/poh_recorder.rs +++ b/poh/src/poh_recorder.rs @@ -18,7 +18,11 @@ use { }, log::*, solana_entry::{entry::Entry, poh::Poh}, - solana_ledger::{blockstore::Blockstore, leader_schedule_cache::LeaderScheduleCache}, + solana_ledger::{ + blockstore::Blockstore, + genesis_utils::{create_genesis_config, GenesisConfigInfo}, + leader_schedule_cache::LeaderScheduleCache, + }, solana_runtime::bank::Bank, solana_sdk::{ clock::NUM_CONSECUTIVE_LEADER_SLOTS, hash::Hash, poh_config::PohConfig, pubkey::Pubkey, @@ -155,7 +159,7 @@ pub struct PohRecorder { pub poh: Arc>, tick_height: u64, clear_bank_signal: Option>, - start_slot: Slot, // parent slot + start_bank: Arc, // parent slot start_tick_height: u64, // first tick_height this recorder will observe tick_cache: Vec<(Entry, u64)>, // cache of entry and its tick_height working_bank: Option, @@ -268,7 +272,7 @@ impl PohRecorder { // previous leader's slots. // If so, PoH is currently building on the previous leader's blocks // If not, PoH is building on a different fork - slot == self.start_slot + slot == self.start_slot() }) } @@ -296,12 +300,12 @@ impl PohRecorder { || !self.is_same_fork_as_previous_leader(current_slot))) } - pub fn last_reset_slot(&self) -> Slot { - self.start_slot + pub fn start_slot(&self) -> Slot { + self.start_bank.slot() } /// returns if leader slot has been reached, how many grace ticks were afforded, - /// imputed leader_slot and self.start_slot + /// imputed leader_slot and self.start_slot() /// reached_leader_slot() == true means "ready for a bank" pub fn reached_leader_slot(&self) -> (bool, u64, Slot, Slot) { trace!( @@ -325,11 +329,11 @@ impl PohRecorder { true, self.tick_height.saturating_sub(ideal_target_tick_height), next_leader_slot, - self.start_slot, + self.start_slot(), ); } } - (false, 0, next_leader_slot, self.start_slot) + (false, 0, next_leader_slot, self.start_slot()) } // returns (leader_first_tick_height, leader_last_tick_height, grace_ticks) given the next @@ -364,14 +368,10 @@ impl PohRecorder { } // synchronize PoH with a bank - pub fn reset( - &mut self, - blockhash: Hash, - start_slot: Slot, - next_leader_slot: Option<(Slot, Slot)>, - ) { + pub fn reset(&mut self, reset_bank: Arc, next_leader_slot: Option<(Slot, Slot)>) { self.clear_bank(); let mut cache = vec![]; + let blockhash = reset_bank.last_blockhash(); let poh_hash = { let mut poh = self.poh.lock().unwrap(); poh.reset(blockhash, self.poh_config.hashes_per_tick); @@ -379,13 +379,17 @@ impl PohRecorder { }; info!( "reset poh from: {},{},{} to: {},{}", - poh_hash, self.tick_height, self.start_slot, blockhash, start_slot + poh_hash, + self.tick_height, + self.start_slot(), + blockhash, + reset_bank.slot() ); std::mem::swap(&mut cache, &mut self.tick_cache); - self.start_slot = start_slot; - self.tick_height = (start_slot + 1) * self.ticks_per_slot; + self.start_bank = reset_bank; + self.tick_height = (self.start_slot() + 1) * self.ticks_per_slot; self.start_tick_height = self.tick_height + 1; let (leader_first_tick_height, leader_last_tick_height, grace_ticks) = @@ -395,15 +399,6 @@ impl PohRecorder { self.leader_last_tick_height = leader_last_tick_height; } - pub fn set_working_bank(&mut self, working_bank: WorkingBank) { - trace!("new working bank"); - assert_eq!(working_bank.bank.ticks_per_slot(), self.ticks_per_slot()); - self.working_bank = Some(working_bank); - // TODO: adjust the working_bank.start time based on number of ticks - // that have already elapsed based on current tick height. - let _ = self.flush_cache(false); - } - pub fn set_bank(&mut self, bank: &Arc) { let working_bank = WorkingBank { bank: bank.clone(), @@ -411,7 +406,12 @@ impl PohRecorder { min_tick_height: bank.tick_height(), max_tick_height: bank.max_tick_height(), }; - self.set_working_bank(working_bank); + trace!("new working bank"); + assert_eq!(working_bank.bank.ticks_per_slot(), self.ticks_per_slot()); + self.working_bank = Some(working_bank); + // TODO: adjust the working_bank.start time based on number of ticks + // that have already elapsed based on current tick height. + let _ = self.flush_cache(false); } // Flush cache will delay flushing the cache for a bank until it past the WorkingBank::min_tick_height @@ -462,9 +462,8 @@ impl PohRecorder { working_bank.max_tick_height, working_bank.bank.slot() ); - let working_slot = - (working_bank.max_tick_height / self.ticks_per_slot).saturating_sub(1); - self.start_slot = working_slot; + self.start_bank = working_bank.bank.clone(); + let working_slot = self.start_slot(); self.start_tick_height = working_slot * self.ticks_per_slot + 1; self.clear_bank(); } @@ -620,7 +619,7 @@ impl PohRecorder { pub fn new_with_clear_signal( tick_height: u64, last_entry_hash: Hash, - start_slot: Slot, + start_bank: Arc, next_leader_slot: Option<(Slot, Slot)>, ticks_per_slot: u64, id: &Pubkey, @@ -654,7 +653,7 @@ impl PohRecorder { working_bank: None, sender, clear_bank_signal, - start_slot, + start_bank, start_tick_height: tick_height + 1, leader_first_tick_height, leader_last_tick_height, @@ -691,7 +690,7 @@ impl PohRecorder { pub fn new( tick_height: u64, last_entry_hash: Hash, - start_slot: Slot, + start_bank: Arc, next_leader_slot: Option<(Slot, Slot)>, ticks_per_slot: u64, id: &Pubkey, @@ -703,7 +702,7 @@ impl PohRecorder { Self::new_with_clear_signal( tick_height, last_entry_hash, - start_slot, + start_bank, next_leader_slot, ticks_per_slot, id, @@ -729,7 +728,9 @@ impl PohRecorder { // Used in tests pub fn schedule_dummy_max_height_reached_failure(&mut self) { - self.reset(Hash::default(), 1, None); + let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); + let bank = Arc::new(Bank::new_for_tests(&genesis_config)); + self.reset(bank, None); } } @@ -748,7 +749,7 @@ pub fn create_test_recorder( let (mut poh_recorder, entry_receiver, record_receiver) = PohRecorder::new( bank.tick_height(), bank.last_blockhash(), - bank.slot(), + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &Pubkey::default(), @@ -778,12 +779,7 @@ mod tests { use { super::*, bincode::serialize, - solana_ledger::{ - blockstore::Blockstore, - blockstore_meta::SlotMeta, - genesis_utils::{create_genesis_config, GenesisConfigInfo}, - get_tmp_ledger_path, - }, + solana_ledger::{blockstore::Blockstore, blockstore_meta::SlotMeta, get_tmp_ledger_path}, solana_perf::test_tx::test_tx, solana_sdk::{clock::DEFAULT_TICKS_PER_SLOT, hash::hash}, std::sync::mpsc::sync_channel, @@ -797,10 +793,12 @@ mod tests { let blockstore = Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"); + let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); + let bank = Arc::new(Bank::new_for_tests(&genesis_config)); let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank, Some((4, 4)), DEFAULT_TICKS_PER_SLOT, &Pubkey::default(), @@ -825,10 +823,12 @@ mod tests { let blockstore = Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"); + let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); + let bank = Arc::new(Bank::new_for_tests(&genesis_config)); let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank, Some((4, 4)), DEFAULT_TICKS_PER_SLOT, &Pubkey::default(), @@ -852,10 +852,12 @@ mod tests { { let blockstore = Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"); + let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); + let bank0 = Arc::new(Bank::new_for_tests(&genesis_config)); let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, Hash::default(), - 0, + bank0.clone(), Some((4, 4)), DEFAULT_TICKS_PER_SLOT, &Pubkey::default(), @@ -866,7 +868,7 @@ mod tests { ); poh_recorder.tick(); assert_eq!(poh_recorder.tick_cache.len(), 1); - poh_recorder.reset(Hash::default(), 0, Some((4, 4))); + poh_recorder.reset(bank0, Some((4, 4))); assert_eq!(poh_recorder.tick_cache.len(), 0); } Blockstore::destroy(&ledger_path).unwrap(); @@ -884,7 +886,7 @@ mod tests { let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &Pubkey::default(), @@ -894,14 +896,7 @@ mod tests { Arc::new(AtomicBool::default()), ); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank, - start, - min_tick_height: 2, - max_tick_height: 3, - }; - poh_recorder.set_working_bank(working_bank); + poh_recorder.set_bank(&bank); assert!(poh_recorder.working_bank.is_some()); poh_recorder.clear_bank(); assert!(poh_recorder.working_bank.is_none()); @@ -916,47 +911,58 @@ mod tests { let blockstore = Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"); let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); - let bank = Arc::new(Bank::new_for_tests(&genesis_config)); - let prev_hash = bank.last_blockhash(); + let bank0 = Arc::new(Bank::new_for_tests(&genesis_config)); + let prev_hash = bank0.last_blockhash(); let (mut poh_recorder, entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank0.clone(), Some((4, 4)), - bank.ticks_per_slot(), + bank0.ticks_per_slot(), &Pubkey::default(), &Arc::new(blockstore), - &Arc::new(LeaderScheduleCache::new_from_bank(&bank)), + &Arc::new(LeaderScheduleCache::new_from_bank(&bank0)), &Arc::new(PohConfig::default()), Arc::new(AtomicBool::default()), ); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank: bank.clone(), - start, - min_tick_height: 2, - max_tick_height: 3, - }; - poh_recorder.set_working_bank(working_bank); - poh_recorder.tick(); - poh_recorder.tick(); - //tick height equal to min_tick_height - //no tick has been sent - assert_eq!(poh_recorder.tick_cache.last().unwrap().1, 2); + bank0.fill_bank_with_ticks(); + let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1)); + + // Set a working bank + poh_recorder.set_bank(&bank1); + + // Tick until poh_recorder.tick_height == working bank's min_tick_height + let num_new_ticks = bank1.tick_height() - poh_recorder.tick_height(); + println!("{} {}", bank1.tick_height(), poh_recorder.tick_height()); + assert!(num_new_ticks > 0); + for _ in 0..num_new_ticks { + poh_recorder.tick(); + } + + // Check that poh_recorder.tick_height == working bank's min_tick_height + let min_tick_height = poh_recorder.working_bank.as_ref().unwrap().min_tick_height; + assert_eq!(min_tick_height, bank1.tick_height()); + assert_eq!(poh_recorder.tick_height(), min_tick_height); + + //poh_recorder.tick height == working bank's min_tick_height, + // so no ticks should have been flushed yet + assert_eq!(poh_recorder.tick_cache.last().unwrap().1, num_new_ticks); assert!(entry_receiver.try_recv().is_err()); // all ticks are sent after height > min + let tick_height_before = poh_recorder.tick_height(); poh_recorder.tick(); - assert_eq!(poh_recorder.tick_height, 3); + assert_eq!(poh_recorder.tick_height, tick_height_before + 1); assert_eq!(poh_recorder.tick_cache.len(), 0); let mut num_entries = 0; while let Ok((wbank, (_entry, _tick_height))) = entry_receiver.try_recv() { - assert_eq!(wbank.slot(), bank.slot()); + assert_eq!(wbank.slot(), bank1.slot()); num_entries += 1; } - assert_eq!(num_entries, 3); - assert!(poh_recorder.working_bank.is_none()); + + // All the cached ticks, plus the new tick above should have been flushed + assert_eq!(num_entries, num_new_ticks + 1); } Blockstore::destroy(&ledger_path).unwrap(); } @@ -973,7 +979,7 @@ mod tests { let (mut poh_recorder, entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &Pubkey::default(), @@ -983,30 +989,29 @@ mod tests { Arc::new(AtomicBool::default()), ); - poh_recorder.tick(); - poh_recorder.tick(); - poh_recorder.tick(); - poh_recorder.tick(); - assert_eq!(poh_recorder.tick_cache.last().unwrap().1, 4); - assert_eq!(poh_recorder.tick_height, 4); + // Tick further than the bank's max height + for _ in 0..bank.max_tick_height() + 1 { + poh_recorder.tick(); + } + assert_eq!( + poh_recorder.tick_cache.last().unwrap().1, + bank.max_tick_height() + 1 + ); + assert_eq!(poh_recorder.tick_height, bank.max_tick_height() + 1); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank, - start, - min_tick_height: 2, - max_tick_height: 3, - }; - poh_recorder.set_working_bank(working_bank); + poh_recorder.set_bank(&bank); poh_recorder.tick(); - assert_eq!(poh_recorder.tick_height, 5); + assert_eq!(poh_recorder.tick_height, bank.max_tick_height() + 2); assert!(poh_recorder.working_bank.is_none()); let mut num_entries = 0; while entry_receiver.try_recv().is_ok() { num_entries += 1; } - assert_eq!(num_entries, 3); + + // Should only flush up to bank's max tick height, despite the tick cache + // having many more entries + assert_eq!(num_entries, bank.max_tick_height()); } Blockstore::destroy(&ledger_path).unwrap(); } @@ -1018,35 +1023,37 @@ mod tests { let blockstore = Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"); let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); - let bank = Arc::new(Bank::new_for_tests(&genesis_config)); - let prev_hash = bank.last_blockhash(); + let bank0 = Arc::new(Bank::new_for_tests(&genesis_config)); + let prev_hash = bank0.last_blockhash(); let (mut poh_recorder, entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank0.clone(), Some((4, 4)), - bank.ticks_per_slot(), + bank0.ticks_per_slot(), &Pubkey::default(), &Arc::new(blockstore), - &Arc::new(LeaderScheduleCache::new_from_bank(&bank)), + &Arc::new(LeaderScheduleCache::new_from_bank(&bank0)), &Arc::new(PohConfig::default()), Arc::new(AtomicBool::default()), ); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank: bank.clone(), - start, - min_tick_height: 2, - max_tick_height: 3, - }; - poh_recorder.set_working_bank(working_bank); - poh_recorder.tick(); + bank0.fill_bank_with_ticks(); + let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1)); + poh_recorder.set_bank(&bank1); + // Let poh_recorder tick up to bank1.tick_height() - 1 + for _ in 0..bank1.tick_height() - 1 { + poh_recorder.tick() + } let tx = test_tx(); let h1 = hash(b"hello world!"); - assert!(poh_recorder - .record(bank.slot(), h1, vec![tx.into()]) - .is_err()); + + // We haven't yet reached the minimum tick height for the working bank, + // so record should fail + assert_matches!( + poh_recorder.record(bank1.slot(), h1, vec![tx.into()]), + Err(PohRecorderError::MinHeightNotReached) + ); assert!(entry_receiver.try_recv().is_err()); } Blockstore::destroy(&ledger_path).unwrap(); @@ -1064,7 +1071,7 @@ mod tests { let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &Pubkey::default(), @@ -1074,21 +1081,20 @@ mod tests { Arc::new(AtomicBool::default()), ); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank: bank.clone(), - start, - min_tick_height: 1, - max_tick_height: 2, - }; - poh_recorder.set_working_bank(working_bank); - poh_recorder.tick(); - assert_eq!(poh_recorder.tick_cache.len(), 1); - assert_eq!(poh_recorder.tick_height, 1); + poh_recorder.set_bank(&bank); let tx = test_tx(); let h1 = hash(b"hello world!"); + + // Fulfills min height criteria for a successful record + assert_eq!( + poh_recorder.tick_height(), + poh_recorder.working_bank.as_ref().unwrap().min_tick_height + ); + + // However we hand over a bad slot so record fails + let bad_slot = bank.slot() + 1; assert_matches!( - poh_recorder.record(bank.slot() + 1, h1, vec![tx.into()]), + poh_recorder.record(bad_slot, h1, vec![tx.into()]), Err(PohRecorderError::MaxHeightReached) ); } @@ -1102,43 +1108,50 @@ mod tests { let blockstore = Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"); let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); - let bank = Arc::new(Bank::new_for_tests(&genesis_config)); - let prev_hash = bank.last_blockhash(); + let bank0 = Arc::new(Bank::new_for_tests(&genesis_config)); + let prev_hash = bank0.last_blockhash(); let (mut poh_recorder, entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank0.clone(), Some((4, 4)), - bank.ticks_per_slot(), + bank0.ticks_per_slot(), &Pubkey::default(), &Arc::new(blockstore), - &Arc::new(LeaderScheduleCache::new_from_bank(&bank)), + &Arc::new(LeaderScheduleCache::new_from_bank(&bank0)), &Arc::new(PohConfig::default()), Arc::new(AtomicBool::default()), ); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank: bank.clone(), - start, - min_tick_height: 1, - max_tick_height: 2, - }; - poh_recorder.set_working_bank(working_bank); - poh_recorder.tick(); - assert_eq!(poh_recorder.tick_cache.len(), 1); - assert_eq!(poh_recorder.tick_height, 1); + bank0.fill_bank_with_ticks(); + let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1)); + poh_recorder.set_bank(&bank1); + + // Record up to exactly min tick height + let min_tick_height = poh_recorder.working_bank.as_ref().unwrap().min_tick_height; + while poh_recorder.tick_height() < min_tick_height { + poh_recorder.tick(); + } + + assert_eq!(poh_recorder.tick_cache.len() as u64, min_tick_height); + + // Check record succeeds on boundary condition where + // poh_recorder.tick height == poh_recorder.working_bank.min_tick_height + assert_eq!(poh_recorder.tick_height, min_tick_height); let tx = test_tx(); let h1 = hash(b"hello world!"); assert!(poh_recorder - .record(bank.slot(), h1, vec![tx.into()]) + .record(bank1.slot(), h1, vec![tx.into()]) .is_ok()); assert_eq!(poh_recorder.tick_cache.len(), 0); //tick in the cache + entry - let (_bank, (e, _tick_height)) = entry_receiver.recv().expect("recv 1"); - assert!(e.is_tick()); - let (_bank, (e, _tick_height)) = entry_receiver.recv().expect("recv 2"); + for _ in 0..min_tick_height { + let (_bank, (e, _tick_height)) = entry_receiver.recv().unwrap(); + assert!(e.is_tick()); + } + + let (_bank, (e, _tick_height)) = entry_receiver.recv().unwrap(); assert!(!e.is_tick()); } Blockstore::destroy(&ledger_path).unwrap(); @@ -1156,7 +1169,7 @@ mod tests { let (mut poh_recorder, entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &Pubkey::default(), @@ -1166,27 +1179,20 @@ mod tests { Arc::new(AtomicBool::default()), ); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank: bank.clone(), - start, - min_tick_height: 1, - max_tick_height: 2, - }; - poh_recorder.set_working_bank(working_bank); - poh_recorder.tick(); - poh_recorder.tick(); - assert_eq!(poh_recorder.tick_height, 2); + poh_recorder.set_bank(&bank); + let num_ticks_to_max = bank.max_tick_height() - poh_recorder.tick_height; + for _ in 0..num_ticks_to_max { + poh_recorder.tick(); + } let tx = test_tx(); let h1 = hash(b"hello world!"); assert!(poh_recorder .record(bank.slot(), h1, vec![tx.into()]) .is_err()); - - let (_bank, (entry, _tick_height)) = entry_receiver.recv().unwrap(); - assert!(entry.is_tick()); - let (_bank, (entry, _tick_height)) = entry_receiver.recv().unwrap(); - assert!(entry.is_tick()); + for _ in 0..num_ticks_to_max { + let (_bank, (entry, _tick_height)) = entry_receiver.recv().unwrap(); + assert!(entry.is_tick()); + } } Blockstore::destroy(&ledger_path).unwrap(); } @@ -1198,36 +1204,52 @@ mod tests { let blockstore = Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"); let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); - let bank = Arc::new(Bank::new_for_tests(&genesis_config)); - let prev_hash = bank.last_blockhash(); + let bank0 = Arc::new(Bank::new_for_tests(&genesis_config)); + let prev_hash = bank0.last_blockhash(); let (mut poh_recorder, entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank0.clone(), Some((4, 4)), - bank.ticks_per_slot(), + bank0.ticks_per_slot(), &Pubkey::default(), &Arc::new(blockstore), - &Arc::new(LeaderScheduleCache::new_from_bank(&bank)), + &Arc::new(LeaderScheduleCache::new_from_bank(&bank0)), &Arc::new(PohConfig::default()), Arc::new(AtomicBool::default()), ); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank, - start, - min_tick_height: 2, - max_tick_height: 3, - }; - poh_recorder.set_working_bank(working_bank); - poh_recorder.tick(); - poh_recorder.tick(); - assert_eq!(poh_recorder.tick_height, 2); + bank0.fill_bank_with_ticks(); + let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1)); + poh_recorder.set_bank(&bank1); + + // Check we can make two ticks without hitting min_tick_height + let remaining_ticks_to_min = + poh_recorder.working_bank.as_ref().unwrap().min_tick_height + - poh_recorder.tick_height(); + for _ in 0..remaining_ticks_to_min { + poh_recorder.tick(); + } + assert_eq!(poh_recorder.tick_height, remaining_ticks_to_min); + assert_eq!( + poh_recorder.tick_cache.len(), + remaining_ticks_to_min as usize + ); + assert!(poh_recorder.working_bank.is_some()); + + // Drop entry receiver, and try to tick again. Because + // the reciever is closed, the ticks will not be drained from the cache, + // and the working bank will be cleared drop(entry_receiver); poh_recorder.tick(); + + // Check everything is cleared assert!(poh_recorder.working_bank.is_none()); - assert_eq!(poh_recorder.tick_cache.len(), 3); + // Extra +1 for the tick that happened after the drop of the entry receiver. + assert_eq!( + poh_recorder.tick_cache.len(), + remaining_ticks_to_min as usize + 1 + ); } Blockstore::destroy(&ledger_path).unwrap(); } @@ -1238,10 +1260,12 @@ mod tests { { let blockstore = Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"); + let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); + let bank = Arc::new(Bank::new_for_tests(&genesis_config)); let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, Hash::default(), - 0, + bank.clone(), Some((4, 4)), DEFAULT_TICKS_PER_SLOT, &Pubkey::default(), @@ -1253,8 +1277,7 @@ mod tests { poh_recorder.tick(); poh_recorder.tick(); assert_eq!(poh_recorder.tick_cache.len(), 2); - let hash = poh_recorder.poh.lock().unwrap().hash; - poh_recorder.reset(hash, 0, Some((4, 4))); + poh_recorder.reset(bank, Some((4, 4))); assert_eq!(poh_recorder.tick_cache.len(), 0); } Blockstore::destroy(&ledger_path).unwrap(); @@ -1266,10 +1289,12 @@ mod tests { { let blockstore = Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"); + let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); + let bank = Arc::new(Bank::new_for_tests(&genesis_config)); let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, Hash::default(), - 0, + bank.clone(), Some((4, 4)), DEFAULT_TICKS_PER_SLOT, &Pubkey::default(), @@ -1281,7 +1306,7 @@ mod tests { poh_recorder.tick(); poh_recorder.tick(); assert_eq!(poh_recorder.tick_cache.len(), 2); - poh_recorder.reset(poh_recorder.tick_cache[0].0.hash, 0, Some((4, 4))); + poh_recorder.reset(bank, Some((4, 4))); assert_eq!(poh_recorder.tick_cache.len(), 0); } Blockstore::destroy(&ledger_path).unwrap(); @@ -1295,10 +1320,12 @@ mod tests { { let blockstore = Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"); + let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); + let bank = Arc::new(Bank::new_for_tests(&genesis_config)); let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, Hash::default(), - 0, + bank.clone(), Some((4, 4)), DEFAULT_TICKS_PER_SLOT, &Pubkey::default(), @@ -1313,7 +1340,7 @@ mod tests { poh_recorder.tick(); assert_eq!(poh_recorder.tick_cache.len(), 4); assert_eq!(poh_recorder.tick_height, 4); - poh_recorder.reset(hash(b"hello"), 0, Some((4, 4))); // parent slot 0 implies tick_height of 3 + poh_recorder.reset(bank, Some((4, 4))); // parent slot 0 implies tick_height of 3 assert_eq!(poh_recorder.tick_cache.len(), 0); poh_recorder.tick(); assert_eq!(poh_recorder.tick_height, DEFAULT_TICKS_PER_SLOT + 1); @@ -1332,7 +1359,7 @@ mod tests { let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, Hash::default(), - 0, + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &Pubkey::default(), @@ -1341,15 +1368,10 @@ mod tests { &Arc::new(PohConfig::default()), Arc::new(AtomicBool::default()), ); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank, - start, - min_tick_height: 2, - max_tick_height: 3, - }; - poh_recorder.set_working_bank(working_bank); - poh_recorder.reset(hash(b"hello"), 0, Some((4, 4))); + + poh_recorder.set_bank(&bank); + assert_eq!(bank.slot(), 0); + poh_recorder.reset(bank, Some((4, 4))); assert!(poh_recorder.working_bank.is_none()); } Blockstore::destroy(&ledger_path).unwrap(); @@ -1368,7 +1390,7 @@ mod tests { PohRecorder::new_with_clear_signal( 0, Hash::default(), - 0, + bank.clone(), None, bank.ticks_per_slot(), &Pubkey::default(), @@ -1386,7 +1408,7 @@ mod tests { } #[test] - fn test_poh_recorder_reset_start_slot() { + fn test_poh_recorder_record_sets_start_slot() { solana_logger::setup(); let ledger_path = get_tmp_ledger_path!(); { @@ -1403,7 +1425,7 @@ mod tests { let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank.clone(), Some((4, 4)), bank.ticks_per_slot(), &Pubkey::default(), @@ -1413,18 +1435,11 @@ mod tests { Arc::new(AtomicBool::default()), ); - let end_slot = 3; - let max_tick_height = (end_slot + 1) * ticks_per_slot; - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank: bank.clone(), - start, - min_tick_height: 1, - max_tick_height, - }; + poh_recorder.set_bank(&bank); - poh_recorder.set_working_bank(working_bank); - for _ in 0..max_tick_height { + // Simulate ticking much further than working_bank.max_tick_height + let max_tick_height = poh_recorder.working_bank.as_ref().unwrap().max_tick_height; + for _ in 0..3 * max_tick_height { poh_recorder.tick(); } @@ -1434,8 +1449,11 @@ mod tests { .record(bank.slot(), h1, vec![tx.into()]) .is_err()); assert!(poh_recorder.working_bank.is_none()); - // Make sure the starting slot is updated - assert_eq!(poh_recorder.start_slot, end_slot); + + // Even thought we ticked much further than working_bank.max_tick_height, + // the `start_slot` is still the slot of the last workign bank set by + // the earlier call to `poh_recorder.set_bank()` + assert_eq!(poh_recorder.start_slot(), bank.slot()); } Blockstore::destroy(&ledger_path).unwrap(); } @@ -1455,7 +1473,7 @@ mod tests { let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank.clone(), None, bank.ticks_per_slot(), &Pubkey::default(), @@ -1513,17 +1531,17 @@ mod tests { let blockstore = Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"); let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2); - let bank = Arc::new(Bank::new_for_tests(&genesis_config)); - let prev_hash = bank.last_blockhash(); + let bank0 = Arc::new(Bank::new_for_tests(&genesis_config)); + let prev_hash = bank0.last_blockhash(); let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank0.clone(), None, - bank.ticks_per_slot(), + bank0.ticks_per_slot(), &Pubkey::default(), &Arc::new(blockstore), - &Arc::new(LeaderScheduleCache::new_from_bank(&bank)), + &Arc::new(LeaderScheduleCache::new_from_bank(&bank0)), &Arc::new(PohConfig::default()), Arc::new(AtomicBool::default()), ); @@ -1532,23 +1550,24 @@ mod tests { assert!(!poh_recorder.reached_leader_slot().0); // Test that with no next leader slot in reset(), we don't reach the leader slot - poh_recorder.reset(bank.last_blockhash(), 0, None); + assert_eq!(bank0.slot(), 0); + poh_recorder.reset(bank0.clone(), None); assert!(!poh_recorder.reached_leader_slot().0); // Provide a leader slot one slot down - poh_recorder.reset(bank.last_blockhash(), 0, Some((2, 2))); + poh_recorder.reset(bank0.clone(), Some((2, 2))); let init_ticks = poh_recorder.tick_height(); // Send one slot worth of ticks - for _ in 0..bank.ticks_per_slot() { + for _ in 0..bank0.ticks_per_slot() { poh_recorder.tick(); } // Tick should be recorded assert_eq!( poh_recorder.tick_height(), - init_ticks + bank.ticks_per_slot() + init_ticks + bank0.ticks_per_slot() ); let parent_meta = SlotMeta { @@ -1564,7 +1583,9 @@ mod tests { assert!(!poh_recorder.reached_leader_slot().0); // reset poh now. we should immediately be leader - poh_recorder.reset(bank.last_blockhash(), 1, Some((2, 2))); + let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1)); + assert_eq!(bank1.slot(), 1); + poh_recorder.reset(bank1.clone(), Some((2, 2))); let (reached_leader_slot, grace_ticks, leader_slot, ..) = poh_recorder.reached_leader_slot(); assert!(reached_leader_slot); @@ -1573,10 +1594,10 @@ mod tests { // Now test that with grace ticks we can reach leader slot // Set the leader slot one slot down - poh_recorder.reset(bank.last_blockhash(), 1, Some((3, 3))); + poh_recorder.reset(bank1.clone(), Some((3, 3))); // Send one slot worth of ticks ("skips" slot 2) - for _ in 0..bank.ticks_per_slot() { + for _ in 0..bank1.ticks_per_slot() { poh_recorder.tick(); } @@ -1584,7 +1605,7 @@ mod tests { assert!(!poh_recorder.reached_leader_slot().0); // Send the grace ticks - for _ in 0..bank.ticks_per_slot() / GRACE_TICKS_FACTOR { + for _ in 0..bank1.ticks_per_slot() / GRACE_TICKS_FACTOR { poh_recorder.tick(); } @@ -1592,21 +1613,24 @@ mod tests { let (reached_leader_slot, grace_ticks, leader_slot, ..) = poh_recorder.reached_leader_slot(); assert!(reached_leader_slot); - assert_eq!(grace_ticks, bank.ticks_per_slot() / GRACE_TICKS_FACTOR); + assert_eq!(grace_ticks, bank1.ticks_per_slot() / GRACE_TICKS_FACTOR); assert_eq!(leader_slot, 3); // Let's test that correct grace ticks are reported // Set the leader slot one slot down - poh_recorder.reset(bank.last_blockhash(), 2, Some((4, 4))); + let bank2 = Arc::new(Bank::new_from_parent(&bank1, &Pubkey::default(), 2)); + poh_recorder.reset(bank2.clone(), Some((4, 4))); // send ticks for a slot - for _ in 0..bank.ticks_per_slot() { + for _ in 0..bank1.ticks_per_slot() { poh_recorder.tick(); } // We are not the leader yet, as expected assert!(!poh_recorder.reached_leader_slot().0); - poh_recorder.reset(bank.last_blockhash(), 3, Some((4, 4))); + let bank3 = Arc::new(Bank::new_from_parent(&bank2, &Pubkey::default(), 3)); + assert_eq!(bank3.slot(), 3); + poh_recorder.reset(bank3.clone(), Some((4, 4))); // without sending more ticks, we should be leader now let (reached_leader_slot, grace_ticks, leader_slot, ..) = @@ -1618,11 +1642,12 @@ mod tests { // Let's test that if a node overshoots the ticks for its target // leader slot, reached_leader_slot() will return true, because it's overdue // Set the leader slot one slot down - poh_recorder.reset(bank.last_blockhash(), 4, Some((5, 5))); + let bank4 = Arc::new(Bank::new_from_parent(&bank3, &Pubkey::default(), 4)); + poh_recorder.reset(bank4.clone(), Some((5, 5))); // Overshoot ticks for the slot let overshoot_factor = 4; - for _ in 0..overshoot_factor * bank.ticks_per_slot() { + for _ in 0..overshoot_factor * bank4.ticks_per_slot() { poh_recorder.tick(); } @@ -1630,7 +1655,7 @@ mod tests { let (reached_leader_slot, grace_ticks, leader_slot, ..) = poh_recorder.reached_leader_slot(); assert!(reached_leader_slot); - assert_eq!(grace_ticks, overshoot_factor * bank.ticks_per_slot()); + assert_eq!(grace_ticks, overshoot_factor * bank4.ticks_per_slot()); assert_eq!(leader_slot, 9); } Blockstore::destroy(&ledger_path).unwrap(); @@ -1648,7 +1673,7 @@ mod tests { let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, prev_hash, - 0, + bank.clone(), None, bank.ticks_per_slot(), &Pubkey::default(), @@ -1661,13 +1686,14 @@ mod tests { // Test that with no leader slot, we don't reach the leader tick assert!(!poh_recorder.would_be_leader(2 * bank.ticks_per_slot())); - poh_recorder.reset(bank.last_blockhash(), 0, None); + assert_eq!(bank.slot(), 0); + poh_recorder.reset(bank.clone(), None); assert!(!poh_recorder.would_be_leader(2 * bank.ticks_per_slot())); // We reset with leader slot after 3 slots let bank_slot = bank.slot() + 3; - poh_recorder.reset(bank.last_blockhash(), 0, Some((bank_slot, bank_slot))); + poh_recorder.reset(bank.clone(), Some((bank_slot, bank_slot))); // Test that the node won't be leader in next 2 slots assert!(!poh_recorder.would_be_leader(2 * bank.ticks_per_slot())); @@ -1699,7 +1725,7 @@ mod tests { let (mut poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, bank.last_blockhash(), - 0, + bank.clone(), Some((2, 2)), bank.ticks_per_slot(), &Pubkey::default(), diff --git a/poh/src/poh_service.rs b/poh/src/poh_service.rs index 75e57d3bc9..8c6b92d64a 100644 --- a/poh/src/poh_service.rs +++ b/poh/src/poh_service.rs @@ -357,7 +357,6 @@ impl PohService { mod tests { use { super::*, - crate::poh_recorder::WorkingBank, rand::{thread_rng, Rng}, solana_ledger::{ blockstore::Blockstore, @@ -396,27 +395,24 @@ mod tests { }); let exit = Arc::new(AtomicBool::new(false)); + let ticks_per_slot = bank.ticks_per_slot(); + let leader_schedule_cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank)); + let blockstore = Arc::new(blockstore); let (poh_recorder, entry_receiver, record_receiver) = PohRecorder::new( bank.tick_height(), prev_hash, - bank.slot(), + bank.clone(), Some((4, 4)), - bank.ticks_per_slot(), + ticks_per_slot, &Pubkey::default(), - &Arc::new(blockstore), - &Arc::new(LeaderScheduleCache::new_from_bank(&bank)), + &blockstore, + &leader_schedule_cache, &poh_config, exit.clone(), ); let poh_recorder = Arc::new(Mutex::new(poh_recorder)); - let start = Arc::new(Instant::now()); - let working_bank = WorkingBank { - bank: bank.clone(), - start, - min_tick_height: bank.tick_height(), - max_tick_height: std::u64::MAX, - }; let ticks_per_slot = bank.ticks_per_slot(); + let bank_slot = bank.slot(); // specify RUN_TIME to run in a benchmark-like mode // to calibrate batch size @@ -441,7 +437,7 @@ mod tests { // send some data let mut time = Measure::start("record"); let _ = poh_recorder.lock().unwrap().record( - bank.slot(), + bank_slot, h1, vec![tx.clone()], ); @@ -478,7 +474,7 @@ mod tests { hashes_per_batch, record_receiver, ); - poh_recorder.lock().unwrap().set_working_bank(working_bank); + poh_recorder.lock().unwrap().set_bank(&bank); // get some events let mut hashes = 0; diff --git a/rpc/src/cluster_tpu_info.rs b/rpc/src/cluster_tpu_info.rs index 9f0cb34043..cf567bd5a4 100644 --- a/rpc/src/cluster_tpu_info.rs +++ b/rpc/src/cluster_tpu_info.rs @@ -105,7 +105,7 @@ mod test { let (poh_recorder, _entry_receiver, _record_receiver) = PohRecorder::new( 0, bank.last_blockhash(), - 0, + bank.clone(), Some((2, 2)), bank.ticks_per_slot(), &Pubkey::default(), diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index d8ba8cb2da..37e1cac0c9 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -5401,6 +5401,20 @@ impl Bank { self.feature_set = Arc::new(feature_set); } + pub fn fill_bank_with_ticks(&self) { + let parent_distance = if self.slot() == 0 { + 1 + } else { + self.slot() - self.parent_slot() + }; + for _ in 0..parent_distance { + let last_blockhash = self.last_blockhash(); + while self.last_blockhash() == last_blockhash { + self.register_tick(&Hash::new_unique()) + } + } + } + // This is called from snapshot restore AND for each epoch boundary // The entire code path herein must be idempotent fn apply_feature_activations(