Test that tick slot hashes update the recent blockhash queue (#24242)
This commit is contained in:
parent
d54ec406df
commit
4ed647d8ec
|
@ -892,7 +892,7 @@ pub fn confirm_slot(
|
||||||
) -> result::Result<(), BlockstoreProcessorError> {
|
) -> result::Result<(), BlockstoreProcessorError> {
|
||||||
let slot = bank.slot();
|
let slot = bank.slot();
|
||||||
|
|
||||||
let (entries, num_shreds, slot_full) = {
|
let slot_entries_load_result = {
|
||||||
let mut load_elapsed = Measure::start("load_elapsed");
|
let mut load_elapsed = Measure::start("load_elapsed");
|
||||||
let load_result = blockstore
|
let load_result = blockstore
|
||||||
.get_slot_entries_with_shred_info(slot, progress.num_shreds, allow_dead_slots)
|
.get_slot_entries_with_shred_info(slot, progress.num_shreds, allow_dead_slots)
|
||||||
|
@ -906,6 +906,35 @@ pub fn confirm_slot(
|
||||||
load_result
|
load_result
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
confirm_slot_entries(
|
||||||
|
bank,
|
||||||
|
slot_entries_load_result,
|
||||||
|
timing,
|
||||||
|
progress,
|
||||||
|
skip_verification,
|
||||||
|
transaction_status_sender,
|
||||||
|
replay_vote_sender,
|
||||||
|
transaction_cost_metrics_sender,
|
||||||
|
entry_callback,
|
||||||
|
recyclers,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn confirm_slot_entries(
|
||||||
|
bank: &Arc<Bank>,
|
||||||
|
slot_entries_load_result: (Vec<Entry>, u64, bool),
|
||||||
|
timing: &mut ConfirmationTiming,
|
||||||
|
progress: &mut ConfirmationProgress,
|
||||||
|
skip_verification: bool,
|
||||||
|
transaction_status_sender: Option<&TransactionStatusSender>,
|
||||||
|
replay_vote_sender: Option<&ReplayVoteSender>,
|
||||||
|
transaction_cost_metrics_sender: Option<&TransactionCostMetricsSender>,
|
||||||
|
entry_callback: Option<&ProcessCallback>,
|
||||||
|
recyclers: &VerifyRecyclers,
|
||||||
|
) -> result::Result<(), BlockstoreProcessorError> {
|
||||||
|
let slot = bank.slot();
|
||||||
|
let (entries, num_shreds, slot_full) = slot_entries_load_result;
|
||||||
let num_entries = entries.len();
|
let num_entries = entries.len();
|
||||||
let num_txs = entries.iter().map(|e| e.transactions.len()).sum::<usize>();
|
let num_txs = entries.iter().map(|e| e.transactions.len()).sum::<usize>();
|
||||||
trace!(
|
trace!(
|
||||||
|
@ -3880,4 +3909,108 @@ pub mod tests {
|
||||||
8
|
8
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn confirm_slot_entries_for_tests(
|
||||||
|
bank: &Arc<Bank>,
|
||||||
|
slot_entries: Vec<Entry>,
|
||||||
|
slot_full: bool,
|
||||||
|
prev_entry_hash: Hash,
|
||||||
|
) -> result::Result<(), BlockstoreProcessorError> {
|
||||||
|
confirm_slot_entries(
|
||||||
|
bank,
|
||||||
|
(slot_entries, 0, slot_full),
|
||||||
|
&mut ConfirmationTiming::default(),
|
||||||
|
&mut ConfirmationProgress::new(prev_entry_hash),
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&VerifyRecyclers::default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_confirm_slot_entries() {
|
||||||
|
const HASHES_PER_TICK: u64 = 10;
|
||||||
|
const TICKS_PER_SLOT: u64 = 2;
|
||||||
|
|
||||||
|
let collector_id = Pubkey::new_unique();
|
||||||
|
|
||||||
|
let GenesisConfigInfo {
|
||||||
|
mut genesis_config,
|
||||||
|
mint_keypair,
|
||||||
|
..
|
||||||
|
} = create_genesis_config(10_000);
|
||||||
|
genesis_config.poh_config.hashes_per_tick = Some(HASHES_PER_TICK);
|
||||||
|
genesis_config.ticks_per_slot = TICKS_PER_SLOT;
|
||||||
|
let genesis_hash = genesis_config.hash();
|
||||||
|
|
||||||
|
let slot_0_bank = Arc::new(Bank::new_for_tests(&genesis_config));
|
||||||
|
assert_eq!(slot_0_bank.slot(), 0);
|
||||||
|
assert_eq!(slot_0_bank.tick_height(), 0);
|
||||||
|
assert_eq!(slot_0_bank.max_tick_height(), 2);
|
||||||
|
assert_eq!(slot_0_bank.last_blockhash(), genesis_hash);
|
||||||
|
assert_eq!(slot_0_bank.get_hash_age(&genesis_hash), Some(0));
|
||||||
|
|
||||||
|
let slot_0_entries = entry::create_ticks(TICKS_PER_SLOT, HASHES_PER_TICK, genesis_hash);
|
||||||
|
let slot_0_hash = slot_0_entries.last().unwrap().hash;
|
||||||
|
confirm_slot_entries_for_tests(&slot_0_bank, slot_0_entries, true, genesis_hash).unwrap();
|
||||||
|
assert_eq!(slot_0_bank.tick_height(), slot_0_bank.max_tick_height());
|
||||||
|
assert_eq!(slot_0_bank.last_blockhash(), slot_0_hash);
|
||||||
|
assert_eq!(slot_0_bank.get_hash_age(&genesis_hash), Some(1));
|
||||||
|
assert_eq!(slot_0_bank.get_hash_age(&slot_0_hash), Some(0));
|
||||||
|
|
||||||
|
let slot_2_bank = Arc::new(Bank::new_from_parent(&slot_0_bank, &collector_id, 2));
|
||||||
|
assert_eq!(slot_2_bank.slot(), 2);
|
||||||
|
assert_eq!(slot_2_bank.tick_height(), 2);
|
||||||
|
assert_eq!(slot_2_bank.max_tick_height(), 6);
|
||||||
|
assert_eq!(slot_2_bank.last_blockhash(), slot_0_hash);
|
||||||
|
|
||||||
|
let slot_1_entries = entry::create_ticks(TICKS_PER_SLOT, HASHES_PER_TICK, slot_0_hash);
|
||||||
|
let slot_1_hash = slot_1_entries.last().unwrap().hash;
|
||||||
|
confirm_slot_entries_for_tests(&slot_2_bank, slot_1_entries, false, slot_0_hash).unwrap();
|
||||||
|
assert_eq!(slot_2_bank.tick_height(), 4);
|
||||||
|
assert_eq!(slot_2_bank.last_blockhash(), slot_1_hash);
|
||||||
|
assert_eq!(slot_2_bank.get_hash_age(&genesis_hash), Some(2));
|
||||||
|
assert_eq!(slot_2_bank.get_hash_age(&slot_0_hash), Some(1));
|
||||||
|
assert_eq!(slot_2_bank.get_hash_age(&slot_1_hash), Some(0));
|
||||||
|
|
||||||
|
// Check that slot 2 transactions can use any previous slot hash, including the
|
||||||
|
// hash for slot 1 which is just ticks.
|
||||||
|
let slot_2_entries = {
|
||||||
|
let to_pubkey = Pubkey::new_unique();
|
||||||
|
let mut prev_entry_hash = slot_1_hash;
|
||||||
|
let mut remaining_entry_hashes = HASHES_PER_TICK;
|
||||||
|
let mut entries: Vec<Entry> = [genesis_hash, slot_0_hash, slot_1_hash]
|
||||||
|
.into_iter()
|
||||||
|
.map(|recent_hash| {
|
||||||
|
let tx =
|
||||||
|
system_transaction::transfer(&mint_keypair, &to_pubkey, 1, recent_hash);
|
||||||
|
remaining_entry_hashes = remaining_entry_hashes.checked_sub(1).unwrap();
|
||||||
|
next_entry_mut(&mut prev_entry_hash, 1, vec![tx])
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
entries.push(next_entry_mut(
|
||||||
|
&mut prev_entry_hash,
|
||||||
|
remaining_entry_hashes,
|
||||||
|
vec![],
|
||||||
|
));
|
||||||
|
entries.push(next_entry_mut(
|
||||||
|
&mut prev_entry_hash,
|
||||||
|
HASHES_PER_TICK,
|
||||||
|
vec![],
|
||||||
|
));
|
||||||
|
entries
|
||||||
|
};
|
||||||
|
let slot_2_hash = slot_2_entries.last().unwrap().hash;
|
||||||
|
confirm_slot_entries_for_tests(&slot_2_bank, slot_2_entries, true, slot_1_hash).unwrap();
|
||||||
|
assert_eq!(slot_2_bank.tick_height(), slot_2_bank.max_tick_height());
|
||||||
|
assert_eq!(slot_2_bank.last_blockhash(), slot_2_hash);
|
||||||
|
assert_eq!(slot_2_bank.get_hash_age(&genesis_hash), Some(3));
|
||||||
|
assert_eq!(slot_2_bank.get_hash_age(&slot_0_hash), Some(2));
|
||||||
|
assert_eq!(slot_2_bank.get_hash_age(&slot_1_hash), Some(1));
|
||||||
|
assert_eq!(slot_2_bank.get_hash_age(&slot_2_hash), Some(0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,8 +93,8 @@ use {
|
||||||
account_utils::StateMut,
|
account_utils::StateMut,
|
||||||
clock::{
|
clock::{
|
||||||
BankId, Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND,
|
BankId, Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND,
|
||||||
INITIAL_RENT_EPOCH, MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES,
|
INITIAL_RENT_EPOCH, MAX_PROCESSING_AGE, MAX_TRANSACTION_FORWARDING_DELAY,
|
||||||
MAX_TRANSACTION_FORWARDING_DELAY, SECONDS_PER_DAY,
|
SECONDS_PER_DAY,
|
||||||
},
|
},
|
||||||
ed25519_program,
|
ed25519_program,
|
||||||
epoch_info::EpochInfo,
|
epoch_info::EpochInfo,
|
||||||
|
@ -1252,12 +1252,6 @@ pub struct Bank {
|
||||||
pub fee_structure: FeeStructure,
|
pub fee_structure: FeeStructure,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BlockhashQueue {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new(MAX_RECENT_BLOCKHASHES)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VoteWithStakeDelegations {
|
struct VoteWithStakeDelegations {
|
||||||
vote_state: Arc<VoteState>,
|
vote_state: Arc<VoteState>,
|
||||||
vote_account: AccountSharedData,
|
vote_account: AccountSharedData,
|
||||||
|
@ -3730,6 +3724,10 @@ impl Bank {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_hash_age(&self, hash: &Hash) -> Option<u64> {
|
||||||
|
self.blockhash_queue.read().unwrap().get_hash_age(hash)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_hash_age(&self, hash: &Hash, max_age: usize) -> Option<bool> {
|
pub fn check_hash_age(&self, hash: &Hash, max_age: usize) -> Option<bool> {
|
||||||
self.blockhash_queue
|
self.blockhash_queue
|
||||||
.read()
|
.read()
|
||||||
|
@ -6854,7 +6852,7 @@ pub(crate) mod tests {
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
|
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
|
||||||
clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_TICKS_PER_SLOT},
|
clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_TICKS_PER_SLOT, MAX_RECENT_BLOCKHASHES},
|
||||||
compute_budget::ComputeBudgetInstruction,
|
compute_budget::ComputeBudgetInstruction,
|
||||||
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
|
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
|
||||||
feature::Feature,
|
feature::Feature,
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
use solana_sdk::sysvar::recent_blockhashes;
|
use solana_sdk::sysvar::recent_blockhashes;
|
||||||
use {
|
use {
|
||||||
serde::{Deserialize, Serialize},
|
serde::{Deserialize, Serialize},
|
||||||
solana_sdk::{fee_calculator::FeeCalculator, hash::Hash, timing::timestamp},
|
solana_sdk::{
|
||||||
|
clock::MAX_RECENT_BLOCKHASHES, fee_calculator::FeeCalculator, hash::Hash, timing::timestamp,
|
||||||
|
},
|
||||||
std::collections::HashMap,
|
std::collections::HashMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,6 +31,12 @@ pub struct BlockhashQueue {
|
||||||
max_age: usize,
|
max_age: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for BlockhashQueue {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new(MAX_RECENT_BLOCKHASHES)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BlockhashQueue {
|
impl BlockhashQueue {
|
||||||
pub fn new(max_age: usize) -> Self {
|
pub fn new(max_age: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
Loading…
Reference in New Issue