Skip to content

Commit

Permalink
Test that tick slot hashes update the recent blockhash queue (solana-…
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry authored and jeffwashington committed Jun 29, 2022
1 parent a97a786 commit 81a25c3
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 11 deletions.
135 changes: 134 additions & 1 deletion ledger/src/blockstore_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ pub fn confirm_slot(
) -> result::Result<(), BlockstoreProcessorError> {
let slot = bank.slot();

let (entries, num_shreds, slot_full) = {
let slot_entries_load_result = {
let mut load_elapsed = Measure::start("load_elapsed");
let load_result = blockstore
.get_slot_entries_with_shred_info(slot, progress.num_shreds, allow_dead_slots)
Expand All @@ -905,6 +905,35 @@ pub fn confirm_slot(
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_txs = entries.iter().map(|e| e.transactions.len()).sum::<usize>();
trace!(
Expand Down Expand Up @@ -3873,4 +3902,108 @@ pub mod tests {
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));
}
}
16 changes: 7 additions & 9 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ use {
account_utils::StateMut,
clock::{
BankId, Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND,
INITIAL_RENT_EPOCH, MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES,
MAX_TRANSACTION_FORWARDING_DELAY, SECONDS_PER_DAY,
INITIAL_RENT_EPOCH, MAX_PROCESSING_AGE, MAX_TRANSACTION_FORWARDING_DELAY,
SECONDS_PER_DAY,
},
ed25519_program,
epoch_info::EpochInfo,
Expand Down Expand Up @@ -1253,12 +1253,6 @@ pub struct Bank {
pub fee_structure: FeeStructure,
}

impl Default for BlockhashQueue {
fn default() -> Self {
Self::new(MAX_RECENT_BLOCKHASHES)
}
}

struct VoteWithStakeDelegations {
vote_state: Arc<VoteState>,
vote_account: AccountSharedData,
Expand Down Expand Up @@ -3763,6 +3757,10 @@ impl Bank {
.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> {
self.blockhash_queue
.read()
Expand Down Expand Up @@ -6929,7 +6927,7 @@ pub(crate) mod tests {
solana_sdk::{
account::Account,
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,
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
feature::Feature,
Expand Down
10 changes: 9 additions & 1 deletion runtime/src/blockhash_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
use solana_sdk::sysvar::recent_blockhashes;
use {
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,
};

Expand All @@ -29,6 +31,12 @@ pub struct BlockhashQueue {
max_age: usize,
}

impl Default for BlockhashQueue {
fn default() -> Self {
Self::new(MAX_RECENT_BLOCKHASHES)
}
}

impl BlockhashQueue {
pub fn new(max_age: usize) -> Self {
Self {
Expand Down

0 comments on commit 81a25c3

Please sign in to comment.