Move all contextual validation code into its own function
This change has two benefits: * reduces conflicts with the sled refactor and any replacement * allows the function to be called independently for testing
This commit is contained in:
parent
c8e6f5843f
commit
d7d15984eb
|
@ -185,37 +185,16 @@ impl StateService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that `block` is contextually valid based on the committed finalized
|
/// Check that `block` is contextually valid for the configured network,
|
||||||
/// and non-finalized state.
|
/// based on the committed finalized and non-finalized state.
|
||||||
fn check_contextual_validity(&mut self, block: &Block) -> Result<(), ValidateContextError> {
|
fn check_contextual_validity(&mut self, block: &Block) -> Result<(), ValidateContextError> {
|
||||||
let height = block
|
check::block_is_contextually_valid(
|
||||||
.coinbase_height()
|
block,
|
||||||
.expect("semantically valid blocks have a coinbase height");
|
self.network,
|
||||||
let hash = block.hash();
|
self.sled.finalized_tip_height(),
|
||||||
|
self.chain(block.header.previous_block_hash),
|
||||||
|
)?;
|
||||||
|
|
||||||
let span = tracing::info_span!("StateService::check_contextual_validity",
|
|
||||||
?height, network = ?self.network, ?hash);
|
|
||||||
let _entered = span.enter();
|
|
||||||
|
|
||||||
let finalized_tip_height = self.sled.finalized_tip_height().expect(
|
|
||||||
"finalized state must contain at least one block to use the non-finalized state",
|
|
||||||
);
|
|
||||||
check::block_is_not_orphaned(finalized_tip_height, block)?;
|
|
||||||
|
|
||||||
let mut relevant_chain = self.chain(block.header.previous_block_hash);
|
|
||||||
let parent_block = relevant_chain
|
|
||||||
.next()
|
|
||||||
.expect("state must contain parent block to do contextual validation");
|
|
||||||
let parent_height = parent_block
|
|
||||||
.coinbase_height()
|
|
||||||
.expect("valid blocks have a coinbase height");
|
|
||||||
let parent_hash = parent_block.hash();
|
|
||||||
check::height_one_more_than_parent_height(parent_height, block)?;
|
|
||||||
// should be impossible by design, so no handleable error is thrown
|
|
||||||
assert_eq!(parent_hash, block.header.previous_block_hash);
|
|
||||||
|
|
||||||
// TODO: validate difficulty adjustment
|
|
||||||
// TODO: other contextual validation design and implelentation
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,64 @@
|
||||||
//! Consensus critical contextual checks
|
//! Consensus critical contextual checks
|
||||||
|
|
||||||
use zebra_chain::block::{self, Block};
|
use zebra_chain::{
|
||||||
|
block::{self, Block},
|
||||||
|
parameters::Network,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::ValidateContextError;
|
use crate::ValidateContextError;
|
||||||
|
|
||||||
|
use super::check;
|
||||||
|
|
||||||
|
/// Check that `block` is contextually valid for `network`, based on the
|
||||||
|
/// `finalized_tip_height` and `relevant_chain`.
|
||||||
|
///
|
||||||
|
/// The relevant chain is an iterator over the ancestors of `block`, starting
|
||||||
|
/// with its parent block.
|
||||||
|
pub(crate) fn block_is_contextually_valid<C>(
|
||||||
|
block: &Block,
|
||||||
|
network: Network,
|
||||||
|
finalized_tip_height: Option<block::Height>,
|
||||||
|
relevant_chain: C,
|
||||||
|
) -> Result<(), ValidateContextError>
|
||||||
|
where
|
||||||
|
C: IntoIterator,
|
||||||
|
C::Item: AsRef<Block>,
|
||||||
|
{
|
||||||
|
let height = block
|
||||||
|
.coinbase_height()
|
||||||
|
.expect("semantically valid blocks have a coinbase height");
|
||||||
|
let hash = block.hash();
|
||||||
|
|
||||||
|
let span = tracing::info_span!(
|
||||||
|
"StateService::check_contextual_validity",
|
||||||
|
?height,
|
||||||
|
?network,
|
||||||
|
?hash
|
||||||
|
);
|
||||||
|
let _entered = span.enter();
|
||||||
|
|
||||||
|
let finalized_tip_height = finalized_tip_height
|
||||||
|
.expect("finalized state must contain at least one block to use the non-finalized state");
|
||||||
|
check::block_is_not_orphaned(finalized_tip_height, block)?;
|
||||||
|
|
||||||
|
let mut relevant_chain = relevant_chain.into_iter();
|
||||||
|
let parent_block = relevant_chain
|
||||||
|
.next()
|
||||||
|
.expect("state must contain parent block to do contextual validation");
|
||||||
|
let parent_block = parent_block.as_ref();
|
||||||
|
let parent_height = parent_block
|
||||||
|
.coinbase_height()
|
||||||
|
.expect("valid blocks have a coinbase height");
|
||||||
|
let parent_hash = parent_block.hash();
|
||||||
|
check::height_one_more_than_parent_height(parent_height, block)?;
|
||||||
|
// should be impossible by design, so no handleable error is thrown
|
||||||
|
assert_eq!(parent_hash, block.header.previous_block_hash);
|
||||||
|
|
||||||
|
// TODO: validate difficulty adjustment
|
||||||
|
// TODO: other contextual validation design and implelentation
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `ValidateContextError::OrphanedBlock` if the height of the given
|
/// Returns `ValidateContextError::OrphanedBlock` if the height of the given
|
||||||
/// block is less than or equal to the finalized tip height.
|
/// block is less than or equal to the finalized tip height.
|
||||||
pub(super) fn block_is_not_orphaned(
|
pub(super) fn block_is_not_orphaned(
|
||||||
|
|
Loading…
Reference in New Issue