Skip to content

Commit

Permalink
Add opcode versioning and check for it
Browse files Browse the repository at this point in the history
Move tx validation version check
Remove pub from opcode constant
  • Loading branch information
SWvheerden committed Oct 20, 2022
1 parent 8289493 commit b5ec9aa
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 101 deletions.
33 changes: 31 additions & 2 deletions base_layer/core/src/consensus/consensus_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use std::{

use chrono::{DateTime, Duration, Utc};
use tari_common::configuration::Network;
use tari_script::script;
use tari_script::{script, OpcodeVersion};
use tari_utilities::epoch_time::EpochTime;

use crate::{
Expand Down Expand Up @@ -101,6 +101,7 @@ pub struct ConsensusConstants {
pub struct OutputVersionRange {
pub outputs: RangeInclusive<TransactionOutputVersion>,
pub features: RangeInclusive<OutputFeaturesVersion>,
pub opcode: RangeInclusive<OpcodeVersion>,
}

/// All V0 for Inputs, Outputs + Features, Kernels
Expand All @@ -114,6 +115,7 @@ fn version_zero() -> (
let output_version_range = OutputVersionRange {
outputs: TransactionOutputVersion::V0..=TransactionOutputVersion::V0,
features: OutputFeaturesVersion::V0..=OutputFeaturesVersion::V0,
opcode: OpcodeVersion::V0..=OpcodeVersion::V0,
};

(input_version_range, output_version_range, kernel_version_range)
Expand Down Expand Up @@ -505,6 +507,11 @@ impl ConsensusConstants {
target_time: 200,
});
let (input_version_range, output_version_range, kernel_version_range) = version_zero();
let output_version_2_range = OutputVersionRange {
outputs: TransactionOutputVersion::V0..=TransactionOutputVersion::V0,
features: OutputFeaturesVersion::V0..=OutputFeaturesVersion::V0,
opcode: OpcodeVersion::V0..=OpcodeVersion::V1,
};
vec![
ConsensusConstants {
effective_from_height: 0,
Expand Down Expand Up @@ -541,12 +548,34 @@ impl ConsensusConstants {
emission_decay: &ESMERALDA_DECAY_PARAMS,
emission_tail: 800 * T,
max_randomx_seed_height: 3000,
proof_of_work: algos.clone(),
faucet_value: (10 * 4000) * T,
transaction_weight: TransactionWeight::v1(),
max_script_byte_size: 2048,
input_version_range: input_version_range.clone(),
output_version_range,
kernel_version_range: kernel_version_range.clone(),
permitted_output_types: Self::current_permitted_output_types(),
},
ConsensusConstants {
effective_from_height: 25000,
coinbase_lock_height: 6,
blockchain_version: 1,
valid_blockchain_version_range: 0..=1,
future_time_limit: 540,
difficulty_block_window: 90,
max_block_transaction_weight: 127_795,
median_timestamp_count: 11,
emission_initial: 18_462_816_327 * uT,
emission_decay: &ESMERALDA_DECAY_PARAMS,
emission_tail: 800 * T,
max_randomx_seed_height: 3000,
proof_of_work: algos,
faucet_value: (10 * 4000) * T,
transaction_weight: TransactionWeight::v1(),
max_script_byte_size: 2048,
input_version_range,
output_version_range,
output_version_range: output_version_2_range,
kernel_version_range,
permitted_output_types: Self::current_permitted_output_types(),
},
Expand Down
3 changes: 3 additions & 0 deletions base_layer/core/src/validation/block_validators/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use crate::{
check_permitted_output_types,
check_sorting_and_duplicates,
check_total_burned,
validate_versions,
},
OrphanValidation,
ValidationError,
Expand Down Expand Up @@ -88,6 +89,8 @@ impl OrphanValidation for OrphanBlockValidator {
trace!(target: LOG_TARGET, "Validating {}", block_id);

let constants = self.rules.consensus_constants(height);
validate_versions(&block.body, constants)?;
trace!(target: LOG_TARGET, "SV - Block body versions are ok for {} ", &block_id);
check_block_weight(block, constants)?;
trace!(target: LOG_TARGET, "SV - Block weight is ok for {} ", &block_id);

Expand Down
72 changes: 72 additions & 0 deletions base_layer/core/src/validation/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,78 @@ pub fn check_permitted_output_types(
Ok(())
}

pub fn validate_versions(
body: &AggregateBody,
consensus_constants: &ConsensusConstants,
) -> 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));
}
}

// 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);

let valid_features_version = consensus_constants
.output_version_range()
.features
.contains(&output.features.version);
if !valid_output_version {
let msg = format!(
"Transaction output version is not allowed by consensus ({:?})",
output.version
);
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));
}
}

