From bd493d6d84e0ac2419f86cb065e3ee65d2318d96 Mon Sep 17 00:00:00 2001 From: Stanimal Date: Mon, 25 Apr 2022 17:33:14 +0200 Subject: [PATCH] test(covenant): improve test coverage --- Cargo.lock | 32 +-- base_layer/core/src/covenants/arguments.rs | 25 +- base_layer/core/src/covenants/byte_codes.rs | 71 +++++- base_layer/core/src/covenants/decoder.rs | 51 +++- base_layer/core/src/covenants/encoder.rs | 60 +++++ base_layer/core/src/covenants/error.rs | 2 - base_layer/core/src/covenants/fields.rs | 236 +++++++++++++++--- .../core/src/covenants/filters/field_eq.rs | 41 +-- .../src/covenants/filters/fields_hashed_eq.rs | 22 -- .../core/src/covenants/filters/filter.rs | 14 ++ .../core/src/covenants/filters/identity.rs | 20 ++ base_layer/core/src/covenants/macros.rs | 12 +- base_layer/core/src/covenants/token.rs | 2 +- .../src/validation/block_validators/test.rs | 2 +- 14 files changed, 468 insertions(+), 122 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7383642686..2cc34690f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7140,22 +7140,6 @@ dependencies = [ "warp", ] -[[package]] -name = "tari_mining_helper_ffi" -version = "0.30.2" -dependencies = [ - "hex", - "libc", - "serde", - "serde_json", - "tari_common", - "tari_comms", - "tari_core", - "tari_crypto", - "tari_utilities", - "thiserror", -] - [[package]] name = "tari_miner" version = "0.31.1" @@ -7191,6 +7175,22 @@ dependencies = [ "tonic", ] +[[package]] +name = "tari_mining_helper_ffi" +version = "0.30.2" +dependencies = [ + "hex", + "libc", + "serde", + "serde_json", + "tari_common", + "tari_comms", + "tari_core", + "tari_crypto", + "tari_utilities", + "thiserror", +] + [[package]] name = "tari_mmr" version = "0.31.1" diff --git a/base_layer/core/src/covenants/arguments.rs b/base_layer/core/src/covenants/arguments.rs index 760f8c07a0..a071b4fbbf 100644 --- a/base_layer/core/src/covenants/arguments.rs +++ b/base_layer/core/src/covenants/arguments.rs @@ -35,7 +35,7 @@ use crate::{ covenants::{ byte_codes, covenant::Covenant, - decoder::{CovenantDecodeError, CovenentReadExt}, + decoder::{CovenantDecodeError, CovenantReadExt}, encoder::CovenentWriteExt, error::CovenantError, fields::{OutputField, OutputFields}, @@ -238,7 +238,12 @@ impl Display for CovenantArg { #[cfg(test)] mod test { + use tari_common_types::types::Commitment; + use tari_script::script; + use tari_utilities::hex::from_hex; + use super::*; + use crate::{covenant, covenants::byte_codes::*}; mod require_x_impl { use super::*; @@ -260,18 +265,18 @@ mod test { } } - mod write_to { - use tari_common_types::types::Commitment; - use tari_script::script; - use tari_utilities::hex::from_hex; - + mod write_to_and_read_from { use super::*; - use crate::{covenant, covenants::byte_codes::*}; - fn test_case(arg: CovenantArg, expected: &[u8]) { + fn test_case(argument: CovenantArg, mut data: &[u8]) { let mut buf = Vec::new(); - arg.write_to(&mut buf).unwrap(); - assert_eq!(buf, expected); + argument.write_to(&mut buf).unwrap(); + assert_eq!(buf, data); + + let reader = &mut data; + let code = reader.read_next_byte_code().unwrap().unwrap(); + let arg = CovenantArg::read_from(&mut data, code).unwrap(); + assert_eq!(arg, argument); } #[test] diff --git a/base_layer/core/src/covenants/byte_codes.rs b/base_layer/core/src/covenants/byte_codes.rs index d8e1ee910a..176fd53943 100644 --- a/base_layer/core/src/covenants/byte_codes.rs +++ b/base_layer/core/src/covenants/byte_codes.rs @@ -22,8 +22,21 @@ //---------------------------------- ARG byte codes --------------------------------------------// pub(super) fn is_valid_arg_code(code: u8) -> bool { - (0x01..=0x09).contains(&code) + ALL_ARGS.contains(&code) } + +pub(super) const ALL_ARGS: [u8; 9] = [ + ARG_HASH, + ARG_PUBLIC_KEY, + ARG_COMMITMENT, + ARG_TARI_SCRIPT, + ARG_COVENANT, + ARG_UINT, + ARG_OUTPUT_FIELD, + ARG_OUTPUT_FIELDS, + ARG_BYTES, +]; + pub const ARG_HASH: u8 = 0x01; pub const ARG_PUBLIC_KEY: u8 = 0x02; pub const ARG_COMMITMENT: u8 = 0x03; @@ -37,9 +50,22 @@ pub const ARG_BYTES: u8 = 0x09; //---------------------------------- FILTER byte codes --------------------------------------------// pub(super) fn is_valid_filter_code(code: u8) -> bool { - (0x20..=0x24).contains(&code) || (0x30..=0x34).contains(&code) + ALL_FILTERS.contains(&code) } +pub(super) const ALL_FILTERS: [u8; 10] = [ + FILTER_IDENTITY, + FILTER_AND, + FILTER_OR, + FILTER_XOR, + FILTER_NOT, + FILTER_OUTPUT_HASH_EQ, + FILTER_FIELDS_PRESERVED, + FILTER_FIELDS_HASHED_EQ, + FILTER_FIELD_EQ, + FILTER_ABSOLUTE_HEIGHT, +]; + pub const FILTER_IDENTITY: u8 = 0x20; pub const FILTER_AND: u8 = 0x21; pub const FILTER_OR: u8 = 0x22; @@ -63,3 +89,44 @@ pub const FIELD_FEATURES_MATURITY: u8 = 0x06; pub const FIELD_FEATURES_UNIQUE_ID: u8 = 0x07; pub const FIELD_FEATURES_PARENT_PUBLIC_KEY: u8 = 0x08; pub const FIELD_FEATURES_METADATA: u8 = 0x09; + +#[cfg(test)] +mod tests { + use super::*; + + mod is_valid_filter_code { + use super::*; + + #[test] + fn it_returns_true_for_all_filter_codes() { + ALL_FILTERS.iter().for_each(|code| { + assert!(is_valid_filter_code(*code)); + }); + } + + #[test] + fn it_returns_false_for_all_arg_codes() { + ALL_ARGS.iter().for_each(|code| { + assert!(!is_valid_filter_code(*code)); + }); + } + } + + mod is_valid_arg_code { + use super::*; + + #[test] + fn it_returns_false_for_all_filter_codes() { + ALL_FILTERS.iter().for_each(|code| { + assert!(!is_valid_arg_code(*code)); + }); + } + + #[test] + fn it_returns_true_for_all_arg_codes() { + ALL_ARGS.iter().for_each(|code| { + assert!(is_valid_arg_code(*code)); + }); + } + } +} diff --git a/base_layer/core/src/covenants/decoder.rs b/base_layer/core/src/covenants/decoder.rs index 5d72dd25f1..f7b0d75452 100644 --- a/base_layer/core/src/covenants/decoder.rs +++ b/base_layer/core/src/covenants/decoder.rs @@ -81,12 +81,12 @@ pub enum CovenantDecodeError { Io(#[from] io::Error), } -pub(super) trait CovenentReadExt: io::Read { +pub(super) trait CovenantReadExt: io::Read { fn read_next_byte_code(&mut self) -> Result, io::Error>; fn read_variable_length_bytes(&mut self, size: usize) -> Result, io::Error>; } -impl CovenentReadExt for R { +impl CovenantReadExt for R { fn read_next_byte_code(&mut self) -> Result, io::Error> { let mut buf = [0u8; 1]; loop { @@ -127,13 +127,41 @@ mod test { use super::*; use crate::{ covenant, - covenants::{arguments::CovenantArg, fields::OutputField, filters::CovenantFilter}, + covenants::{ + arguments::CovenantArg, + byte_codes::ARG_OUTPUT_FIELD, + fields::OutputField, + filters::CovenantFilter, + }, }; #[test] fn it_immediately_ends_iterator_given_empty_bytes() { let buf = &[] as &[u8; 0]; assert!(CovenantTokenDecoder::new(&mut &buf[..]).next().is_none()); + assert!(CovenantTokenDecoder::new(&mut &buf[..]).next().is_none()); + } + + #[test] + fn it_ends_after_an_error() { + let buf = &[0xffu8]; + let mut reader = &buf[..]; + let mut decoder = CovenantTokenDecoder::new(&mut reader); + assert!(matches!(decoder.next(), Some(Err(_)))); + assert!(decoder.next().is_none()); + } + + #[test] + fn it_returns_an_error_if_arg_expected() { + let buf = &[ARG_OUTPUT_FIELD]; + let mut reader = &buf[..]; + let mut decoder = CovenantTokenDecoder::new(&mut reader); + + assert!(matches!( + decoder.next(), + Some(Err(CovenantDecodeError::UnexpectedEof { .. })) + )); + assert!(decoder.next().is_none()); } #[test] @@ -171,4 +199,21 @@ mod test { assert!(decoder.next().is_none()); } + + mod covenant_read_ext { + use super::*; + + #[test] + fn it_reads_bytes_with_length_prefix() { + let data = vec![0x03u8, 0x01, 0x02, 0x03]; + let bytes = CovenantReadExt::read_variable_length_bytes(&mut data.as_slice(), 3).unwrap(); + assert_eq!(bytes, [1u8, 2, 3]); + } + + #[test] + fn it_errors_if_len_byte_exceeds_maximum() { + let data = vec![0x02, 0x01]; + CovenantReadExt::read_variable_length_bytes(&mut data.as_slice(), 1).unwrap_err(); + } + } } diff --git a/base_layer/core/src/covenants/encoder.rs b/base_layer/core/src/covenants/encoder.rs index f18c2e372c..48bcd93b1c 100644 --- a/base_layer/core/src/covenants/encoder.rs +++ b/base_layer/core/src/covenants/encoder.rs @@ -52,3 +52,63 @@ impl CovenentWriteExt for W { Ok(1) } } + +#[cfg(test)] +mod tests { + + use super::*; + use crate::{ + covenant, + covenants::{ + byte_codes::{ARG_HASH, ARG_OUTPUT_FIELD, FILTER_AND, FILTER_FIELD_EQ, FILTER_IDENTITY, FILTER_OR}, + OutputField, + }, + }; + + #[test] + fn it_encodes_empty_tokens() { + let encoder = CovenantTokenEncoder::new(&[]); + let mut buf = Vec::::new(); + let written = encoder.write_to(&mut buf).unwrap(); + assert_eq!(buf, [] as [u8; 0]); + assert_eq!(written, 0); + } + + #[test] + fn it_encodes_tokens_correctly() { + let covenant = covenant!(and(identity(), or(identity()))); + let encoder = CovenantTokenEncoder::new(covenant.tokens()); + let mut buf = Vec::::new(); + let written = encoder.write_to(&mut buf).unwrap(); + assert_eq!(buf, [FILTER_AND, FILTER_IDENTITY, FILTER_OR, FILTER_IDENTITY]); + assert_eq!(written, 4); + } + + #[test] + fn it_encodes_args_correctly() { + let dummy = [0u8; 32]; + let covenant = covenant!(field_eq(@field::features, @hash(dummy))); + let encoder = CovenantTokenEncoder::new(covenant.tokens()); + let mut buf = Vec::::new(); + let written = encoder.write_to(&mut buf).unwrap(); + assert_eq!(buf[..4], [ + FILTER_FIELD_EQ, + ARG_OUTPUT_FIELD, + OutputField::Features.as_byte(), + ARG_HASH + ]); + assert_eq!(buf[4..], [0u8; 32]); + assert_eq!(written, 36); + } + + mod covenant_write_ext { + use super::*; + + #[test] + fn it_writes_a_single_byte() { + let mut buf = Vec::new(); + buf.write_u8_fixed(123u8).unwrap(); + assert_eq!(buf, vec![123u8]); + } + } +} diff --git a/base_layer/core/src/covenants/error.rs b/base_layer/core/src/covenants/error.rs index 201d71fb3d..4eacf2775d 100644 --- a/base_layer/core/src/covenants/error.rs +++ b/base_layer/core/src/covenants/error.rs @@ -40,6 +40,4 @@ pub enum CovenantError { RemainingTokens, #[error("Invalid argument for filter {filter}: {details}")] InvalidArgument { filter: &'static str, details: String }, - #[error("Unsupported argument {arg}: {details}")] - UnsupportedArgument { arg: &'static str, details: String }, } diff --git a/base_layer/core/src/covenants/fields.rs b/base_layer/core/src/covenants/fields.rs index 027b957177..a4cc3f9341 100644 --- a/base_layer/core/src/covenants/fields.rs +++ b/base_layer/core/src/covenants/fields.rs @@ -29,13 +29,13 @@ use std::{ use digest::Digest; use integer_encoding::VarIntWriter; -use tari_common_types::types::Challenge; +use tari_common_types::types::HashDigest; use crate::{ consensus::ToConsensusBytes, covenants::{ byte_codes, - decoder::{CovenantDecodeError, CovenentReadExt}, + decoder::{CovenantDecodeError, CovenantReadExt}, encoder::CovenentWriteExt, error::CovenantError, }, @@ -162,17 +162,17 @@ impl OutputField { } pub fn is_eq(self, output: &TransactionOutput, val: &T) -> Result { - use OutputField::{Features, FeaturesParentPublicKey, FeaturesUniqueId}; + use OutputField::{FeaturesParentPublicKey, FeaturesUniqueId}; match self { // Handle edge cases FeaturesParentPublicKey | FeaturesUniqueId => match self.get_field_value_ref::>(output) { Some(Some(field_val)) => Ok(field_val == val), - _ => Ok(false), + Some(None) => Ok(false), + None => Err(CovenantError::InvalidArgument { + filter: "is_eq", + details: format!("Invalid type for field {}", self), + }), }, - Features => Err(CovenantError::UnsupportedArgument { - arg: "features", - details: "OutputFeatures is not supported for operation is_eq".to_string(), - }), _ => match self.get_field_value_ref::(output) { Some(field_val) => Ok(field_val == val), None => Err(CovenantError::InvalidArgument { @@ -304,10 +304,10 @@ impl OutputFields { self.fields.is_empty() } - pub fn construct_challenge_from(&self, output: &TransactionOutput) -> Challenge { - let mut challenge = Challenge::new(); + pub fn construct_challenge_from(&self, output: &TransactionOutput) -> HashDigest { + let mut challenge = HashDigest::new(); for field in &self.fields { - challenge = challenge.chain(field.get_field_value_bytes(output)); + challenge.update(field.get_field_value_bytes(output)); } challenge } @@ -332,26 +332,206 @@ impl FromIterator for OutputFields { #[cfg(test)] mod test { + use tari_common_types::types::PublicKey; + use tari_script::script; + use super::*; use crate::{ - covenants::test::create_outputs, - transactions::{test_helpers::UtxoTestParams, transaction_components::OutputFeatures}, + covenant, + covenants::test::{create_input, create_outputs}, + transactions::{ + test_helpers::UtxoTestParams, + transaction_components::{OutputFeatures, OutputFlags}, + }, }; - #[test] - fn get_field_value_ref() { - let mut features = OutputFeatures { - maturity: 42, - ..Default::default() - }; - let output = create_outputs(1, UtxoTestParams { - features: features.clone(), - ..Default::default() - }) - .pop() - .unwrap(); - features.set_recovery_byte(output.features.recovery_byte); - let r = OutputField::Features.get_field_value_ref::(&output); - assert_eq!(*r.unwrap(), features); + mod output_field { + use super::*; + + mod is_eq { + use tari_common_types::types::Commitment; + + use super::*; + + #[test] + fn it_returns_true_if_eq() { + let output = create_outputs(1, UtxoTestParams { + features: OutputFeatures { + parent_public_key: Some(Default::default()), + unique_id: Some(b"1234".to_vec()), + ..Default::default() + }, + script: script![Drop Nop], + ..Default::default() + }) + .remove(0); + + assert!(OutputField::Commitment.is_eq(&output, &output.commitment).unwrap()); + assert!(OutputField::Features.is_eq(&output, &output.features).unwrap()); + assert!(OutputField::Script.is_eq(&output, &output.script).unwrap()); + assert!(OutputField::Covenant.is_eq(&output, &output.covenant).unwrap()); + assert!(OutputField::FeaturesMaturity + .is_eq(&output, &output.features.maturity) + .unwrap()); + assert!(OutputField::FeaturesFlags + .is_eq(&output, &output.features.flags) + .unwrap()); + assert!(OutputField::FeaturesParentPublicKey + .is_eq(&output, output.features.parent_public_key.as_ref().unwrap()) + .unwrap()); + assert!(OutputField::FeaturesMetadata + .is_eq(&output, &output.features.metadata) + .unwrap()); + assert!(OutputField::FeaturesUniqueId + .is_eq(&output, output.features.unique_id.as_ref().unwrap()) + .unwrap()); + assert!(OutputField::SenderOffsetPublicKey + .is_eq(&output, &output.sender_offset_public_key) + .unwrap()); + } + + #[test] + fn it_returns_false_if_not_eq() { + let output = create_outputs(1, UtxoTestParams { + features: OutputFeatures { + parent_public_key: Some(Default::default()), + unique_id: Some(b"1234".to_vec()), + ..Default::default() + }, + script: script![Drop Nop], + ..Default::default() + }) + .remove(0); + + assert!(!OutputField::Commitment.is_eq(&output, &Commitment::default()).unwrap()); + assert!(!OutputField::Features + .is_eq(&output, &OutputFeatures::default()) + .unwrap()); + assert!(!OutputField::Script.is_eq(&output, &script![Nop Drop]).unwrap()); + assert!(!OutputField::Covenant + .is_eq(&output, &covenant!(and(identity(), identity()))) + .unwrap()); + assert!(!OutputField::FeaturesMaturity.is_eq(&output, &123).unwrap()); + assert!(!OutputField::FeaturesFlags + .is_eq(&output, &OutputFlags::COINBASE_OUTPUT) + .unwrap()); + assert!(!OutputField::FeaturesParentPublicKey + .is_eq(&output, &PublicKey::default()) + .unwrap()); + assert!(!OutputField::FeaturesMetadata.is_eq(&output, &[123u8]).unwrap()); + assert!(!OutputField::FeaturesUniqueId.is_eq(&output, &[123u8]).unwrap()); + assert!(!OutputField::SenderOffsetPublicKey + .is_eq(&output, &PublicKey::default()) + .unwrap()); + } + } + + mod is_eq_input { + use super::*; + + #[test] + fn it_returns_true_if_eq_input() { + let output = create_outputs(1, UtxoTestParams { + features: OutputFeatures { + maturity: 42, + ..Default::default() + }, + script: script![Drop Nop], + ..Default::default() + }) + .remove(0); + let mut input = create_input(); + input.set_maturity(42).unwrap(); + input.set_script(script![Drop Nop]).unwrap(); + + assert!(OutputField::Commitment.is_eq_input(&input, &output)); + assert!(OutputField::Features.is_eq_input(&input, &output)); + assert!(OutputField::Script.is_eq_input(&input, &output)); + assert!(OutputField::Covenant.is_eq_input(&input, &output)); + assert!(OutputField::FeaturesMaturity.is_eq_input(&input, &output)); + assert!(OutputField::FeaturesFlags.is_eq_input(&input, &output)); + assert!(OutputField::FeaturesParentPublicKey.is_eq_input(&input, &output)); + assert!(OutputField::FeaturesMetadata.is_eq_input(&input, &output)); + assert!(OutputField::FeaturesUniqueId.is_eq_input(&input, &output)); + assert!(OutputField::SenderOffsetPublicKey.is_eq_input(&input, &output)); + } + } + + #[test] + fn display() { + let output_fields = [ + OutputField::Commitment, + OutputField::Features, + OutputField::FeaturesFlags, + OutputField::FeaturesUniqueId, + OutputField::FeaturesMetadata, + OutputField::FeaturesMaturity, + OutputField::FeaturesParentPublicKey, + OutputField::SenderOffsetPublicKey, + OutputField::Script, + OutputField::Covenant, + ]; + output_fields.iter().for_each(|f| { + assert!(f.to_string().starts_with("field::")); + }) + } + } + + mod output_fields { + use super::*; + + mod construct_challenge_from { + use super::*; + use crate::consensus::ConsensusEncoding; + + #[test] + fn it_constructs_challenge_using_consensus_encoding() { + let features = OutputFeatures { + maturity: 42, + flags: OutputFlags::COINBASE_OUTPUT, + ..Default::default() + }; + let output = create_outputs(1, UtxoTestParams { + features, + script: script![Drop Nop], + ..Default::default() + }) + .remove(0); + + let mut fields = OutputFields::new(); + fields.push(OutputField::Features); + fields.push(OutputField::Commitment); + fields.push(OutputField::Script); + let hash = fields.construct_challenge_from(&output).finalize(); + + let mut challenge = Vec::new(); + output.features.consensus_encode(&mut challenge).unwrap(); + output.commitment.consensus_encode(&mut challenge).unwrap(); + output.script.consensus_encode(&mut challenge).unwrap(); + let expected_hash = HashDigest::new().chain(&challenge).finalize(); + assert_eq!(hash, expected_hash); + } + } + + mod get_field_value_ref { + use super::*; + + #[test] + fn it_retrieves_the_value_as_ref() { + let mut features = OutputFeatures { + maturity: 42, + ..Default::default() + }; + let output = create_outputs(1, UtxoTestParams { + features: features.clone(), + ..Default::default() + }) + .pop() + .unwrap(); + features.set_recovery_byte(output.features.recovery_byte); + let r = OutputField::Features.get_field_value_ref::(&output); + assert_eq!(*r.unwrap(), features); + } + } } } diff --git a/base_layer/core/src/covenants/filters/field_eq.rs b/base_layer/core/src/covenants/filters/field_eq.rs index d1f6ae28a3..b002f8c0d4 100644 --- a/base_layer/core/src/covenants/filters/field_eq.rs +++ b/base_layer/core/src/covenants/filters/field_eq.rs @@ -165,43 +165,22 @@ mod test { assert_eq!(output_set.get_selected_indexes(), vec![5, 7]); } - // #[test] - // fn it_filters_covenant() { - // // TODO: Covenant field is not in output yet - // let covenant = covenant!(identity()); - // let covenant = covenant!(field_eq( - // @field::covenant, - // @covenant(covenant.clone()) - // )); - // let input = create_input(); - // let mut context = create_context(&covenant, &input, 0); - // // Remove `field_eq` - // context.next_filter().unwrap(); - // let mut outputs = create_outputs(10, Default::default()); - // outputs[5].covenant = covenant.clone(); - // outputs[7].covenant = covenant.clone(); - // let mut output_set = OutputSet::new(&outputs); - // FieldEqFilter.filter(&mut context, &mut output_set).unwrap(); - // - // assert_eq!(output_set.len(), 2); - // assert_eq!(output_set.get_selected_indexes(), vec![5, 7]); - // } - #[test] - fn it_errors_for_unsupported_features_field() { - let covenant = covenant!(field_eq( - @field::features, - @bytes(vec![]) - )); + fn it_filters_covenant() { + let next_cov = covenant!(and(identity(), or(field_eq(@field::features_maturity, @uint(42))))); + let covenant = covenant!(field_eq(@field::covenant, @covenant(next_cov.clone()))); let input = create_input(); let mut context = create_context(&covenant, &input, 0); // Remove `field_eq` context.next_filter().unwrap(); - let outputs = create_outputs(10, Default::default()); + let mut outputs = create_outputs(10, Default::default()); + outputs[5].covenant = next_cov.clone(); + outputs[7].covenant = next_cov; let mut output_set = OutputSet::new(&outputs); - let err = FieldEqFilter.filter(&mut context, &mut output_set).unwrap_err(); - unpack_enum!(CovenantError::UnsupportedArgument { arg, .. } = err); - assert_eq!(arg, "features"); + FieldEqFilter.filter(&mut context, &mut output_set).unwrap(); + + assert_eq!(output_set.len(), 2); + assert_eq!(output_set.get_selected_indexes(), vec![5, 7]); } #[test] diff --git a/base_layer/core/src/covenants/filters/fields_hashed_eq.rs b/base_layer/core/src/covenants/filters/fields_hashed_eq.rs index 3fd6816b44..510c69bed7 100644 --- a/base_layer/core/src/covenants/filters/fields_hashed_eq.rs +++ b/base_layer/core/src/covenants/filters/fields_hashed_eq.rs @@ -20,28 +20,6 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Copyright 2021, The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - use digest::Digest; use crate::covenants::{context::CovenantContext, error::CovenantError, filters::Filter, output_set::OutputSet}; diff --git a/base_layer/core/src/covenants/filters/filter.rs b/base_layer/core/src/covenants/filters/filter.rs index 8310f7e5ec..32539fc0c0 100644 --- a/base_layer/core/src/covenants/filters/filter.rs +++ b/base_layer/core/src/covenants/filters/filter.rs @@ -165,3 +165,17 @@ impl Filter for CovenantFilter { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::covenants::byte_codes::ALL_FILTERS; + + #[test] + fn it_returns_filter_from_byte_code() { + ALL_FILTERS.iter().for_each(|code| { + let filter = CovenantFilter::try_from_byte_code(*code).unwrap(); + assert_eq!(filter.as_byte_code(), *code); + }) + } +} diff --git a/base_layer/core/src/covenants/filters/identity.rs b/base_layer/core/src/covenants/filters/identity.rs index 1748c97810..91e8d3c1fb 100644 --- a/base_layer/core/src/covenants/filters/identity.rs +++ b/base_layer/core/src/covenants/filters/identity.rs @@ -30,3 +30,23 @@ impl Filter for IdentityFilter { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + covenant, + covenants::{filters::test::setup_filter_test, test::create_input}, + }; + + #[test] + fn it_returns_the_outputset_unchanged() { + let covenant = covenant!(identity()); + let input = create_input(); + let (mut context, outputs) = setup_filter_test(&covenant, &input, 0, |_| {}); + let mut output_set = OutputSet::new(&outputs); + let previous_len = output_set.len(); + IdentityFilter.filter(&mut context, &mut output_set).unwrap(); + assert_eq!(output_set.len(), previous_len); + } +} diff --git a/base_layer/core/src/covenants/macros.rs b/base_layer/core/src/covenants/macros.rs index 2690d5773f..247a9020db 100644 --- a/base_layer/core/src/covenants/macros.rs +++ b/base_layer/core/src/covenants/macros.rs @@ -77,16 +77,16 @@ macro_rules! __covenant_inner { $crate::__covenant_inner!(@ { $covenant } $($tail)*) }; - // @covenant(...), ... - (@ { $covenant:ident } @covenant($($inner:tt)*), $($tail:tt)*) => { + // @covenant_lit(...), ... + (@ { $covenant:ident } @covenant_lit($($inner:tt)*), $($tail:tt)*) => { let inner = $crate::covenant!($($inner)*); $covenant.push_token($crate::covenants::CovenantToken::covenant(inner)); $crate::__covenant_inner!(@ { $covenant } $($tail)*) }; - // @covenant(...) - (@ { $covenant:ident } @covenant($($inner:tt)*) $(,)?) => { - $crate::__covenant_inner!(@ { $covenant } @covenant($($inner)*),) + // @covenant_lit(...) + (@ { $covenant:ident } @covenant_lit($($inner:tt)*) $(,)?) => { + $crate::__covenant_inner!(@ { $covenant } @covenant_lit($($inner)*),) }; // @arg(expr1, expr2, ...), ... @@ -200,7 +200,7 @@ mod test { #[test] fn covenant() { let bytes = vec![0xba, 0xda, 0x55]; - let covenant = covenant!(field_eq(@field::covenant, @covenant(and(field_eq(@field::features_unique_id, @bytes(bytes), identity()))))); + let covenant = covenant!(field_eq(@field::covenant, @covenant_lit(and(field_eq(@field::features_unique_id, @bytes(bytes), identity()))))); assert_eq!(covenant.to_bytes().to_hex(), "330703050a213307070903bada5520"); } diff --git a/base_layer/core/src/covenants/token.rs b/base_layer/core/src/covenants/token.rs index f24f63415c..6d618119f0 100644 --- a/base_layer/core/src/covenants/token.rs +++ b/base_layer/core/src/covenants/token.rs @@ -27,7 +27,7 @@ use tari_script::TariScript; use crate::covenants::{ arguments::{CovenantArg, Hash}, - decoder::{CovenantDecodeError, CovenentReadExt}, + decoder::{CovenantDecodeError, CovenantReadExt}, fields::OutputField, filters::{ AbsoluteHeightFilter, diff --git a/base_layer/core/src/validation/block_validators/test.rs b/base_layer/core/src/validation/block_validators/test.rs index 77e340d049..33b21a3818 100644 --- a/base_layer/core/src/validation/block_validators/test.rs +++ b/base_layer/core/src/validation/block_validators/test.rs @@ -460,7 +460,7 @@ mod orphan_validator { let validator = OrphanBlockValidator::new(rules, false, CryptoFactories::default()); let (_, coinbase) = blockchain.append(block_spec!("1", parent: "GB")); - let schema = txn_schema!(from: vec![coinbase.clone()], to: vec![201 * T]); + let schema = txn_schema!(from: vec![coinbase], to: vec![201 * T]); let (initial_tx, outputs) = schema_to_transaction(&[schema]); let schema = txn_schema!(from: vec![outputs[0].clone()], to: vec![200 * T]);