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