Log message and comment cleanups

Also:
* Clarify the out of order block debug message
This commit is contained in:
teor 2020-09-03 12:50:16 +10:00 committed by Henry de Valence
parent adafe1d189
commit 1b76cb0250
3 changed files with 47 additions and 36 deletions

View File

@ -84,21 +84,36 @@ where
// height for parsed blocks when we deserialize them. // height for parsed blocks when we deserialize them.
let height = block let height = block
.coinbase_height() .coinbase_height()
.ok_or("Invalid block: missing block height.")?; .ok_or_else(|| format!("invalid block {:?}: missing block height",
hash))?;
if height > block::Height::MAX { if height > block::Height::MAX {
Err("Invalid block height: greater than the maximum height.")?; Err(format!("invalid block height {:?} in {:?}: greater than the maximum height {:?}",
height,
hash,
block::Height::MAX))?;
} }
// Check that this block is actually a new block // Check that this block is actually a new block
if BlockVerifier::get_block(&mut state, hash).await?.is_some() { if BlockVerifier::get_block(&mut state_service, hash).await?.is_some() {
Err(format!("Block has already been verified. {:?} {:?}", height, hash))?; Err(format!("duplicate block {:?} {:?}: block has already been verified",
height,
hash))?;
} }
// Do the difficulty checks first, to raise the threshold for // Do the difficulty checks first, to raise the threshold for
// attacks that use any other fields. // attacks that use any other fields.
let difficulty_threshold = block.header.difficulty_threshold.to_expanded().ok_or("Invalid difficulty threshold in block header.")?; let difficulty_threshold = block
.header
.difficulty_threshold
.to_expanded()
.ok_or_else(|| format!("invalid difficulty threshold in block header {:?} {:?}",
height,
hash))?;
if hash > difficulty_threshold { if hash > difficulty_threshold {
Err("Block failed the difficulty filter: hash must be less than or equal to the difficulty threshold.")?; Err(format!("block {:?} failed the difficulty filter: hash {:?} must be less than or equal to the difficulty threshold {:?}",
height,
hash,
difficulty_threshold))?;
} }
check::is_equihash_solution_valid(&block.header)?; check::is_equihash_solution_valid(&block.header)?;
@ -110,21 +125,20 @@ where
check::is_time_valid_at(&block.header, now)?; check::is_time_valid_at(&block.header, now)?;
check::is_coinbase_first(&block)?; check::is_coinbase_first(&block)?;
// TODO: // TODO: context-free header verification: merkle root
// - context-free header verification: merkle root
// - contextual verification
// As a temporary solution for chain gaps, wait for the previous block, // As a temporary solution for chain gaps, wait for the previous block,
// and check its height. // and check its height.
// TODO: //
// - Add a previous block height and hash constraint to the AddBlock request, // TODO: replace this check with the contextual verification RFC design
// so that we can verify in parallel, then check constraints before committing
// //
// Skip contextual checks for the genesis block // Skip contextual checks for the genesis block
let previous_block_hash = block.header.previous_block_hash; let previous_block_hash = block.header.previous_block_hash;
if previous_block_hash != crate::parameters::GENESIS_PREVIOUS_BLOCK_HASH { if previous_block_hash != crate::parameters::GENESIS_PREVIOUS_BLOCK_HASH {
if height == block::Height(0) { if height == block::Height(0) {
Err("Invalid block: height is 0, but previous block hash is not null.")?; Err(format!("invalid block {:?}: height is 0, but previous block hash {:?} is not null",
hash,
previous_block_hash))?;
} }
let expected_height = block::Height(height.0 - 1); let expected_height = block::Height(height.0 - 1);
@ -141,11 +155,15 @@ where
let previous_height = previous_block.coinbase_height().unwrap(); let previous_height = previous_block.coinbase_height().unwrap();
if previous_height != expected_height { if previous_height != expected_height {
Err("Invalid block height: must be 1 more than the previous block height.")?; Err(format!("invalid block height {:?} for {:?}: must be 1 more than the previous block height {:?} in {:?}",
height,
hash,
previous_height,
previous_block_hash))?;
} }
} }
tracing::trace!(?height, ?hash, "Verified block"); tracing::trace!("verified block");
metrics::gauge!( metrics::gauge!(
"block.verified.block.height", "block.verified.block.height",
height.0 as _ height.0 as _
@ -202,9 +220,7 @@ where
match BlockVerifier::get_block(state, hash).await? { match BlockVerifier::get_block(state, hash).await? {
Some(block) => return Ok(block), Some(block) => return Ok(block),
// Busy-waiting is only a temporary solution to waiting for blocks. // Busy-waiting is only a temporary solution to waiting for blocks.
// TODO: // Replace with the contextual verification RFC design
// - Get an AwaitBlock future from the state
// - Replace with AddBlock constraints
None => { None => {
tracing::debug!(?height, ?hash, "Waiting for state to have block"); tracing::debug!(?height, ?hash, "Waiting for state to have block");
time::delay_for(Duration::from_millis(50)).await time::delay_for(Duration::from_millis(50)).await

View File

@ -33,7 +33,7 @@ use zebra_chain::parameters::{Network, NetworkUpgrade::Sapling};
/// The maximum expected gap between blocks. /// The maximum expected gap between blocks.
/// ///
/// Used to identify unexpected high blocks. /// Used to identify unexpected out of order blocks.
const MAX_EXPECTED_BLOCK_GAP: u32 = 100_000; const MAX_EXPECTED_BLOCK_GAP: u32 = 100_000;
/// A wrapper type that holds the `ChainVerifier`'s `CheckpointVerifier`, and /// A wrapper type that holds the `ChainVerifier`'s `CheckpointVerifier`, and
@ -120,10 +120,11 @@ where
let checkpoint_verifier = self.checkpoint.clone().map(|c| c.verifier); let checkpoint_verifier = self.checkpoint.clone().map(|c| c.verifier);
let max_checkpoint_height = self.checkpoint.clone().map(|c| c.max_height); let max_checkpoint_height = self.checkpoint.clone().map(|c| c.max_height);
// Log an info-level message on unexpected high blocks // Log an info-level message on unexpected out of order blocks
let is_unexpected_high_block = match (height, self.last_block_height) { let is_unexpected_gap = match (height, self.last_block_height) {
(Some(block::Height(height)), Some(block::Height(last_block_height))) (Some(block::Height(height)), Some(block::Height(last_block_height)))
if (height > last_block_height + MAX_EXPECTED_BLOCK_GAP) => if (height > last_block_height + MAX_EXPECTED_BLOCK_GAP)
|| (height + MAX_EXPECTED_BLOCK_GAP < last_block_height) =>
{ {
self.last_block_height = Some(block::Height(height)); self.last_block_height = Some(block::Height(height));
true true
@ -137,20 +138,14 @@ where
}; };
async move { async move {
// TODO(teor): in the post-sapling checkpoint range, allow callers
// to use BlockVerifier, CheckpointVerifier, or both.
// Call a verifier based on the block height and checkpoints. // Call a verifier based on the block height and checkpoints.
if is_higher_than_max_checkpoint(height, max_checkpoint_height) { if is_higher_than_max_checkpoint(height, max_checkpoint_height) {
// Log a message on early high blocks. // Log a message on unexpected out of order blocks.
//
// The sync service rejects most of these blocks, but we // The sync service rejects most of these blocks, but we
// still want to know if a large number get through. // still want to know if a large number get through.
// if is_unexpected_gap {
// This message can also happen if we keep getting unexpected tracing::debug!("large block height gap: this block or the previous block is out of order");
// low blocks. (We can't distinguish between these cases, until
// we've verified the blocks.)
if is_unexpected_high_block {
tracing::debug!(?height, "unexpected high block, or recent unexpected low blocks");
} }
block_verifier block_verifier
@ -160,17 +155,17 @@ where
.await?; .await?;
} else { } else {
checkpoint_verifier checkpoint_verifier
.expect("Missing checkpoint verifier: verifier must be Some if max checkpoint height is Some") .expect("missing checkpoint verifier: verifier must be Some if max checkpoint height is Some")
.ready_and() .ready_and()
.await? .await?
.call(block.clone()) .call(block.clone())
.await?; .await?;
} }
tracing::trace!(?height, ?hash, "Verified block"); tracing::trace!(?height, ?hash, "verified block");
metrics::gauge!( metrics::gauge!(
"chain.verified.block.height", "chain.verified.block.height",
height.expect("Valid blocks have a block height").0 as _ height.expect("valid blocks have a block height").0 as _
); );
metrics::counter!("chain.verified.block.count", 1); metrics::counter!("chain.verified.block.count", 1);

View File

@ -653,7 +653,7 @@ impl CheckpointVerifier {
); );
let block_count = rev_valid_blocks.len(); let block_count = rev_valid_blocks.len();
tracing::info!(?block_count, ?current_range, "Verified checkpoint range"); tracing::info!(?block_count, ?current_range, "verified checkpoint range");
metrics::gauge!( metrics::gauge!(
"checkpoint.verified.block.height", "checkpoint.verified.block.height",
target_checkpoint_height.0 as _ target_checkpoint_height.0 as _