Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Commit

Permalink
Configurable hashes per tick
Browse files Browse the repository at this point in the history
  • Loading branch information
bw-solana committed Dec 16, 2022
1 parent 86b2e54 commit 50b9bb4
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 19 deletions.
2 changes: 1 addition & 1 deletion entry/src/poh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use {
pub struct Poh {
pub hash: Hash,
num_hashes: u64,
hashes_per_tick: u64,
pub hashes_per_tick: u64,
remaining_hashes: u64,
tick_number: u64,
slot_start_time: Instant,
Expand Down
29 changes: 22 additions & 7 deletions poh/src/poh_recorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,6 @@ pub struct PohRecorder {
id: Pubkey,
blockstore: Arc<Blockstore>,
leader_schedule_cache: Arc<LeaderScheduleCache>,
poh_config: PohConfig,
ticks_per_slot: u64,
target_ns_per_tick: u64,
record_lock_contention_us: u64,
Expand Down Expand Up @@ -460,13 +459,11 @@ impl PohRecorder {
))
}

// synchronize PoH with a bank
pub fn reset(&mut self, reset_bank: Arc<Bank>, next_leader_slot: Option<(Slot, Slot)>) {
self.clear_bank();
fn reset_poh(&mut self, reset_bank: Arc<Bank>, reset_start_bank: bool) {
let blockhash = reset_bank.last_blockhash();
let poh_hash = {
let mut poh = self.poh.lock().unwrap();
poh.reset(blockhash, self.poh_config.hashes_per_tick);
poh.reset(blockhash, *reset_bank.hashes_per_tick());
poh.hash
};
info!(
Expand All @@ -479,9 +476,17 @@ impl PohRecorder {
);

self.tick_cache = vec![];
self.start_bank = reset_bank;
if reset_start_bank {
self.start_bank = reset_bank;
}
self.tick_height = (self.start_slot() + 1) * self.ticks_per_slot;
self.start_tick_height = self.tick_height + 1;
}

// synchronize PoH with a bank
pub fn reset(&mut self, reset_bank: Arc<Bank>, next_leader_slot: Option<(Slot, Slot)>) {
self.clear_bank();
self.reset_poh(reset_bank, true);

if let Some(ref sender) = self.poh_timing_point_sender {
// start_slot() is the parent slot. current slot is start_slot() + 1.
Expand Down Expand Up @@ -513,6 +518,17 @@ impl PohRecorder {
};
trace!("new working bank");
assert_eq!(working_bank.bank.ticks_per_slot(), self.ticks_per_slot());
if let Some(hashes_per_tick) = *working_bank.bank.hashes_per_tick() {
if self.poh.lock().unwrap().hashes_per_tick != hashes_per_tick {
// Reset poh when changing hashes per tick so that we ensure all ticks
// for this slot are created with the proper hashes per tick
info!(
"resetting poh due to hashes per tick change detected at {}",
working_bank.bank.slot()
);
self.reset_poh(working_bank.clone().bank, false);
}
}
self.working_bank = Some(working_bank);

// send poh slot start timing point
Expand Down Expand Up @@ -865,7 +881,6 @@ impl PohRecorder {
leader_schedule_cache: leader_schedule_cache.clone(),
ticks_per_slot,
target_ns_per_tick,
poh_config: poh_config.clone(),
record_lock_contention_us: 0,
flush_cache_tick_us: 0,
flush_cache_no_tick_us: 0,
Expand Down
92 changes: 81 additions & 11 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,10 @@ use {
account_utils::StateMut,
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
clock::{
BankId, Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND,
INITIAL_RENT_EPOCH, MAX_PROCESSING_AGE, MAX_TRANSACTION_FORWARDING_DELAY,
MAX_TRANSACTION_FORWARDING_DELAY_GPU, SECONDS_PER_DAY,
BankId, Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_HASHES_PER_TICK,
DEFAULT_TICKS_PER_SECOND, INITIAL_RENT_EPOCH, MAX_PROCESSING_AGE,
MAX_TRANSACTION_FORWARDING_DELAY, MAX_TRANSACTION_FORWARDING_DELAY_GPU,
SECONDS_PER_DAY,
},
ed25519_program,
epoch_info::EpochInfo,
Expand Down Expand Up @@ -1661,7 +1662,8 @@ impl Bank {
let (_, apply_feature_activations_time) = measure!(
new.apply_feature_activations(
ApplyFeatureActivationsCaller::NewFromParent,
false
false,
vec![false; FeatureActivation::NumVariants as usize],
),
"apply_feature_activation",
);
Expand Down Expand Up @@ -1888,7 +1890,11 @@ impl Bank {

let parent_timestamp = parent.clock().unix_timestamp;
let mut new = Bank::new_from_parent(parent, collector_id, slot);
new.apply_feature_activations(ApplyFeatureActivationsCaller::WarpFromParent, false);
new.apply_feature_activations(
ApplyFeatureActivationsCaller::WarpFromParent,
false,
vec![false; FeatureActivation::NumVariants as usize],
);
new.update_epoch_stakes(new.epoch_schedule().get_epoch(slot));
new.tick_height.store(new.max_tick_height(), Relaxed);

Expand Down Expand Up @@ -2015,10 +2021,6 @@ impl Bank {
"Bank snapshot genesis creation time does not match genesis.bin creation time.\
The snapshot and genesis.bin might pertain to different clusters"
);
assert_eq!(
bank.hashes_per_tick,
genesis_config.poh_config.hashes_per_tick
);
assert_eq!(bank.ticks_per_slot, genesis_config.ticks_per_slot);
assert_eq!(
bank.ns_per_slot,
Expand Down Expand Up @@ -6426,6 +6428,7 @@ impl Bank {
self.apply_feature_activations(
ApplyFeatureActivationsCaller::FinishInit,
debug_do_not_add_builtins,
vec![false; FeatureActivation::NumVariants as usize],
);

if self
Expand Down Expand Up @@ -7452,10 +7455,12 @@ impl Bank {

// This is called from snapshot restore AND for each epoch boundary
// The entire code path herein must be idempotent
fn apply_feature_activations(
pub fn apply_feature_activations(
&mut self,
caller: ApplyFeatureActivationsCaller,
debug_do_not_add_builtins: bool,
// This vector is for forcing a feature to get activated for testing purposes
features_activated_test: Vec<bool>,
) {
use ApplyFeatureActivationsCaller::*;
let allow_new_activations = match caller {
Expand Down Expand Up @@ -7507,6 +7512,21 @@ impl Bank {
const ACCOUNTS_DATA_LEN: u64 = 50_000_000_000;
self.accounts_data_size_initial = ACCOUNTS_DATA_LEN;
}

if new_feature_activations.contains(&feature_set::configurable_hashes_per_tick::id())
|| features_activated_test[FeatureActivation::ConfigurablePohTicksPerSecond as usize]
{
self.apply_updated_hashes_per_tick(DEFAULT_HASHES_PER_TICK);
}
}

fn apply_updated_hashes_per_tick(&mut self, hashes_per_tick: u64) {
info!(
"Activating configurable_hashes_per_tick {} at slot {}",
hashes_per_tick,
self.slot(),
);
self.hashes_per_tick = Some(hashes_per_tick);
}

fn adjust_sysvar_balance_for_rent(&self, account: &mut AccountSharedData) {
Expand Down Expand Up @@ -7797,12 +7817,19 @@ fn calculate_data_size_delta(old_data_size: usize, new_data_size: usize) -> i64
/// Since `apply_feature_activations()` has different behavior depending on its caller, enumerate
/// those callers explicitly.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum ApplyFeatureActivationsCaller {
pub enum ApplyFeatureActivationsCaller {
FinishInit,
NewFromParent,
WarpFromParent,
}

/// Allows for force enabling feature activations for testing.
pub enum FeatureActivation {
ConfigurablePohTicksPerSecond,
// Add new feature activation enums here
NumVariants,
}

/// Return the computed values from `collect_rent_from_accounts()`
///
/// Since `collect_rent_from_accounts()` is running in parallel, instead of updating the
Expand Down Expand Up @@ -20157,4 +20184,47 @@ pub(crate) mod tests {
)),
);
}

#[test]
fn test_feature_activation_idempotent() {
let GenesisConfigInfo {
mut genesis_config, ..
} = genesis_utils::create_genesis_config_with_leader(
1_000_000 * LAMPORTS_PER_SOL,
&Pubkey::new_unique(),
100 * LAMPORTS_PER_SOL,
);
genesis_config.rent = Rent::default();
const HASHES_PER_TICK_START: u64 = 3;
genesis_config.poh_config.hashes_per_tick = Some(HASHES_PER_TICK_START);

let mut bank = Bank::new_for_tests(&genesis_config);
assert_eq!(bank.hashes_per_tick, Some(HASHES_PER_TICK_START));

// Don't activate feature
let mut test_activation = vec![false; FeatureActivation::NumVariants as usize];
bank.apply_feature_activations(
ApplyFeatureActivationsCaller::NewFromParent,
false,
test_activation.clone(),
);
assert_eq!(bank.hashes_per_tick, Some(HASHES_PER_TICK_START));

// Activate feature
test_activation[FeatureActivation::ConfigurablePohTicksPerSecond as usize] = true;
bank.apply_feature_activations(
ApplyFeatureActivationsCaller::NewFromParent,
false,
test_activation.clone(),
);
assert_eq!(bank.hashes_per_tick, Some(DEFAULT_HASHES_PER_TICK));

// Activate feature "again"
bank.apply_feature_activations(
ApplyFeatureActivationsCaller::NewFromParent,
false,
test_activation,
);
assert_eq!(bank.hashes_per_tick, Some(DEFAULT_HASHES_PER_TICK));
}
}
5 changes: 5 additions & 0 deletions sdk/src/feature_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,10 @@ pub mod enable_program_redeployment_cooldown {
solana_sdk::declare_id!("J4HFT8usBxpcF63y46t1upYobJgChmKyZPm5uTBRg25Z");
}

pub mod configurable_hashes_per_tick {
solana_sdk::declare_id!("3uFHb9oKdGfgZGJK9EHaAXN4USvnQtAFC13Fh5gGFS5B");
}

lazy_static! {
/// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
Expand Down Expand Up @@ -687,6 +691,7 @@ lazy_static! {
(cap_transaction_accounts_data_size::id(), "cap transaction accounts data size up to its compute unit limits #27839"),
(enable_alt_bn128_syscall::id(), "add alt_bn128 syscalls #27961"),
(enable_program_redeployment_cooldown::id(), "enable program redeployment cooldown #29135"),
(configurable_hashes_per_tick::id(), "Configure desired hashes per tick to update on epoch boundary"),
/*************** ADD NEW FEATURES HERE ***************/
]
.iter()
Expand Down

0 comments on commit 50b9bb4

Please sign in to comment.