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

Add restricted address semantic validation #1454

Merged
merged 8 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ iterator-sorted = { version = "0.1.0", default-features = false }
packable = { version = "0.8.3", default-features = false, features = [
"primitive-types",
] }
paste = { version = "1.0.14", default-features = false }
prefix-hex = { version = "0.7.1", default-features = false, features = [
"primitive-types",
] }
Expand Down
45 changes: 1 addition & 44 deletions sdk/src/types/block/address/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,50 +83,7 @@ impl Address {
}
}

/// Checks whether the address is an [`Ed25519Address`].
pub fn is_ed25519(&self) -> bool {
matches!(self, Self::Ed25519(_))
}

/// Gets the address as an actual [`Ed25519Address`].
/// PANIC: do not call on a non-ed25519 address.
pub fn as_ed25519(&self) -> &Ed25519Address {
if let Self::Ed25519(address) = self {
address
} else {
panic!("as_ed25519 called on a non-ed25519 address");
}
}

/// Checks whether the address is an [`AccountAddress`].
pub fn is_account(&self) -> bool {
matches!(self, Self::Account(_))
}

/// Gets the address as an actual [`AccountAddress`].
/// PANIC: do not call on a non-account address.
pub fn as_account(&self) -> &AccountAddress {
if let Self::Account(address) = self {
address
} else {
panic!("as_account called on a non-account address");
}
}

/// Checks whether the address is an [`NftAddress`].
pub fn is_nft(&self) -> bool {
matches!(self, Self::Nft(_))
}

/// Gets the address as an actual [`NftAddress`].
/// PANIC: do not call on a non-nft address.
pub fn as_nft(&self) -> &NftAddress {
if let Self::Nft(address) = self {
address
} else {
panic!("as_nft called on a non-nft address");
}
}
def_is_as_opt!(Address: Ed25519, Account, Nft, ImplicitAccountCreation, Restricted);

/// Tries to create an [`Address`] from a bech32 encoded string.
pub fn try_from_bech32(address: impl AsRef<str>) -> Result<Self, Error> {
Expand Down
5 changes: 5 additions & 0 deletions sdk/src/types/block/address/restricted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ impl RestrictedAddress {
self.allowed_capabilities = allowed_capabilities.into();
self
}

/// Returns whether a given [`AddressCapabilityFlag`] is enabled.
pub fn has_capability(&self, flag: AddressCapabilityFlag) -> bool {
self.allowed_capabilities.has_capability(flag)
}
}

impl TryFrom<Address> for RestrictedAddress {
Expand Down
45 changes: 1 addition & 44 deletions sdk/src/types/block/context_input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,50 +59,7 @@ impl ContextInput {
}
}

/// Checks whether the context input is a [`CommitmentContextInput`].
pub fn is_commitment(&self) -> bool {
matches!(self, Self::Commitment(_))
}

/// Gets the input as an actual [`CommitmentContextInput`].
/// PANIC: do not call on a non-commitment context input.
pub fn as_commitment(&self) -> &CommitmentContextInput {
if let Self::Commitment(input) = self {
input
} else {
panic!("invalid downcast of non-CommitmentContextInput");
}
}

/// Checks whether the context input is a [`BlockIssuanceCreditContextInput`].
pub fn is_block_issuance_credit(&self) -> bool {
matches!(self, Self::BlockIssuanceCredit(_))
}

/// Gets the input as an actual [`BlockIssuanceCreditContextInput`].
/// PANIC: do not call on a non-block-issuance-credit context input.
pub fn as_block_issuance_credit(&self) -> &BlockIssuanceCreditContextInput {
if let Self::BlockIssuanceCredit(input) = self {
input
} else {
panic!("invalid downcast of non-BlockIssuanceCreditContextInput");
}
}

/// Checks whether the context input is a [`RewardContextInput`].
pub fn is_reward(&self) -> bool {
matches!(self, Self::Reward(_))
}

/// Gets the input as an actual [`RewardContextInput`].
/// PANIC: do not call on a non-reward context input.
pub fn as_reward(&self) -> &RewardContextInput {
if let Self::Reward(input) = self {
input
} else {
panic!("invalid downcast of non-RewardContextInput");
}
}
def_is_as_opt!(ContextInput: Commitment, BlockIssuanceCredit, Reward);
}

#[cfg(test)]
Expand Down
30 changes: 1 addition & 29 deletions sdk/src/types/block/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,35 +95,7 @@ impl Block {
ValidationBlockBuilder::new(strong_parents, highest_supported_version, protocol_parameters_hash)
}

/// Checks whether the block is a [`BasicBlock`].
pub fn is_basic(&self) -> bool {
matches!(self, Self::Basic(_))
}

/// Gets the block as an actual [`BasicBlock`].
/// NOTE: Will panic if the block is not a [`BasicBlock`].
pub fn as_basic(&self) -> &BasicBlock {
if let Self::Basic(block) = self {
block
} else {
panic!("invalid downcast of non-BasicBlock");
}
}

/// Checks whether the block is a [`ValidationBlock`].
pub fn is_validation(&self) -> bool {
matches!(self, Self::Validation(_))
}

/// Gets the block as an actual [`ValidationBlock`].
/// NOTE: Will panic if the block is not a [`ValidationBlock`].
pub fn as_validation(&self) -> &ValidationBlock {
if let Self::Validation(block) = self {
block
} else {
panic!("invalid downcast of non-ValidationBlock");
}
}
def_is_as_opt!(Block: Basic, Validation);

pub(crate) fn hash(&self) -> [u8; 32] {
Blake2b256::digest(self.pack_to_vec()).into()
Expand Down
12 changes: 1 addition & 11 deletions sdk/src/types/block/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,5 @@ impl Input {
}
}

