Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update PoH speed check to derive rate from Bank #2447

Merged
merged 4 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Release channels have their own copy of this changelog:
* removed the unreleased `redelegate` instruction processor and CLI commands (#2213)
* Changes
* SDK: removed the `respan` macro. This was marked as "internal use only" and was no longer used internally.
* `agave-validator`: Update PoH speed check to compare against current hash rate from a Bank (#2447)

## [2.0.0]
* Breaking
Expand Down
83 changes: 51 additions & 32 deletions core/src/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,11 @@ impl Validator {
Some(poh_timing_point_sender.clone()),
)
.map_err(ValidatorError::Other)?;

if !config.no_poh_speed_test {
check_poh_speed(&bank_forks.read().unwrap().root_bank(), None)?;
}

let hard_forks = bank_forks.read().unwrap().root_bank().hard_forks();
if !hard_forks.is_empty() {
info!("Hard forks: {:?}", hard_forks);
Expand All @@ -745,7 +750,6 @@ impl Validator {
&genesis_config.hash(),
Some(&hard_forks),
));

Self::print_node_info(&node);

if let Some(expected_shred_version) = config.expected_shred_version {
Expand Down Expand Up @@ -1677,33 +1681,35 @@ fn active_vote_account_exists_in_bank(bank: &Bank, vote_account: &Pubkey) -> boo
false
}

fn check_poh_speed(
genesis_config: &GenesisConfig,
maybe_hash_samples: Option<u64>,
) -> Result<(), ValidatorError> {
if let Some(hashes_per_tick) = genesis_config.hashes_per_tick() {
let ticks_per_slot = genesis_config.ticks_per_slot();
let hashes_per_slot = hashes_per_tick * ticks_per_slot;
let hash_samples = maybe_hash_samples.unwrap_or(hashes_per_slot);

let hash_time = compute_hash_time(hash_samples);
let my_hashes_per_second = (hash_samples as f64 / hash_time.as_secs_f64()) as u64;
let target_slot_duration = Duration::from_nanos(genesis_config.ns_per_slot() as u64);
let target_hashes_per_second =
(hashes_per_slot as f64 / target_slot_duration.as_secs_f64()) as u64;
fn check_poh_speed(bank: &Bank, maybe_hash_samples: Option<u64>) -> Result<(), ValidatorError> {
let Some(hashes_per_tick) = bank.hashes_per_tick() else {
warn!("Unable to read hashes per tick from Bank, skipping PoH speed check");
return Ok(());
};

info!(
"PoH speed check: \
let ticks_per_slot = bank.ticks_per_slot();
let hashes_per_slot = hashes_per_tick * ticks_per_slot;
let hash_samples = maybe_hash_samples.unwrap_or(hashes_per_slot);

let hash_time = compute_hash_time(hash_samples);
let my_hashes_per_second = (hash_samples as f64 / hash_time.as_secs_f64()) as u64;

let target_slot_duration = Duration::from_nanos(bank.ns_per_slot as u64);
let target_hashes_per_second =
(hashes_per_slot as f64 / target_slot_duration.as_secs_f64()) as u64;

info!(
"PoH speed check: \
computed hashes per second {my_hashes_per_second}, \
target hashes per second {target_hashes_per_second}"
);
if my_hashes_per_second < target_hashes_per_second {
return Err(ValidatorError::PohTooSlow {
mine: my_hashes_per_second,
target: target_hashes_per_second,
});
}
);
if my_hashes_per_second < target_hashes_per_second {
return Err(ValidatorError::PohTooSlow {
mine: my_hashes_per_second,
target: target_hashes_per_second,
});
}

Ok(())
}

Expand Down Expand Up @@ -1835,10 +1841,6 @@ fn load_genesis(
}
}

if !config.no_poh_speed_test {
check_poh_speed(&genesis_config, None)?;
}

Ok(genesis_config)
}

Expand Down Expand Up @@ -2937,11 +2939,25 @@ mod tests {
));
}

fn target_tick_duration() -> Duration {
// DEFAULT_MS_PER_SLOT = 400
// DEFAULT_TICKS_PER_SLOT = 64
// MS_PER_TICK = 6
//
// But, DEFAULT_MS_PER_SLOT / DEFAULT_TICKS_PER_SLOT = 6.25
//
// So, convert to microseconds first to avoid the integer rounding error
let target_tick_duration_us = solana_sdk::clock::DEFAULT_MS_PER_SLOT * 1000
/ solana_sdk::clock::DEFAULT_TICKS_PER_SLOT;
assert_eq!(target_tick_duration_us, 6250);
Duration::from_micros(target_tick_duration_us)
}

#[test]
fn test_poh_speed() {
solana_logger::setup();
let poh_config = PohConfig {
target_tick_duration: Duration::from_millis(solana_sdk::clock::MS_PER_TICK),
target_tick_duration: target_tick_duration(),
Comment on lines -2944 to +2960
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, this change isn't critical for the PR. But, the constant MS_PER_TICK is 6ms; 6 ms/tick * 64 ticks/slot = 384 ms/slot. It annoyed me that this didn't come out to the 400ms, and I noticed when observing the info log from speed check. Can revert it back if desired

// make PoH rate really fast to cause the panic condition
hashes_per_tick: Some(100 * solana_sdk::clock::DEFAULT_HASHES_PER_TICK),
..PohConfig::default()
Expand All @@ -2950,20 +2966,23 @@ mod tests {
poh_config,
..GenesisConfig::default()
};
assert!(check_poh_speed(&genesis_config, Some(10_000)).is_err());
let bank = Bank::new_for_tests(&genesis_config);
assert!(check_poh_speed(&bank, Some(10_000)).is_err());
}

#[test]
fn test_poh_speed_no_hashes_per_tick() {
solana_logger::setup();
let poh_config = PohConfig {
target_tick_duration: Duration::from_millis(solana_sdk::clock::MS_PER_TICK),
target_tick_duration: target_tick_duration(),
hashes_per_tick: None,
..PohConfig::default()
};
let genesis_config = GenesisConfig {
poh_config,
..GenesisConfig::default()
};
check_poh_speed(&genesis_config, Some(10_000)).unwrap();
let bank = Bank::new_for_tests(&genesis_config);
check_poh_speed(&bank, Some(10_000)).unwrap();
}
}
Loading