Skip to content

Commit

Permalink
Input and output previous STXO block validation check
Browse files Browse the repository at this point in the history
Merge pull request #1974

- Added a full consensus block validation check that ensures that the inputs and outputs are not part of the STXO set. This duplicate hash check should be performed to ensure that when a block is added to the blockchain backend that it does not leave the backend in an inconsistent state. - This change could be consensus breaking.
  • Loading branch information
CjS77 committed Jun 11, 2020
2 parents 2c0af3e + 7c992c1 commit 1e3ecd6
Showing 1 changed file with 28 additions and 2 deletions.
30 changes: 28 additions & 2 deletions base_layer/core/src/validation/block_validators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::{
BlockValidationError,
NewBlockTemplate,
},
chain_storage::{calculate_mmr_roots, is_utxo, BlockchainBackend},
chain_storage::{calculate_mmr_roots, is_stxo, is_utxo, BlockchainBackend},
consensus::{ConsensusConstants, ConsensusManager},
transactions::{transaction::OutputFlags, types::CryptoFactories},
validation::{
Expand Down Expand Up @@ -108,6 +108,7 @@ impl<B: BlockchainBackend> Validation<Block, B> for FullConsensusValidator {
/// The consensus checks that are done (in order of cheapest to verify to most expensive):
/// 1. Does the block satisfy the stateless checks?
/// 1. Are all inputs currently in the UTXO set?
/// 1. Are all inputs and outputs not in the STXO set?
/// 1. Are the block header MMR roots valid?
/// 1. Is the block header timestamp less than the ftl?
/// 1. Is the block header timestamp greater than the median timestamp?
Expand All @@ -116,9 +117,10 @@ impl<B: BlockchainBackend> Validation<Block, B> for FullConsensusValidator {
fn validate(&self, block: &Block, db: &B) -> Result<(), ValidationError> {
let block_id = format!("block #{} ({})", block.header.height, block.hash().to_hex());
check_inputs_are_utxos(block, db)?;
check_not_stxos(block, db)?;
trace!(
target: LOG_TARGET,
"Block validation: All inputs are valid for {}",
"Block validation: All inputs and outputs are valid for {}",
&block_id
);
check_mmr_roots(block, db)?;
Expand Down Expand Up @@ -272,6 +274,30 @@ fn check_inputs_are_utxos<B: BlockchainBackend>(block: &Block, db: &B) -> Result
Ok(())
}

// This function checks that the inputs and outputs do not exist in the STxO set.
fn check_not_stxos<B: BlockchainBackend>(block: &Block, db: &B) -> Result<(), ValidationError> {
for input in block.body.inputs() {
if is_stxo(db, input.hash()).map_err(|e| ValidationError::CustomError(e.to_string()))? {
// we dont want to log this as a node or wallet might retransmit a transaction
debug!(
target: LOG_TARGET,
"Block validation failed due to already spent input: {}", input
);
return Err(ValidationError::ContainsSTxO);
}
}
for output in block.body.outputs() {
if is_stxo(db, output.hash()).map_err(|e| ValidationError::CustomError(e.to_string()))? {
debug!(
target: LOG_TARGET,
"Block validation failed due to previously spent output: {}", output
);
return Err(ValidationError::ContainsSTxO);
}
}
Ok(())
}

/// This function tests that the block timestamp is less than the ftl.
fn check_timestamp_ftl(
block_header: &BlockHeader,
Expand Down

0 comments on commit 1e3ecd6

Please sign in to comment.