Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Coats committed Oct 3, 2023
1 parent d76dedb commit c8b9b35
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 40 deletions.
2 changes: 1 addition & 1 deletion sdk/src/types/block/output/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ impl DelegationOutput {

// Transition, just without full ValidationContext.
pub(crate) fn transition_inner(current_state: &Self, next_state: &Self) -> Result<(), StateTransitionError> {
if !(current_state.delegation_id.is_null() && !next_state.delegation_id().is_null()) {
if !current_state.delegation_id.is_null() || next_state.delegation_id().is_null() {
return Err(StateTransitionError::NonDelayedClaimingTransition);
}

Expand Down
95 changes: 73 additions & 22 deletions sdk/src/types/block/payload/transaction/essence/regular.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use alloc::{collections::BTreeSet, vec::Vec};

use derive_more::{Deref, From};
use derive_more::Deref;
use hashbrown::HashSet;
use packable::{bounded::BoundedU16, prefix::BoxedSlicePrefix, Packable};

Expand Down Expand Up @@ -433,45 +433,96 @@ fn verify_payload_packable<const VERIFY: bool>(
Ok(())
}

pub struct TransactionCapabilityFlag;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum TransactionCapabilityFlag {
BurnNativeTokens = 0b00000001,
BurnMana = 0b00000010,
DestroyAccountOutputs = 0b00000100,
DestroyFoundryOutputs = 0b00001000,
DestroyNftOutputs = 0b00010000,
}

impl TransactionCapabilityFlag {
pub const BURN_NATIVE_TOKENS: u8 = 0b00000001;
pub const BURN_MANA: u8 = 0b00000010;
pub const DESTROY_ACCOUNT_OUTPUTS: u8 = 0b00000100;
pub const DESTROY_FOUNDRY_OUTPUTS: u8 = 0b00001000;
pub const DESTROY_NFT_OUTPUTS: u8 = 0b00010000;
pub const NONE: u8 = 0;
pub const ALL: u8 = 0b00011111;
pub fn all() -> impl Iterator<Item = Self> {
[
Self::BurnNativeTokens,
Self::BurnMana,
Self::DestroyAccountOutputs,
Self::DestroyFoundryOutputs,
Self::DestroyNftOutputs,
]
.into_iter()
}
}

#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, From, Deref, Packable)]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Deref, Packable)]
#[repr(transparent)]
pub struct TransactionCapabilities(u8);

impl TransactionCapabilities {
pub fn with_capabilities(mut self, flags: impl Into<u8>) -> Self {
self.0 |= flags.into();
pub const NONE: Self = Self(0);
pub const ALL: Self = Self(0b00011111);

pub fn is_all(&self) -> bool {
Self::ALL.eq(self)
}

pub fn is_none(&self) -> bool {
Self::NONE.eq(self)
}

pub fn set_all(&mut self) -> &mut Self {
*self = Self::ALL;
self
}

pub fn add_capabilities(&mut self, flags: impl Into<u8>) -> &mut Self {
self.0 |= flags.into();
pub fn set_none(&mut self) -> &mut Self {
*self = Self::NONE;
self
}

pub fn set_capabilities(&mut self, flags: impl Into<u8>) -> &mut Self {
self.0 = flags.into();
pub fn add_capability(&mut self, flag: TransactionCapabilityFlag) -> &mut Self {
self.0 |= flag as u8;
self
}

pub fn has_capabilities(&self, flags: impl Into<u8>) -> bool {
let flags = flags.into();
self.0 & flags == flags
pub fn add_capabilities(&mut self, flags: impl IntoIterator<Item = TransactionCapabilityFlag>) -> &mut Self {
for flag in flags {
self.add_capability(flag);
}
self
}

pub fn is_none(&self) -> bool {
self.0 == 0
pub fn with_capabilities(mut self, flags: impl IntoIterator<Item = TransactionCapabilityFlag>) -> Self {
for flag in flags {
self.add_capability(flag);
}
self
}

pub fn set_capabilities(&mut self, flags: impl IntoIterator<Item = TransactionCapabilityFlag>) -> &mut Self {
*self = Self::default().with_capabilities(flags);
self
}

pub fn has_capability(&self, flag: TransactionCapabilityFlag) -> bool {
self.0 & flag as u8 == flag as u8
}

pub fn has_capabilities(&self, flags: impl IntoIterator<Item = TransactionCapabilityFlag>) -> bool {
flags.into_iter().all(|flag| self.has_capability(flag))
}

pub fn split(self) -> impl Iterator<Item = TransactionCapabilityFlag> {
TransactionCapabilityFlag::all().filter(move |f| self.has_capability(*f))
}
}

impl<I: IntoIterator<Item = TransactionCapabilityFlag>> From<I> for TransactionCapabilities {
fn from(value: I) -> Self {
Self::default().with_capabilities(value)
}
}

Expand Down Expand Up @@ -554,7 +605,7 @@ pub(crate) mod dto {
.with_inputs(dto.inputs)
.with_outputs(outputs)
.with_mana_allotments(mana_allotments)
.with_capabilities(dto.capabilities);
.with_capabilities(TransactionCapabilities(dto.capabilities));

builder = if let Some(p) = dto.payload {
if let PayloadDto::TaggedData(i) = p {
Expand Down
10 changes: 5 additions & 5 deletions sdk/src/types/block/semantic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ pub fn semantic_validation(
&& !context
.essence
.capabilities()
.has_capabilities(TransactionCapabilityFlag::DESTROY_ACCOUNT_OUTPUTS)
.has_capability(TransactionCapabilityFlag::DestroyAccountOutputs)
{
// TODO: better failure reason incoming?
return Ok(Some(TransactionFailureReason::SemanticValidationFailed));
Expand All @@ -287,7 +287,7 @@ pub fn semantic_validation(
&& !context
.essence
.capabilities()
.has_capabilities(TransactionCapabilityFlag::DESTROY_FOUNDRY_OUTPUTS)
.has_capability(TransactionCapabilityFlag::DestroyFoundryOutputs)
{
// TODO: better failure reason incoming?
return Ok(Some(TransactionFailureReason::SemanticValidationFailed));
Expand All @@ -300,7 +300,7 @@ pub fn semantic_validation(
&& !context
.essence
.capabilities()
.has_capabilities(TransactionCapabilityFlag::DESTROY_NFT_OUTPUTS)
.has_capability(TransactionCapabilityFlag::DestroyNftOutputs)
{
// TODO: better failure reason incoming?
return Ok(Some(TransactionFailureReason::SemanticValidationFailed));
Expand Down Expand Up @@ -439,7 +439,7 @@ pub fn semantic_validation(
&& context
.essence
.capabilities()
.has_capabilities(TransactionCapabilityFlag::BURN_MANA)
.has_capability(TransactionCapabilityFlag::BurnMana)
{
// TODO: better failure reason incoming?
return Ok(Some(TransactionFailureReason::SemanticValidationFailed));
Expand All @@ -455,7 +455,7 @@ pub fn semantic_validation(
&& context
.essence
.capabilities()
.has_capabilities(TransactionCapabilityFlag::BURN_NATIVE_TOKENS)
.has_capability(TransactionCapabilityFlag::BurnNativeTokens)
{
// TODO: better failure reason incoming?
return Ok(Some(TransactionFailureReason::SemanticValidationFailed));
Expand Down
27 changes: 15 additions & 12 deletions sdk/tests/types/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use iota_sdk::types::block::{
input::{Input, UtxoInput},
output::{unlock_condition::AddressUnlockCondition, BasicOutput, Output},
payload::{
transaction::{RegularTransactionEssence, TransactionCapabilityFlag, TransactionId, TransactionPayload},
transaction::{
RegularTransactionEssence, TransactionCapabilities, TransactionCapabilityFlag, TransactionId,
TransactionPayload,
},
Payload, TaggedDataPayload,
},
protocol::protocol_parameters,
Expand Down Expand Up @@ -90,21 +93,21 @@ fn transactions_capabilities() {

assert!(capabilities.is_none());

assert!(!capabilities.has_capabilities(Flag::BURN_NATIVE_TOKENS));
capabilities.add_capabilities(Flag::BURN_NATIVE_TOKENS);
assert!(capabilities.has_capabilities(Flag::BURN_NATIVE_TOKENS));
assert!(!capabilities.has_capability(Flag::BurnNativeTokens));
capabilities.add_capability(Flag::BurnNativeTokens);
assert!(capabilities.has_capabilities([Flag::BurnNativeTokens]));

assert!(!capabilities.has_capabilities(Flag::BURN_MANA));
capabilities.set_capabilities(Flag::BURN_MANA | Flag::DESTROY_ACCOUNT_OUTPUTS);
assert!(capabilities.has_capabilities(Flag::BURN_MANA | Flag::DESTROY_ACCOUNT_OUTPUTS));
assert!(!capabilities.has_capabilities(Flag::BURN_NATIVE_TOKENS));
assert!(!capabilities.has_capability(Flag::BurnMana));
capabilities.set_capabilities([Flag::BurnMana, Flag::DestroyAccountOutputs]);
assert!(capabilities.has_capabilities([Flag::BurnMana, Flag::DestroyAccountOutputs]));
assert!(!capabilities.has_capability(Flag::BurnNativeTokens));

assert!(!capabilities.is_none());

assert!(!capabilities.has_capabilities(Flag::ALL));
capabilities.add_capabilities(Flag::ALL);
assert!(capabilities.has_capabilities(Flag::ALL));
assert!(capabilities.has_capabilities(Flag::DESTROY_FOUNDRY_OUTPUTS | Flag::DESTROY_NFT_OUTPUTS));
assert!(!capabilities.has_capabilities(TransactionCapabilities::ALL.split()));
capabilities.set_all();
assert!(capabilities.has_capabilities(TransactionCapabilities::ALL.split()));
assert!(capabilities.has_capabilities([Flag::DestroyFoundryOutputs, Flag::DestroyNftOutputs]));
}

#[test]
Expand Down

0 comments on commit c8b9b35

Please sign in to comment.