check_permitted_output_types(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));
}
}

Ok(())
}

#[cfg(test)]
mod test {
use tari_test_utils::unpack_enum;
Expand Down
71 changes: 7 additions & 64 deletions base_layer/core/src/validation/transaction_validators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ use tari_utilities::hex::Hex;

use crate::{
chain_storage::{BlockchainBackend, BlockchainDatabase},
consensus::ConsensusConstants,
transactions::{transaction_components::Transaction, CryptoFactories},
validation::{
helpers::{check_inputs_are_utxos, check_outputs, check_permitted_output_types, check_total_burned},
helpers::{
check_inputs_are_utxos,
check_outputs,
check_total_burned,
validate_versions,
},
MempoolTransactionValidation,
ValidationError,
},
Expand Down Expand Up @@ -98,67 +102,6 @@ impl<B: BlockchainBackend> TxConsensusValidator<B> {
Self { db }
}

fn validate_versions(
&self,
tx: &Transaction,
consensus_constants: &ConsensusConstants,
) -> Result<(), ValidationError> {
// validate input version
for input in tx.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));
}
}

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

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

if !valid_output_version {
let msg = format!(
"Transaction output version is not allowed by consensus ({:?})",
output.version
);
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));
}

check_permitted_output_types(consensus_constants, output)?;
}

// validate kernel version
for kernel in tx.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));
}
}

Ok(())
}

fn validate_excess_sig_not_in_db(&self, tx: &Transaction) -> Result<(), ValidationError> {
for kernel in tx.body.kernels() {
if let Some((db_kernel, header_hash)) = self.db.fetch_kernel_by_excess_sig(kernel.excess_sig.to_owned())? {
Expand Down Expand Up @@ -191,7 +134,7 @@ impl<B: BlockchainBackend> MempoolTransactionValidation for TxConsensusValidator

self.validate_excess_sig_not_in_db(tx)?;

self.validate_versions(tx, consensus_constants)
validate_versions(tx.body(), consensus_constants)
}
}

Expand Down
2 changes: 1 addition & 1 deletion infrastructure/tari_script/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ mod serde;
mod stack;

pub use error::ScriptError;
pub use op_codes::{slice_to_boxed_hash, slice_to_hash, HashValue, Message, Opcode, ScalarValue};
pub use op_codes::{slice_to_boxed_hash, slice_to_hash, HashValue, Message, Opcode, OpcodeVersion, ScalarValue};
pub use script::TariScript;
pub use script_commitment::{ScriptCommitment, ScriptCommitmentError, ScriptCommitmentFactory};
pub use script_context::ScriptContext;
Expand Down
82 changes: 48 additions & 34 deletions infrastructure/tari_script/src/op_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,52 +79,52 @@ pub fn slice_to_vec_pubkeys(slice: &[u8], num: usize) -> Result<Vec<RistrettoPub
}

// Opcode constants: Block Height Checks
pub const OP_CHECK_HEIGHT_VERIFY: u8 = 0x66;
pub const OP_CHECK_HEIGHT: u8 = 0x67;
pub const OP_COMPARE_HEIGHT_VERIFY: u8 = 0x68;
pub const OP_COMPARE_HEIGHT: u8 = 0x69;
const OP_CHECK_HEIGHT_VERIFY: u8 = 0x66;
const OP_CHECK_HEIGHT: u8 = 0x67;
const OP_COMPARE_HEIGHT_VERIFY: u8 = 0x68;
const OP_COMPARE_HEIGHT: u8 = 0x69;

// Opcode constants: Stack Manipulation
pub const OP_DROP: u8 = 0x70;
pub const OP_DUP: u8 = 0x71;
pub const OP_REV_ROT: u8 = 0x72;
pub const OP_PUSH_HASH: u8 = 0x7a;
pub const OP_PUSH_ZERO: u8 = 0x7b;
pub const OP_NOP: u8 = 0x73;
pub const OP_PUSH_ONE: u8 = 0x7c;
pub const OP_PUSH_INT: u8 = 0x7d;
pub const OP_PUSH_PUBKEY: u8 = 0x7e;
const OP_DROP: u8 = 0x70;
const OP_DUP: u8 = 0x71;
const OP_REV_ROT: u8 = 0x72;
const OP_PUSH_HASH: u8 = 0x7a;
const OP_PUSH_ZERO: u8 = 0x7b;
const OP_NOP: u8 = 0x73;
const OP_PUSH_ONE: u8 = 0x7c;
const OP_PUSH_INT: u8 = 0x7d;
const OP_PUSH_PUBKEY: u8 = 0x7e;

