Skip to content

Commit

Permalink
Move all contextual validation code into its own function
Browse files Browse the repository at this point in the history
This change has two benefits:
* reduces conflicts with the sled refactor and any replacement
* allows the function to be called independently for testing
  • Loading branch information
teor2345 committed Nov 17, 2020
1 parent c8e6f58 commit d7d1598
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 30 deletions.
37 changes: 8 additions & 29 deletions zebra-state/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,37 +185,16 @@ impl StateService {
}
}

/// Check that `block` is contextually valid based on the committed finalized
/// and non-finalized state.
/// Check that `block` is contextually valid for the configured network,
/// based on the committed finalized and non-finalized state.
fn check_contextual_validity(&mut self, block: &Block) -> Result<(), ValidateContextError> {
let height = block
.coinbase_height()
.expect("semantically valid blocks have a coinbase height");
let hash = block.hash();
check::block_is_contextually_valid(
block,
self.network,
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(())
}

Expand Down
57 changes: 56 additions & 1 deletion zebra-state/src/service/check.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,64 @@
//! Consensus critical contextual checks
use zebra_chain::block::{self, Block};
use zebra_chain::{
block::{self, Block},
parameters::Network,
};

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
/// block is less than or equal to the finalized tip height.
pub(super) fn block_is_not_orphaned(
Expand Down

0 comments on commit d7d1598

Please sign in to comment.