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

feat: add block issuer feature #984

Merged
merged 42 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a2b493e
init
qrayven Jul 28, 2023
bf9801c
init
qrayven Jul 28, 2023
101a95f
Merge branch '2.0' into pr/qrayven/889
qrayven Aug 1, 2023
98f0719
feat: block issuer feature
qrayven Aug 1, 2023
ab28953
add rand
qrayven Aug 1, 2023
5419ba2
some fixes
qrayven Aug 1, 2023
d5cb04c
fix more issues
qrayven Aug 1, 2023
ba84964
change order in rand
qrayven Aug 1, 2023
6818f91
fix no_std for box
qrayven Aug 1, 2023
e289900
fix no_std for macro
qrayven Aug 1, 2023
11b9c0d
remove unnecessary imports
qrayven Aug 1, 2023
cbba160
too much
qrayven Aug 1, 2023
6f81054
Merge branch '2.0' into pr/qrayven/889
qrayven Aug 1, 2023
1717a61
fix error order
qrayven Aug 1, 2023
d591eaa
addressing comments
qrayven Aug 2, 2023
7f35d52
Update sdk/src/types/block/rand/public_key.rs
qrayven Aug 2, 2023
dc41f9a
Update sdk/src/types/block/output/feature/block_issuer.rs
qrayven Aug 2, 2023
e1af229
Update sdk/src/types/block/output/feature/block_issuer.rs
qrayven Aug 2, 2023
bae2972
Update sdk/src/types/block/output/feature/block_issuer.rs
qrayven Aug 2, 2023
0d8df8a
fixing issues
qrayven Aug 3, 2023
7464531
unused imports
qrayven Aug 3, 2023
ef3fb47
Merge branch '2.0' into pr/qrayven/889
qrayven Aug 3, 2023
e86edda
remove alloc
qrayven Aug 3, 2023
8d525e6
add string ser-de for slot index
qrayven Aug 3, 2023
0ec5cfa
fmt
qrayven Aug 3, 2023
4d6be36
clippyt
qrayven Aug 3, 2023
802bc2b
Update sdk/src/types/block/rand/output/feature.rs
qrayven Aug 3, 2023
4d365ce
Update sdk/src/types/block/output/feature/block_issuer.rs
qrayven Aug 3, 2023
b77339d
Update sdk/src/types/block/output/feature/block_issuer.rs
qrayven Aug 3, 2023
d347906
address issues
qrayven Aug 3, 2023
68fdc0e
use btreeset
qrayven Aug 3, 2023
b3c23b9
fix
qrayven Aug 3, 2023
ec16552
Merge branch '2.0' into pr/qrayven/889
Aug 3, 2023
2e1e887
Merge branch '2.0' into pr/qrayven/889
qrayven Aug 4, 2023
eb096b5
add uniq and sorted public keys
qrayven Aug 4, 2023
99690b1
fmt
qrayven Aug 4, 2023
ccc91e7
fmt
qrayven Aug 4, 2023
8d2b52b
clippy
qrayven Aug 4, 2023
e7125ec
Merge branch '2.0' into pr/qrayven/889
qrayven Aug 4, 2023
c21406a
fix non-std
qrayven Aug 4, 2023
0c83442
fmt
qrayven Aug 4, 2023
a54d406
remove default
qrayven Aug 4, 2023
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
7 changes: 5 additions & 2 deletions sdk/src/types/block/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ use primitive_types::U256;
use crate::types::block::{
input::UtxoInput,
output::{
feature::FeatureCount, unlock_condition::UnlockConditionCount, AccountId, ChainId, MetadataFeatureLength,
NativeTokenCount, NftId, OutputIndex, StateMetadataLength, TagFeatureLength,
feature::block_issuer::PublicKeyCount, feature::FeatureCount, unlock_condition::UnlockConditionCount,
AccountId, ChainId, MetadataFeatureLength, NativeTokenCount, NftId, OutputIndex, StateMetadataLength,
TagFeatureLength,
},
payload::{InputCount, OutputCount, TagLength, TaggedDataLength},
unlock::{UnlockCount, UnlockIndex},
Expand Down Expand Up @@ -65,6 +66,7 @@ pub enum Error {
InvalidParentCount,
InvalidPayloadKind(u32),
InvalidPayloadLength { expected: usize, actual: usize },
InvalidPublicKeyCount(<PublicKeyCount as TryFrom<usize>>::Error),
InvalidReferenceIndex(<UnlockIndex as TryFrom<u16>>::Error),
InvalidSignature,
InvalidSignatureKind(u8),
Expand Down Expand Up @@ -214,6 +216,7 @@ impl fmt::Display for Error {
write!(f, "invalid transaction native tokens count: {count}")
}
Self::InvalidUnlockCount(count) => write!(f, "invalid unlock count: {count}"),
Self::InvalidPublicKeyCount(count) => write!(f, "invalid public key count: {count}"),
Self::InvalidUnlockKind(k) => write!(f, "invalid unlock kind: {k}"),
Self::InvalidUnlockReference(index) => {
write!(f, "invalid unlock reference: {index}")
Expand Down
113 changes: 113 additions & 0 deletions sdk/src/types/block/output/feature/block_issuer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2021 IOTA Stiftung
qrayven marked this conversation as resolved.
Show resolved Hide resolved
// SPDX-License-Identifier: Apache-2.0

use packable::{bounded::BoundedU8, prefix::BoxedSlicePrefix};

use crate::types::block::{public_key::PublicKey, slot::SlotIndex, Error};

pub type PublicKeyCount = BoundedU8<0, { u8::MAX }>;

/// This feature defines the public keys with which a signature to burn Mana from
/// the containing account's Block Issuance Credit can be verified.
qrayven marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, packable::Packable)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[packable(unpack_error = Error)]
pub struct BlockIssuerFeature {
/// The slot index at which the Block Issuer Feature expires and can be removed.
expiry_slot: SlotIndex,
/// The number of Block Issuer Keys.
keys_count: u8,
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
/// The Block Issuer Keys.
#[packable(unpack_error_with = |e| e.unwrap_item_err_or_else(|p| Error::InvalidPublicKeyCount(p.into())))]
keys: BoxedSlicePrefix<PublicKey, PublicKeyCount>,
}

impl BlockIssuerFeature {
/// The [`Feature`](crate::types::block::output::Feature) kind of an [`BlockIssuerFeature`].
pub const KIND: u8 = 4;

/// Creates a new [`BlockIssuerFeature`].
#[inline(always)]
pub fn new(expiry_slot: impl Into<SlotIndex>, keys: impl Into<Box<[PublicKey]>>) -> Result<Self, Error> {

Check failure on line 31 in sdk/src/types/block/output/feature/block_issuer.rs

View workflow job for this annotation

GitHub Actions / Check `no_std` compatability

cannot find type `Box` in this scope
let keys: Box<[PublicKey]> = keys.into();

Check failure on line 32 in sdk/src/types/block/output/feature/block_issuer.rs

View workflow job for this annotation

GitHub Actions / Check `no_std` compatability

cannot find type `Box` in this scope

Ok(Self {
expiry_slot: expiry_slot.into(),
keys_count: keys.len() as u8,
keys: keys.try_into().map_err(Error::InvalidPublicKeyCount)?,
})
}

/// Returns the Slot Index at which the Block Issuer Feature expires and can be removed.
pub fn expiry_slot(&self) -> SlotIndex {
self.expiry_slot
}

/// Returns the number of Block Issuer Keys.
pub fn keys_count(&self) -> u8 {
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
self.keys_count
}

/// Returns the Block Issuer Keys.
pub fn keys(&self) -> &[PublicKey] {
&self.keys
}
}

pub(crate) mod dto {
DaughterOfMars marked this conversation as resolved.
Show resolved Hide resolved
use crate::{
types::block::{
public_key::{dto::PublicKeyDto, PublicKey},
Error,
},
utils::serde::string,
};
use packable::bounded::TryIntoBoundedU8Error;
use serde::{Deserialize, Serialize};

use super::BlockIssuerFeature;

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct BlockIssuerFeatureDto {
qrayven marked this conversation as resolved.
Show resolved Hide resolved
qrayven marked this conversation as resolved.
Show resolved Hide resolved
#[serde(rename = "type")]
pub kind: u8,
#[serde(with = "string")]
pub expiry_slot: u64,
pub keys_count: u8,
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
#[serde(skip_serializing_if = "Vec::is_empty", default)]

Check failure on line 77 in sdk/src/types/block/output/feature/block_issuer.rs

View workflow job for this annotation

GitHub Actions / Check `no_std` compatability

failed to resolve: use of undeclared type `Vec`
Thoralf-M marked this conversation as resolved.
Show resolved Hide resolved
pub keys: Vec<PublicKeyDto>,

Check failure on line 78 in sdk/src/types/block/output/feature/block_issuer.rs

View workflow job for this annotation

GitHub Actions / Check `no_std` compatability

cannot find type `Vec` in this scope
}

impl From<&BlockIssuerFeature> for BlockIssuerFeatureDto {
fn from(value: &BlockIssuerFeature) -> Self {
Self {
kind: BlockIssuerFeature::KIND,
expiry_slot: value.expiry_slot.into(),
keys_count: value.keys_count,
keys: value.keys.iter().map(|key| key.into()).collect(),
}
}
}

impl TryFrom<BlockIssuerFeatureDto> for BlockIssuerFeature {
type Error = Error;

fn try_from(value: BlockIssuerFeatureDto) -> Result<Self, Self::Error> {
let keys = value
.keys
.into_iter()
.map(|key| PublicKey::try_from(key))
.collect::<Result<Vec<PublicKey>, Error>>()?;

Check failure on line 100 in sdk/src/types/block/output/feature/block_issuer.rs

View workflow job for this annotation

GitHub Actions / Check `no_std` compatability

cannot find type `Vec` in this scope

if value.keys_count != keys.len() as u8 {
return Err(Error::InvalidPublicKeyCount(TryIntoBoundedU8Error::Invalid(
value.keys_count,
)));
}

Self::new(value.expiry_slot, keys)
}
}

impl_serde_typed_dto!(BlockIssuerFeature, BlockIssuerFeatureDto, "block issuer feature");
}
32 changes: 31 additions & 1 deletion sdk/src/types/block/output/feature/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2021-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

pub mod block_issuer;
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
mod issuer;
mod metadata;
mod sender;
Expand All @@ -14,6 +15,7 @@ use derive_more::{Deref, From};
use iterator_sorted::is_unique_sorted;
use packable::{bounded::BoundedU8, prefix::BoxedSlicePrefix, Packable};

use self::block_issuer::BlockIssuerFeature;
pub use self::{
issuer::IssuerFeature, metadata::MetadataFeature, sender::SenderFeature, staking::StakingFeature, tag::TagFeature,
};
Expand Down Expand Up @@ -41,6 +43,9 @@ pub enum Feature {
/// A staking feature.
#[packable(tag = StakingFeature::KIND)]
Staking(StakingFeature),
/// A block issuer feature.
#[packable(tag = BlockIssuerFeature::KIND)]
BlockIssuer(BlockIssuerFeature),
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
}

impl PartialOrd for Feature {
Expand All @@ -63,6 +68,7 @@ impl core::fmt::Debug for Feature {
Self::Metadata(feature) => feature.fmt(f),
Self::Tag(feature) => feature.fmt(f),
Self::Staking(feature) => feature.fmt(f),
Self::BlockIssuer(feature) => feature.fmt(f),
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand All @@ -76,6 +82,7 @@ impl Feature {
Self::Metadata(_) => MetadataFeature::KIND,
Self::Tag(_) => TagFeature::KIND,
Self::Staking(_) => StakingFeature::KIND,
Self::BlockIssuer(_) => BlockIssuerFeature::KIND,
}
}

Expand All @@ -87,6 +94,7 @@ impl Feature {
Self::Metadata(_) => FeatureFlags::METADATA,
Self::Tag(_) => FeatureFlags::TAG,
Self::Staking(_) => FeatureFlags::STAKING,
Self::BlockIssuer(_) => FeatureFlags::BLOCK_ISSUER,
}
}

Expand Down Expand Up @@ -164,6 +172,21 @@ impl Feature {
panic!("invalid downcast of non-StakingFeature");
}
}

/// 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");
}
}
}

