Skip to content

Commit

Permalink
Add validation for zero conf
Browse files Browse the repository at this point in the history
Added validation checks to ensure an input in a block that is also an output
in the same block will be accepted when syncing blocks.
  • Loading branch information
hansieodendaal committed Mar 26, 2024
1 parent f842c76 commit 211c278
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,27 +110,44 @@ fn validate_input_not_pruned<B: BlockchainBackend>(
db: &B,
) -> Result<Vec<TransactionInput>, ValidationError> {
let mut inputs: Vec<TransactionInput> = body.inputs().clone();
let outputs: Vec<TransactionOutput> = body.outputs().clone();
for input in &mut inputs {
if input.is_compact() {
let output_mined_info = db
.fetch_output(&input.output_hash())?
.ok_or(ValidationError::UnknownInput)?;
let output = match db.fetch_output(&input.output_hash()) {
Ok(val) => match val {
Some(output_mined_info) => output_mined_info.output,
None => {
let input_output_hash = input.output_hash();
if let Some(found) = outputs.iter().find(|o| o.hash() == input_output_hash) {
found.clone()
} else {
warn!(
target: LOG_TARGET,
"Input not found in database or block, commitment: {}, hash: {}",
input.commitment()?.to_hex(), input_output_hash.to_hex()
);
return Err(ValidationError::UnknownInput);
}
},
},
Err(e) => return Err(ValidationError::from(e)),
};

let rp_hash = match output_mined_info.output.proof {
let rp_hash = match output.proof {
Some(proof) => proof.hash(),
None => FixedHash::zero(),
};
input.add_output_data(
output_mined_info.output.version,
output_mined_info.output.features,
output_mined_info.output.commitment,
output_mined_info.output.script,
output_mined_info.output.sender_offset_public_key,
output_mined_info.output.covenant,
output_mined_info.output.encrypted_data,
output_mined_info.output.metadata_signature,
output.version,
output.features,
output.commitment,
output.script,
output.sender_offset_public_key,
output.covenant,
output.encrypted_data,
output.metadata_signature,
rp_hash,
output_mined_info.output.minimum_value_promise,
output.minimum_value_promise,
);
}
}
Expand Down Expand Up @@ -207,11 +224,16 @@ fn check_inputs_are_utxos<B: BlockchainBackend>(db: &B, body: &AggregateBody) ->
}

let output_hashes = output_hashes.as_ref().unwrap();
let output_hash = input.output_hash();
if output_hashes.iter().any(|output| output == &output_hash) {
let input_output_hash = input.output_hash();
if output_hashes.iter().any(|val| val == &input_output_hash) {
continue;
}
not_found_inputs.push(output_hash);
warn!(
target: LOG_TARGET,
"Input not found in database, commitment: {}, hash: {}",
input.commitment()?.to_hex(), input_output_hash.to_hex()
);
not_found_inputs.push(input_output_hash);
},
Err(err) => {
return Err(err);
Expand Down
5 changes: 3 additions & 2 deletions base_layer/core/src/validation/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ pub fn is_all_unique_and_sorted<'a, I: IntoIterator<Item = &'a T>, T: PartialOrd
true
}

/// This function checks that an input is a valid spendable UTXO
/// This function checks that an input is a valid spendable UTXO in the database. It cannot confirm
/// zero confermation transactions.
pub fn check_input_is_utxo<B: BlockchainBackend>(db: &B, input: &TransactionInput) -> Result<(), ValidationError> {
let output_hash = input.output_hash();
if let Some(utxo_hash) = db.fetch_unspent_output_hash_by_commitment(input.commitment()?)? {
Expand Down Expand Up @@ -203,7 +204,7 @@ pub fn check_input_is_utxo<B: BlockchainBackend>(db: &B, input: &TransactionInpu

warn!(
target: LOG_TARGET,
"Validation failed due to input: {} which does not exist yet", input
"Input ({}, {}) does not exist in the database yet", input.commitment()?.to_hex(), output_hash.to_hex()
);
Err(ValidationError::UnknownInput)
}
Expand Down

0 comments on commit 211c278

Please sign in to comment.