Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): adds txo version checks to async validator #4852

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ impl<B: BlockchainBackend + 'static> BlockValidator<B> {
.commitment
.commit_value(&total_kernel_offset, total_reward.as_u64());
let db = self.db.inner().clone();
let constants = self.rules.consensus_constants(height).clone();
task::spawn_blocking(move || {
let db = db.db_read_access()?;
let timer = Instant::now();
Expand All @@ -175,6 +176,7 @@ impl<B: BlockchainBackend + 'static> BlockValidator<B> {
return Err(ValidationError::UnsortedOrDuplicateKernel);
}

helpers::validate_kernel_version(&constants, kernel)?;
kernel.verify_signature()?;

if kernel.is_coinbase() {
Expand Down Expand Up @@ -248,6 +250,7 @@ impl<B: BlockchainBackend + 'static> BlockValidator<B> {
let db = self.db.inner().clone();
let prev_hash: [u8; 32] = header.prev_hash.as_slice().try_into().unwrap_or([0; 32]);
let height = header.height;
let constants = self.rules.consensus_constants(height).clone();
task::spawn_blocking(move || {
let timer = Instant::now();
let mut aggregate_input_key = PublicKey::default();
Expand Down Expand Up @@ -296,6 +299,8 @@ impl<B: BlockchainBackend + 'static> BlockValidator<B> {
return Err(TransactionError::InputMaturity.into());
}

helpers::validate_input_version(&constants, input)?;

match helpers::check_input_is_utxo(&*db, input) {
Err(ValidationError::UnknownInput) => {
// Check if the input spends from the current block
Expand Down Expand Up @@ -402,6 +407,7 @@ impl<B: BlockchainBackend + 'static> BlockValidator<B> {
aggregate_sender_offset = aggregate_sender_offset + &output.sender_offset_public_key;
}

helpers::validate_output_version(&constants, output)?;
helpers::check_permitted_output_types(&constants, output)?;
helpers::check_tari_script_byte_size(&output.script, max_script_size)?;
output.verify_metadata_signature()?;
Expand Down
128 changes: 77 additions & 51 deletions base_layer/core/src/validation/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,73 +713,99 @@ pub fn check_permitted_output_types(
Ok(())
}

pub fn validate_versions(
body: &AggregateBody,
pub fn validate_input_version(
consensus_constants: &ConsensusConstants,
input: &TransactionInput,
) -> Result<(), ValidationError> {
// validate input version
for input in body.inputs() {
if !consensus_constants.input_version_range().contains(&input.version) {
let msg = format!(
"Transaction input contains a version not allowed by consensus ({:?})",
input.version
);
return Err(ValidationError::ConsensusError(msg));
}
if !consensus_constants.input_version_range().contains(&input.version) {
let msg = format!(
"Transaction input contains a version not allowed by consensus ({:?})",
input.version
);
return Err(ValidationError::ConsensusError(msg));
}

// validate output version and output features version
for output in body.outputs() {
let valid_output_version = consensus_constants
.output_version_range()
.outputs
.contains(&output.version);
Ok(())
}

let valid_features_version = consensus_constants
pub fn validate_output_version(
consensus_constants: &ConsensusConstants,
output: &TransactionOutput,
) -> Result<(), ValidationError> {
let valid_output_version = consensus_constants
.output_version_range()
.outputs
.contains(&output.version);

if !valid_output_version {
let msg = format!(
"Transaction output version is not allowed by consensus ({:?})",
output.version
);
return Err(ValidationError::ConsensusError(msg));
}

let valid_features_version = consensus_constants
.output_version_range()
.features
.contains(&output.features.version);

if !valid_features_version {
let msg = format!(
"Transaction output features version is not allowed by consensus ({:?})",
output.features.version
);
return Err(ValidationError::ConsensusError(msg));
}

for opcode in output.script.as_slice() {
if !consensus_constants
.output_version_range()
.features
.contains(&output.features.version);
if !valid_output_version {
.opcode
.contains(&opcode.get_version())
{
let msg = format!(
"Transaction output version is not allowed by consensus ({:?})",
output.version
"Transaction output script opcode is not allowed by consensus ({})",
opcode
);
return Err(ValidationError::ConsensusError(msg));
}
}

if !valid_features_version {
let msg = format!(
"Transaction output features version is not allowed by consensus ({:?})",
output.features.version
);
return Err(ValidationError::ConsensusError(msg));
}
for opcode in output.script.as_slice() {
if !consensus_constants
.output_version_range()
.opcode
.contains(&opcode.get_version())
{
let msg = format!(
"Transaction output script opcode is not allowed by consensus ({})",
opcode
);
return Err(ValidationError::ConsensusError(msg));
}
}
Ok(())
}

check_permitted_output_types(consensus_constants, output)?;
pub fn validate_kernel_version(
consensus_constants: &ConsensusConstants,
kernel: &TransactionKernel,
) -> Result<(), ValidationError> {
if !consensus_constants.kernel_version_range().contains(&kernel.version) {
let msg = format!(
"Transaction kernel version is not allowed by consensus ({:?})",
kernel.version
);
return Err(ValidationError::ConsensusError(msg));
}
Ok(())
}

pub fn validate_versions(
body: &AggregateBody,
consensus_constants: &ConsensusConstants,
) -> Result<(), ValidationError> {
// validate input version
for input in body.inputs() {
validate_input_version(consensus_constants, input)?;
}

// validate output version and output features version
for output in body.outputs() {
validate_output_version(consensus_constants, output)?;
}

// validate kernel version
for kernel in body.kernels() {
if !consensus_constants.kernel_version_range().contains(&kernel.version) {
let msg = format!(
"Transaction kernel version is not allowed by consensus ({:?})",
kernel.version
);
return Err(ValidationError::ConsensusError(msg));
}
validate_kernel_version(consensus_constants, kernel)?;
}

Ok(())
Expand Down
14 changes: 12 additions & 2 deletions base_layer/core/src/validation/transaction_validators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ use crate::{
chain_storage::{BlockchainBackend, BlockchainDatabase},
transactions::{transaction_components::Transaction, CryptoFactories},
validation::{
helpers::{check_inputs_are_utxos, check_outputs, check_total_burned, validate_versions},
helpers::{
check_inputs_are_utxos,
check_outputs,
check_permitted_output_types,
check_total_burned,
validate_versions,
},
MempoolTransactionValidation,
ValidationError,
},
Expand Down Expand Up @@ -129,7 +135,11 @@ impl<B: BlockchainBackend> MempoolTransactionValidation for TxConsensusValidator

self.validate_excess_sig_not_in_db(tx)?;

validate_versions(tx.body(), consensus_constants)
validate_versions(tx.body(), consensus_constants)?;
for output in tx.body.outputs() {
check_permitted_output_types(consensus_constants, output)?;
}
Ok(())
}
}

Expand Down