/// Checks whether the input is a [`UtxoInput`].
pub fn is_utxo(&self) -> bool {
matches!(self, Self::Utxo(_))
}

/// Gets the input as an actual [`UtxoInput`].
/// PANIC: do not call on a non-utxo input.
pub fn as_utxo(&self) -> &UtxoInput {
let Self::Utxo(input) = self;
input
}
def_is_as_opt!(Input: Utxo);
}
35 changes: 35 additions & 0 deletions sdk/src/types/block/macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,38 @@ macro_rules! impl_serde_typed_dto {
}
};
}

#[macro_export]
macro_rules! def_is_as_opt {
($type:ty: $($name:ident),+$(,)?) => {
paste::paste! {
$(
#[doc = "Checks whether the " [<$type:snake>] " is a(n) [`" [<$name $type>] "`]."]
pub fn [<is_ $name:snake>](&self) -> bool {
matches!(self, Self::$name(_))
}

#[doc = "Gets the " [<$type:snake>] " as an actual [`" [<$name $type>] "`]."]
#[doc = "PANIC: do not call on a non-" [<$name>] " " [<$type:snake>] "."]
pub fn [<as_ $name:snake>](&self) -> &[<$name $type>] {
#[allow(irrefutable_let_patterns)]
if let Self::$name(v) = self {
v
} else {
panic!("{} called on a non-{} {}", stringify!([<as_ $name:snake>]), stringify!([<$name>]), stringify!($type:snake));
}
}

#[doc = "Gets the " [<$type:snake>] " as an actual [`" [<$name $type>] "`], if it is one."]
pub fn [<as_ $name:snake _opt>](&self) -> Option<&[<$name $type>]> {
#[allow(irrefutable_let_patterns)]
if let Self::$name(v) = self {
Some(v)
} else {
None
}
}
)+
}
};
}
12 changes: 1 addition & 11 deletions sdk/src/types/block/output/feature/block_issuer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,7 @@ impl BlockIssuerKey {
}
}

/// Checks whether the block issuer key is an [`Ed25519BlockIssuerKey`].
pub fn is_ed25519(&self) -> bool {
matches!(self, Self::Ed25519(_))
}

/// Gets the block issuer key as an actual [`Ed25519BlockIssuerKey`].
/// NOTE: Will panic if the block issuer key is not a [`Ed25519BlockIssuerKey`].
pub fn as_ed25519(&self) -> &Ed25519BlockIssuerKey {
let Self::Ed25519(key) = self;
key
}
def_is_as_opt!(BlockIssuerKey: Ed25519);
}

/// An Ed25519 block issuer key.
Expand Down
90 changes: 1 addition & 89 deletions sdk/src/types/block/output/feature/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,95 +106,7 @@ impl Feature {
}
}

/// Checks whether the feature is a [`SenderFeature`].
pub fn is_sender(&self) -> bool {
matches!(self, Self::Sender(_))
}

/// Gets the feature as an actual [`SenderFeature`].
/// NOTE: Will panic if the feature is not a [`SenderFeature`].
pub fn as_sender(&self) -> &SenderFeature {
if let Self::Sender(feature) = self {
feature
} else {
panic!("invalid downcast of non-SenderFeature");
}
}

/// Checks whether the feature is an [`IssuerFeature`].
pub fn is_issuer(&self) -> bool {
matches!(self, Self::Issuer(_))
}

/// Gets the feature as an actual [`IssuerFeature`].
/// NOTE: Will panic if the feature is not an [`IssuerFeature`].
pub fn as_issuer(&self) -> &IssuerFeature {
if let Self::Issuer(feature) = self {
feature
} else {
panic!("invalid downcast of non-IssuerFeature");
}
}

/// Checks whether the feature is a [`MetadataFeature`].
pub fn is_metadata(&self) -> bool {
matches!(self, Self::Metadata(_))
}

/// Gets the feature as an actual [`MetadataFeature`].
/// NOTE: Will panic if the feature is not a [`MetadataFeature`].
pub fn as_metadata(&self) -> &MetadataFeature {
if let Self::Metadata(feature) = self {
feature
} else {
panic!("invalid downcast of non-MetadataFeature");
}
}

/// Checks whether the feature is a [`TagFeature`].
pub fn is_tag(&self) -> bool {
matches!(self, Self::Tag(_))
}

/// Gets the feature as an actual [`TagFeature`].
/// NOTE: Will panic if the feature is not a [`TagFeature`].
pub fn as_tag(&self) -> &TagFeature {
if let Self::Tag(feature) = self {
feature
} else {
panic!("invalid downcast of non-TagFeature");
}
}

/// Checks whether the feature is a [`BlockIssuerFeature`].
pub fn is_block_issuer(&self) -> bool {
matches!(self, Self::BlockIssuer(_))
}

/// Gets the feature as an actual [`BlockIssuerFeature`].
/// NOTE: Will panic if the feature is not a [`BlockIssuerFeature`].
pub fn as_block_issuer(&self) -> &BlockIssuerFeature {
if let Self::BlockIssuer(feature) = self {
feature
} else {
panic!("invalid downcast of non-BlockIssuerFeature");
}
}

/// Checks whether the feature is a [`StakingFeature`].
pub fn is_staking(&self) -> bool {
matches!(self, Self::Staking(_))
}

/// Gets the feature as an actual [`StakingFeature`].
/// NOTE: Will panic if the feature is not a [`StakingFeature`].
pub fn as_staking(&self) -> &StakingFeature {
if let Self::Staking(feature) = self {
feature
} else {
panic!("invalid downcast of non-StakingFeature");
}
}
def_is_as_opt!(Feature: Sender, Issuer, Metadata, Tag, BlockIssuer, Staking);
}

create_bitflags!(
Expand Down
Loading
Loading