From b5ec9aa0cce1f3b57f5d29c1ac114bfcd16c4c14 Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Thu, 20 Oct 2022 15:06:39 +0200 Subject: [PATCH] Add opcode versioning and check for it Move tx validation version check Remove pub from opcode constant --- .../core/src/consensus/consensus_constants.rs | 33 +++++++- .../src/validation/block_validators/orphan.rs | 3 + base_layer/core/src/validation/helpers.rs | 72 ++++++++++++++++ .../src/validation/transaction_validators.rs | 71 ++-------------- infrastructure/tari_script/src/lib.rs | 2 +- infrastructure/tari_script/src/op_codes.rs | 82 +++++++++++-------- 6 files changed, 162 insertions(+), 101 deletions(-) diff --git a/base_layer/core/src/consensus/consensus_constants.rs b/base_layer/core/src/consensus/consensus_constants.rs index c2e420ea37..471dfb44f8 100644 --- a/base_layer/core/src/consensus/consensus_constants.rs +++ b/base_layer/core/src/consensus/consensus_constants.rs @@ -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::{ @@ -101,6 +101,7 @@ pub struct ConsensusConstants { pub struct OutputVersionRange { pub outputs: RangeInclusive, pub features: RangeInclusive, + pub opcode: RangeInclusive, } /// All V0 for Inputs, Outputs + Features, Kernels @@ -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) @@ -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, @@ -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(), }, diff --git a/base_layer/core/src/validation/block_validators/orphan.rs b/base_layer/core/src/validation/block_validators/orphan.rs index fb57ec4151..0710df52c2 100644 --- a/base_layer/core/src/validation/block_validators/orphan.rs +++ b/base_layer/core/src/validation/block_validators/orphan.rs @@ -37,6 +37,7 @@ use crate::{ check_permitted_output_types, check_sorting_and_duplicates, check_total_burned, + validate_versions, }, OrphanValidation, ValidationError, @@ -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); diff --git a/base_layer/core/src/validation/helpers.rs b/base_layer/core/src/validation/helpers.rs index 954d231226..f47f935833 100644 --- a/base_layer/core/src/validation/helpers.rs +++ b/base_layer/core/src/validation/helpers.rs @@ -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; diff --git a/base_layer/core/src/validation/transaction_validators.rs b/base_layer/core/src/validation/transaction_validators.rs index 25e638b8ab..158ed1caab 100644 --- a/base_layer/core/src/validation/transaction_validators.rs +++ b/base_layer/core/src/validation/transaction_validators.rs @@ -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, }, @@ -98,67 +102,6 @@ impl TxConsensusValidator { 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())? { @@ -191,7 +134,7 @@ impl MempoolTransactionValidation for TxConsensusValidator self.validate_excess_sig_not_in_db(tx)?; - self.validate_versions(tx, consensus_constants) + validate_versions(tx.body(), consensus_constants) } } diff --git a/infrastructure/tari_script/src/lib.rs b/infrastructure/tari_script/src/lib.rs index 81ef3d5e7f..d769ab5bd1 100644 --- a/infrastructure/tari_script/src/lib.rs +++ b/infrastructure/tari_script/src/lib.rs @@ -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; diff --git a/infrastructure/tari_script/src/op_codes.rs b/infrastructure/tari_script/src/op_codes.rs index 2eab0a48bd..d247d32c24 100644 --- a/infrastructure/tari_script/src/op_codes.rs +++ b/infrastructure/tari_script/src/op_codes.rs @@ -79,52 +79,52 @@ pub fn slice_to_vec_pubkeys(slice: &[u8], num: usize) -> Result OpcodeVersion { + match self { + Opcode::CheckMultiSigVerify(..) => OpcodeVersion::V1, + _ => OpcodeVersion::V0, + } + } + pub fn parse(bytes: &[u8]) -> Result, ScriptError> { let mut script = Vec::new(); let mut bytes_copy = bytes; @@ -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};