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/covenants)!: update covenants to support OutputType enum #4472

Merged
Show file tree
Hide file tree
Changes from 1 commit
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
19 changes: 17 additions & 2 deletions base_layer/core/src/covenants/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use crate::{
error::CovenantError,
fields::{OutputField, OutputFields},
},
transactions::transaction_components::OutputType,
};

const MAX_COVENANT_ARG_SIZE: usize = 4096;
Expand All @@ -52,6 +53,7 @@ pub enum CovenantArg {
Commitment(Commitment),
TariScript(TariScript),
Covenant(Covenant),
OutputType(OutputType),
Uint(u64),
OutputField(OutputField),
OutputFields(OutputFields),
Expand Down Expand Up @@ -88,6 +90,10 @@ impl CovenantArg {
let covenant = Covenant::from_bytes(&buf)?;
Ok(CovenantArg::Covenant(covenant))
},
ARG_OUTPUT_TYPE => {
let output_type = OutputType::consensus_decode(reader)?;
Ok(CovenantArg::OutputType(output_type))
},
ARG_UINT => {
let v = u64::consensus_decode(reader)?;
Ok(CovenantArg::Uint(v))
Expand Down Expand Up @@ -117,7 +123,8 @@ impl CovenantArg {

pub fn write_to<W: io::Write>(&self, writer: &mut W) -> Result<(), io::Error> {
use byte_codes::*;
use CovenantArg::{Bytes, Commitment, Covenant, Hash, OutputField, OutputFields, PublicKey, TariScript, Uint};
#[allow(clippy::enum_glob_use)]
use CovenantArg::*;

match self {
Hash(hash) => {
Expand All @@ -142,6 +149,10 @@ impl CovenantArg {
writer.write_varint(len)?;
covenant.write_to(writer)?;
},
OutputType(output_type) => {
writer.write_u8_fixed(ARG_OUTPUT_TYPE)?;
output_type.consensus_encode(writer)?;
},
Uint(int) => {
writer.write_u8_fixed(ARG_UINT)?;
int.consensus_encode(writer)?;
Expand Down Expand Up @@ -193,6 +204,8 @@ impl CovenantArg {

require_x_impl!(require_covenant, Covenant, "covenant");

require_x_impl!(require_output_type, OutputType, "output_type");

require_x_impl!(require_outputfield, OutputField, "outputfield");

require_x_impl!(require_outputfields, OutputFields, "outputfields");
Expand Down Expand Up @@ -220,7 +233,8 @@ impl CovenantArg {

impl Display for CovenantArg {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
use CovenantArg::{Bytes, Commitment, Covenant, Hash, OutputField, OutputFields, PublicKey, TariScript, Uint};
#[allow(clippy::enum_glob_use)]
use CovenantArg::*;
match self {
Hash(hash) => write!(f, "Hash({})", to_hex(&hash[..])),
PublicKey(public_key) => write!(f, "PublicKey({})", public_key.to_hex()),
Expand All @@ -231,6 +245,7 @@ impl Display for CovenantArg {
OutputField(field) => write!(f, "OutputField({})", field.as_byte()),
OutputFields(fields) => write!(f, "OutputFields({} field(s))", fields.len()),
Bytes(bytes) => write!(f, "Bytes({} byte(s))", bytes.len()),
OutputType(output_type) => write!(f, "OutputType({})", output_type),
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions base_layer/core/src/covenants/byte_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub(super) fn is_valid_arg_code(code: u8) -> bool {
ALL_ARGS.contains(&code)
}

pub(super) const ALL_ARGS: [u8; 9] = [
pub(super) const ALL_ARGS: [u8; 10] = [
ARG_HASH,
ARG_PUBLIC_KEY,
ARG_COMMITMENT,
Expand All @@ -35,6 +35,7 @@ pub(super) const ALL_ARGS: [u8; 9] = [
ARG_OUTPUT_FIELD,
ARG_OUTPUT_FIELDS,
ARG_BYTES,
ARG_OUTPUT_TYPE,
];

pub const ARG_HASH: u8 = 0x01;
Expand All @@ -46,6 +47,7 @@ pub const ARG_UINT: u8 = 0x06;
pub const ARG_OUTPUT_FIELD: u8 = 0x07;
pub const ARG_OUTPUT_FIELDS: u8 = 0x08;
pub const ARG_BYTES: u8 = 0x09;
pub const ARG_OUTPUT_TYPE: u8 = 0x0a;

//---------------------------------- FILTER byte codes --------------------------------------------//

Expand Down Expand Up @@ -84,7 +86,7 @@ pub const FIELD_SCRIPT: u8 = 0x01;
pub const FIELD_SENDER_OFFSET_PUBLIC_KEY: u8 = 0x02;
pub const FIELD_COVENANT: u8 = 0x03;
pub const FIELD_FEATURES: u8 = 0x04;
pub const FIELD_FEATURES_FLAGS: u8 = 0x05;
pub const FIELD_FEATURES_OUTPUT_TYPE: u8 = 0x05;
pub const FIELD_FEATURES_MATURITY: u8 = 0x06;
pub const FIELD_FEATURES_METADATA: u8 = 0x07;
pub const FIELD_FEATURES_SIDE_CHAIN_FEATURES: u8 = 0x08;
Expand Down
2 changes: 1 addition & 1 deletion base_layer/core/src/covenants/covenant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ mod test {
let mut input = create_input();
input.set_maturity(42).unwrap();
let covenant = covenant!(fields_preserved(@fields(
@field::features_flags,
@field::features_output_type,
@field::features_maturity,
@field::features_contract_id,
@field::features_metadata))
Expand Down
24 changes: 12 additions & 12 deletions base_layer/core/src/covenants/fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub enum OutputField {
SenderOffsetPublicKey = byte_codes::FIELD_SENDER_OFFSET_PUBLIC_KEY,
Covenant = byte_codes::FIELD_COVENANT,
Features = byte_codes::FIELD_FEATURES,
FeaturesFlags = byte_codes::FIELD_FEATURES_FLAGS,
FeaturesOutputType = byte_codes::FIELD_FEATURES_OUTPUT_TYPE,
FeaturesMaturity = byte_codes::FIELD_FEATURES_MATURITY,
FeaturesUniqueId = byte_codes::FIELD_FEATURES_UNIQUE_ID,
FeaturesParentPublicKey = byte_codes::FIELD_FEATURES_PARENT_PUBLIC_KEY,
Expand All @@ -70,7 +70,7 @@ impl OutputField {
FIELD_SENDER_OFFSET_PUBLIC_KEY => Ok(SenderOffsetPublicKey),
FIELD_COVENANT => Ok(Covenant),
FIELD_FEATURES => Ok(Features),
FIELD_FEATURES_FLAGS => Ok(FeaturesFlags),
FIELD_FEATURES_OUTPUT_TYPE => Ok(FeaturesOutputType),
FIELD_FEATURES_MATURITY => Ok(FeaturesMaturity),
FIELD_FEATURES_UNIQUE_ID => Ok(FeaturesUniqueId),
FIELD_FEATURES_PARENT_PUBLIC_KEY => Ok(FeaturesParentPublicKey),
Expand All @@ -95,7 +95,7 @@ impl OutputField {
SenderOffsetPublicKey => &output.sender_offset_public_key as &dyn Any,
Covenant => &output.covenant as &dyn Any,
Features => &output.features as &dyn Any,
FeaturesFlags => &output.features.output_type as &dyn Any,
FeaturesOutputType => &output.features.output_type as &dyn Any,
FeaturesMaturity => &output.features.maturity as &dyn Any,
FeaturesUniqueId => &output.features.unique_id as &dyn Any,
FeaturesParentPublicKey => &output.features.parent_public_key as &dyn Any,
Expand Down Expand Up @@ -123,7 +123,7 @@ impl OutputField {
SenderOffsetPublicKey => output.sender_offset_public_key.to_consensus_bytes(),
Covenant => output.covenant.to_consensus_bytes(),
Features => output.features.to_consensus_bytes(),
FeaturesFlags => output.features.output_type.to_consensus_bytes(),
FeaturesOutputType => output.features.output_type.to_consensus_bytes(),
FeaturesMaturity => output.features.maturity.to_consensus_bytes(),
FeaturesUniqueId => output.features.unique_id.to_consensus_bytes(),
FeaturesParentPublicKey => output.features.parent_public_key.to_consensus_bytes(),
Expand Down Expand Up @@ -154,7 +154,7 @@ impl OutputField {
.features()
.map(|features| *features == output.features)
.unwrap_or(false),
FeaturesFlags => input
FeaturesOutputType => input
.features()
.map(|features| features.output_type == output.features.output_type)
.unwrap_or(false),
Expand Down Expand Up @@ -261,8 +261,8 @@ impl OutputField {
}

#[allow(dead_code)]
pub fn features_flags() -> Self {
OutputField::FeaturesFlags
pub fn features_output_type() -> Self {
OutputField::FeaturesOutputType
}

#[allow(dead_code)]
Expand Down Expand Up @@ -306,7 +306,7 @@ impl Display for OutputField {
Script => write!(f, "field::script"),
Covenant => write!(f, "field::covenant"),
Features => write!(f, "field::features"),
FeaturesFlags => write!(f, "field::features_flags"),
FeaturesOutputType => write!(f, "field::features_flags"),
FeaturesUniqueId => write!(f, "field::features_unique_id"),
FeaturesSideChainFeatures => write!(f, "field::features_sidechain_features"),
FeaturesSideChainFeaturesContractId => write!(f, "field::features_contract_id"),
Expand Down Expand Up @@ -438,7 +438,7 @@ mod test {
assert!(OutputField::FeaturesMaturity
.is_eq(&output, &output.features.maturity)
.unwrap());
assert!(OutputField::FeaturesFlags
assert!(OutputField::FeaturesOutputType
.is_eq(&output, &output.features.output_type)
.unwrap());
assert!(OutputField::FeaturesSideChainFeatures
Expand Down Expand Up @@ -481,7 +481,7 @@ mod test {
.is_eq(&output, &covenant!(and(identity(), identity())))
.unwrap());
assert!(!OutputField::FeaturesMaturity.is_eq(&output, &123u64).unwrap());
assert!(!OutputField::FeaturesFlags
assert!(!OutputField::FeaturesOutputType
.is_eq(&output, &OutputType::Coinbase)
.unwrap());
assert!(!OutputField::FeaturesSideChainFeatures
Expand Down Expand Up @@ -534,7 +534,7 @@ mod test {
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::FeaturesOutputType.is_eq_input(&input, &output));
assert!(OutputField::FeaturesParentPublicKey.is_eq_input(&input, &output));
assert!(OutputField::FeaturesSideChainFeatures.is_eq_input(&input, &output));
assert!(OutputField::FeaturesSideChainFeaturesContractId.is_eq_input(&input, &output));
Expand All @@ -549,7 +549,7 @@ mod test {
let output_fields = [
OutputField::Commitment,
OutputField::Features,
OutputField::FeaturesFlags,
OutputField::FeaturesOutputType,
OutputField::FeaturesUniqueId,
OutputField::FeaturesSideChainFeatures,
OutputField::FeaturesSideChainFeaturesContractId,
Expand Down
19 changes: 19 additions & 0 deletions base_layer/core/src/covenants/filters/field_eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ impl Filter for FieldEqFilter {
Commitment(commitment) => field.is_eq(output, commitment),
TariScript(script) => field.is_eq(output, script),
Covenant(covenant) => field.is_eq(output, covenant),
OutputType(output_type) => field.is_eq(output, output_type),
Uint(int) => {
let val = field
.get_field_value_ref::<u64>(output)
Expand Down Expand Up @@ -81,6 +82,7 @@ mod test {
use crate::{
covenant,
covenants::test::{create_context, create_input, create_outputs},
transactions::transaction_components::OutputType,
};

#[test]
Expand Down Expand Up @@ -180,6 +182,23 @@ mod test {
assert_eq!(output_set.get_selected_indexes(), vec![5, 7]);
}

#[test]
fn it_filters_output_type() {
let covenant = covenant!(field_eq(@field::features_output_type, @output_type(Coinbase)));
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].features.output_type = OutputType::Coinbase;
outputs[7].features.output_type = OutputType::Coinbase;
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_if_field_has_an_incorrect_type() {
let covenant = covenant!(field_eq(@field::features, @uint(42)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ mod test {
#[test]
fn it_filters_outputs_that_match_input_fields() {
let hash = FixedHash::hash_bytes("A");
let covenant = covenant!(fields_preserved(@fields(@field::features_maturity, @field::features_contract_id, @field::features_flags)));
let covenant = covenant!(fields_preserved(@fields(@field::features_maturity, @field::features_contract_id, @field::features_output_type)));
let mut input = create_input();
input.set_maturity(42).unwrap();
input.features_mut().unwrap().sidechain_features = Some(Box::new(SideChainFeatures::new(hash)));
Expand Down
7 changes: 7 additions & 0 deletions base_layer/core/src/covenants/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ macro_rules! __covenant_inner {
$crate::__covenant_inner!(@ { $covenant } @covenant_lit($($inner)*),)
};

// @output_type(expr1), ...
(@ { $covenant:ident } @output_type($arg:expr $(,)?), $($tail:tt)*) => {
use $crate::transactions::transaction_components::OutputType::*;
$covenant.push_token($crate::covenants::CovenantToken::output_type($arg));
$crate::__covenant_inner!(@ { $covenant } $($tail)*)
};

// @arg(expr1, expr2, ...), ...
(@ { $covenant:ident } @$arg:ident($($args:expr),* $(,)?), $($tail:tt)*) => {
$covenant.push_token($crate::covenants::CovenantToken::$arg($($args),*));
Expand Down
42 changes: 25 additions & 17 deletions base_layer/core/src/covenants/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,27 @@ use std::{collections::VecDeque, io, iter::FromIterator};
use tari_common_types::types::{Commitment, FixedHash, PublicKey};
use tari_script::TariScript;

use crate::covenants::{
arguments::CovenantArg,
decoder::{CovenantDecodeError, CovenantReadExt},
fields::OutputField,
filters::{
AbsoluteHeightFilter,
AndFilter,
CovenantFilter,
FieldEqFilter,
FieldsHashedEqFilter,
FieldsPreservedFilter,
IdentityFilter,
NotFilter,
OrFilter,
OutputHashEqFilter,
XorFilter,
use crate::{
covenants::{
arguments::CovenantArg,
decoder::{CovenantDecodeError, CovenantReadExt},
fields::OutputField,
filters::{
AbsoluteHeightFilter,
AndFilter,
CovenantFilter,
FieldEqFilter,
FieldsHashedEqFilter,
FieldsPreservedFilter,
IdentityFilter,
NotFilter,
OrFilter,
OutputHashEqFilter,
XorFilter,
},
Covenant,
},
Covenant,
transactions::transaction_components::OutputType,
};

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -174,6 +177,11 @@ impl CovenantToken {
CovenantArg::Uint(val).into()
}

#[allow(dead_code)]
pub fn output_type(output_type: OutputType) -> Self {
CovenantArg::OutputType(output_type).into()
}

#[allow(dead_code)]
pub fn field(field: OutputField) -> Self {
CovenantArg::OutputField(field).into()
Expand Down