create_bitflags!(
Expand All @@ -176,6 +199,7 @@ create_bitflags!(
(METADATA, MetadataFeature),
(TAG, TagFeature),
(STAKING, StakingFeature),
(BLOCK_ISSUER, BlockIssuerFeature),
]
);

Expand Down Expand Up @@ -274,6 +298,11 @@ impl Features {
pub fn staking(&self) -> Option<&StakingFeature> {
self.get(StakingFeature::KIND).map(Feature::as_staking)
}

/// Gets a reference to a [`BlockIssuerFeature`], if any.
pub fn block_issuer(&self) -> Option<&BlockIssuerFeature> {
self.get(BlockIssuerFeature::KIND).map(Feature::as_block_issuer)
}
}

#[inline]
Expand Down Expand Up @@ -311,7 +340,8 @@ mod test {
FeatureFlags::ISSUER,
FeatureFlags::METADATA,
FeatureFlags::TAG,
FeatureFlags::STAKING
FeatureFlags::STAKING,
FeatureFlags::BLOCK_ISSUER
]
);
}
Expand Down
1 change: 1 addition & 0 deletions sdk/src/types/block/public_key/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub use self::ed25519::Ed25519PublicKey;
use crate::types::block::Error;

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From, packable::Packable)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
DaughterOfMars marked this conversation as resolved.
Show resolved Hide resolved
#[packable(unpack_error = Error)]
#[packable(tag_type = u8, with_error = Error::InvalidPublicKeyKind)]
pub enum PublicKey {
Expand Down
2 changes: 2 additions & 0 deletions sdk/src/types/block/rand/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub mod output;
pub mod parents;
/// Module providing random payload generation utilities.
pub mod payload;
/// Module providing random public key generation utilities.
pub mod public_key;
/// Module providing random signature generation utilities.
pub mod signature;
/// Module providing random slot generation utilities.
Expand Down
10 changes: 9 additions & 1 deletion sdk/src/types/block/rand/output/feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ use alloc::vec::Vec;

use crate::types::block::{
output::feature::{
Feature, FeatureFlags, IssuerFeature, MetadataFeature, SenderFeature, StakingFeature, TagFeature,
block_issuer::BlockIssuerFeature, Feature, FeatureFlags, IssuerFeature, MetadataFeature, SenderFeature,
StakingFeature, TagFeature,
},
rand::{
address::rand_address,
bytes::rand_bytes,
number::{rand_number, rand_number_range},
public_key::rand_public_key,
},
};

Expand Down Expand Up @@ -41,13 +43,19 @@ pub fn rand_staking_feature() -> StakingFeature {
StakingFeature::new(rand_number(), rand_number(), rand_number(), rand_number())
}

/// Generates a random [`BlockIssuerFeature`].
pub fn rand_block_issuer_feature() -> BlockIssuerFeature {
BlockIssuerFeature::new(rand_number::<u64>(), vec![rand_public_key()]).unwrap()
}

fn rand_feature_from_flag(flag: &FeatureFlags) -> Feature {
match *flag {
FeatureFlags::SENDER => Feature::Sender(rand_sender_feature()),
FeatureFlags::ISSUER => Feature::Issuer(rand_issuer_feature()),
FeatureFlags::METADATA => Feature::Metadata(rand_metadata_feature()),
FeatureFlags::TAG => Feature::Tag(rand_tag_feature()),
FeatureFlags::STAKING => Feature::Staking(rand_staking_feature()),
FeatureFlags::BLOCK_ISSUER => Feature::BlockIssuer(rand_block_issuer_feature()),
_ => unreachable!(),
}
}
Expand Down
15 changes: 15 additions & 0 deletions sdk/src/types/block/rand/public_key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2020-2021 IOTA Stiftung
qrayven marked this conversation as resolved.
Show resolved Hide resolved
// SPDX-License-Identifier: Apache-2.0

use crate::types::block::public_key::{Ed25519PublicKey, PublicKey};

/// Generates a valid random Ed25519 public key.
pub fn rand_ed25519_public_key() -> Ed25519PublicKey {
let key = crypto::signatures::ed25519::SecretKey::generate().unwrap();
key.public_key().into()
}

/// Generates a valid random public key.
pub fn rand_public_key() -> PublicKey {
rand_ed25519_public_key().into()
}
8 changes: 7 additions & 1 deletion sdk/src/types/block/slot/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use derive_more::{Deref, Display, From};
/// Timeline is divided into slots, and each slot has a corresponding slot index.
/// To calculate the slot index of a timestamp, `genesisTimestamp` and the duration of a slot are needed.
/// The slot index of timestamp `ts` is `(ts - genesisTimestamp)/duration + 1`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, From, Deref, Display, packable::Packable)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, From, Deref, Display, PartialOrd, Ord, packable::Packable)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Thoralf-M marked this conversation as resolved.
Show resolved Hide resolved
DaughterOfMars marked this conversation as resolved.
Show resolved Hide resolved
pub struct SlotIndex(u64);

Expand All @@ -16,3 +16,9 @@ impl SlotIndex {
Self::from(index)
}
}

impl From<SlotIndex> for u64 {
fn from(slot_index: SlotIndex) -> Self {
*slot_index
}
}
Loading