// Opcode constants: Math Operations
pub const OP_EQUAL: u8 = 0x80;
pub const OP_EQUAL_VERIFY: u8 = 0x81;
pub const OP_ADD: u8 = 0x93;
pub const OP_SUB: u8 = 0x94;
pub const OP_GE_ZERO: u8 = 0x82;
pub const OP_GT_ZERO: u8 = 0x83;
pub const OP_LE_ZERO: u8 = 0x84;
pub const OP_LT_ZERO: u8 = 0x85;
const OP_EQUAL: u8 = 0x80;
const OP_EQUAL_VERIFY: u8 = 0x81;
const OP_ADD: u8 = 0x93;
const OP_SUB: u8 = 0x94;
const OP_GE_ZERO: u8 = 0x82;
const OP_GT_ZERO: u8 = 0x83;
const OP_LE_ZERO: u8 = 0x84;
const OP_LT_ZERO: u8 = 0x85;

// Opcode constants: Boolean Logic
pub const OP_OR_VERIFY: u8 = 0x64;
pub const OP_OR: u8 = 0x65;

// Opcode constants: Cryptographic Operations
pub const OP_CHECK_SIG: u8 = 0xac;
pub const OP_CHECK_SIG_VERIFY: u8 = 0xad;
pub const OP_CHECK_MULTI_SIG: u8 = 0xae;
pub const OP_CHECK_MULTI_SIG_VERIFY: u8 = 0xaf;
pub const OP_HASH_BLAKE256: u8 = 0xb0;
pub const OP_HASH_SHA256: u8 = 0xb1;
pub const OP_HASH_SHA3: u8 = 0xb2;
pub const OP_TO_RISTRETTO_POINT: u8 = 0xb3;
pub const OP_CHECK_MULTI_SIG_VERIFY_AGGREGATE_PUB_KEY: u8 = 0xb4;
const OP_CHECK_SIG: u8 = 0xac;
const OP_CHECK_SIG_VERIFY: u8 = 0xad;
const OP_CHECK_MULTI_SIG: u8 = 0xae;
const OP_CHECK_MULTI_SIG_VERIFY: u8 = 0xaf;
const OP_HASH_BLAKE256: u8 = 0xb0;
const OP_HASH_SHA256: u8 = 0xb1;
const OP_HASH_SHA3: u8 = 0xb2;
const OP_TO_RISTRETTO_POINT: u8 = 0xb3;
const OP_CHECK_MULTI_SIG_VERIFY_AGGREGATE_PUB_KEY: u8 = 0xb4;

// Opcode constants: Miscellaneous
pub const OP_RETURN: u8 = 0x60;
pub const OP_IF_THEN: u8 = 0x61;
pub const OP_ELSE: u8 = 0x62;
pub const OP_END_IF: u8 = 0x63;
const OP_RETURN: u8 = 0x60;
const OP_IF_THEN: u8 = 0x61;
const OP_ELSE: u8 = 0x62;
const OP_END_IF: u8 = 0x63;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Opcode {
Expand Down Expand Up @@ -258,6 +258,13 @@ pub enum Opcode {
}

impl Opcode {
pub fn get_version(&self) -> OpcodeVersion {
match self {
Opcode::CheckMultiSigVerify(..) => OpcodeVersion::V1,
_ => OpcodeVersion::V0,
}
}

pub fn parse(bytes: &[u8]) -> Result<Vec<Opcode>, ScriptError> {
let mut script = Vec::new();
let mut bytes_copy = bytes;
Expand Down Expand Up @@ -565,6 +572,13 @@ impl fmt::Display for Opcode {
}
}

#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum OpcodeVersion {
V0 = 0,
V1 = 1,
}

#[cfg(test)]
mod test {
use crate::{op_codes::*, Opcode, ScriptError};
Expand Down

0 comments on commit b5ec9aa

Please sign in to comment.