Skip to content

Commit

Permalink
Add StakingFeature (#710)
Browse files Browse the repository at this point in the history
* Add StakingFeature

* Update sdk/src/types/block/output/feature/staking.rs

Co-authored-by: Thoralf-M <[email protected]>

* Fix tests

* Nits

* Nits

* Fmt

* License nit

* Remove unused itertools

---------

Co-authored-by: Thoralf-M <[email protected]>
  • Loading branch information
thibault-martinez and Thoralf-M authored Jul 17, 2023
1 parent 0fc813c commit a1a4396
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 76 deletions.
16 changes: 0 additions & 16 deletions Cargo.lock

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

22 changes: 2 additions & 20 deletions bindings/nodejs/examples/client/10-mqtt.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
// Copyright 2021-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import {
Block,
Client,
initLogger,
MilestonePayload,
parsePayload,
} from '@iota/sdk';
import { Block, Client, initLogger } from '@iota/sdk';
import { plainToInstance } from 'class-transformer';

require('dotenv').config({ path: '.env' });
Expand Down Expand Up @@ -38,19 +32,7 @@ async function run() {
}

const parsed = JSON.parse(data);
if (parsed.topic == 'milestone') {
const payload = parsePayload(
JSON.parse(parsed.payload),
) as MilestonePayload;
const index = payload.index;
const previousMilestone = payload.previousMilestoneId;
console.log(
'New milestone index' +
index +
', previous ID: ' +
previousMilestone,
);
} else if (parsed.topic == 'blocks') {
if (parsed.topic == 'blocks') {
const block = plainToInstance(Block, JSON.parse(parsed.payload));
console.log('payload:', block.payload);
}
Expand Down
6 changes: 3 additions & 3 deletions bindings/nodejs/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3702,9 +3702,9 @@ safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==

"[email protected] || 3.x || 4 || 5", [email protected], semver@^4.3.3, semver@^5.0.3, semver@^5.7.1, semver@^6.0.0, semver@^6.3.0, semver@^7.3.5, semver@^7.3.7, semver@^7.5.2, semver@~5.3.0:
version "7.5.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"

Expand Down
1 change: 0 additions & 1 deletion bindings/python/iota_sdk/client/_node_core_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from iota_sdk.types.node_info import NodeInfo, NodeInfoWrapper
from iota_sdk.types.output import OutputWithMetadata, OutputMetadata
from iota_sdk.types.output_id import OutputId
from iota_sdk.types.payload import MilestonePayload
from typing import List
from dacite import from_dict

Expand Down
26 changes: 0 additions & 26 deletions bindings/python/iota_sdk/types/payload.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,32 +42,6 @@ def as_dict(self):

return config


@dataclass
class MilestonePayload(Payload):
"""Initialize a MilestonePayload
"""
index: int
timestamp: int
protocolVersion: int
previousMilestoneId: HexStr
parents: List[HexStr]
inclusionMerkleRoot: HexStr
appliedMerkleRoot: HexStr
signatures: List[Ed25519Signature]
options: Optional[List[Any]] = None
metadata: Optional[HexStr] = None

@classmethod
def from_dict(cls, milestone) -> MilestonePayload:
obj = cls.__new__(cls)
super(MilestonePayload, obj).__init__(milestone["type"])
del milestone["type"]
for k, v in milestone.items():
setattr(obj, k, v)
return obj


class TaggedDataPayload(Payload):
def __init__(self, tag: HexStr, data: HexStr):
"""Initialize a TaggedDataPayload
Expand Down
3 changes: 1 addition & 2 deletions sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ hashbrown = { version = "0.14.0", default-features = false, features = [ "ahash"
hex = { version = "0.4.3", default-features = false }
iota-crypto = { version = "0.22.2", default-features = false, features = [ "blake2b", "ed25519", "secp256k1", "ternary_encoding" ] }
iterator-sorted = { version = "0.1.0", default-features = false }
itertools = { version = "0.11.0", default-features = false, features = [ "use_alloc" ] }
packable = { version = "0.8.1", default-features = false, features = [ "primitive-types" ] }
prefix-hex = { version = "0.7.0", default-features = false, features = [ "primitive-types" ] }
primitive-types = { version = "0.12.1", default-features = false }
Expand Down Expand Up @@ -86,7 +85,7 @@ pow = [ "std", "num_cpus", "iota-crypto/curl-p" ]
rand = [ "dep:rand" ]
rocksdb = [ "dep:rocksdb", "storage" ]
serde = [ "serde_repr", "hashbrown/serde", "packable/serde", "primitive-types/serde_no_std", "zeroize?/serde" ]
std = [ "packable/std", "prefix-hex/std", "primitive-types/std", "bech32/std", "bitflags/std", "rand?/std_rng", "regex?/std", "derive_builder?/std", "iota_stronghold?/std", "iota-crypto/std", "once_cell?/std", "itertools/use_std" ]
std = [ "packable/std", "prefix-hex/std", "primitive-types/std", "bech32/std", "bitflags/std", "rand?/std_rng", "regex?/std", "derive_builder?/std", "iota_stronghold?/std", "iota-crypto/std", "once_cell?/std" ]
storage = [ "iota-crypto/chacha", "dep:time", "dep:anymap", "dep:once_cell", "dep:heck" ]
stronghold = [ "iota_stronghold", "derive_builder", "iota-crypto/chacha", "dep:time", "dep:anymap", "dep:once_cell", "dep:heck" ]
tls = [ "reqwest?/rustls-tls", "rumqttc?/use-rustls" ]
Expand Down
65 changes: 61 additions & 4 deletions sdk/src/types/block/output/feature/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
mod issuer;
mod metadata;
mod sender;
mod staking;
mod tag;

use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};
Expand All @@ -13,7 +14,9 @@ use derive_more::{Deref, From};
use iterator_sorted::is_unique_sorted;
use packable::{bounded::BoundedU8, prefix::BoxedSlicePrefix, Packable};

pub use self::{issuer::IssuerFeature, metadata::MetadataFeature, sender::SenderFeature, tag::TagFeature};
pub use self::{
issuer::IssuerFeature, metadata::MetadataFeature, sender::SenderFeature, staking::StakingFeature, tag::TagFeature,
};
pub(crate) use self::{metadata::MetadataFeatureLength, tag::TagFeatureLength};
use crate::types::block::{create_bitflags, Error};

Expand All @@ -39,13 +42,17 @@ pub enum Feature {
/// A tag feature.
#[packable(tag = TagFeature::KIND)]
Tag(TagFeature),
/// A staking feature.
#[packable(tag = StakingFeature::KIND)]
Staking(StakingFeature),
}

impl PartialOrd for Feature {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.kind().partial_cmp(&other.kind())
}
}

impl Ord for Feature {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.partial_cmp(other).unwrap()
Expand All @@ -59,6 +66,7 @@ impl core::fmt::Debug for Feature {
Self::Issuer(feature) => feature.fmt(f),
Self::Metadata(feature) => feature.fmt(f),
Self::Tag(feature) => feature.fmt(f),
Self::Staking(feature) => feature.fmt(f),
}
}
}
Expand All @@ -71,6 +79,7 @@ impl Feature {
Self::Issuer(_) => IssuerFeature::KIND,
Self::Metadata(_) => MetadataFeature::KIND,
Self::Tag(_) => TagFeature::KIND,
Self::Staking(_) => StakingFeature::KIND,
}
}

Expand All @@ -81,6 +90,7 @@ impl Feature {
Self::Issuer(_) => FeatureFlags::ISSUER,
Self::Metadata(_) => FeatureFlags::METADATA,
Self::Tag(_) => FeatureFlags::TAG,
Self::Staking(_) => FeatureFlags::STAKING,
}
}

Expand Down Expand Up @@ -143,6 +153,21 @@ impl Feature {
panic!("invalid downcast of non-TagFeature");
}
}

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

create_bitflags!(
Expand All @@ -154,6 +179,7 @@ create_bitflags!(
(ISSUER, IssuerFeature),
(METADATA, MetadataFeature),
(TAG, TagFeature),
(STAKING, StakingFeature),
]
);

Expand Down Expand Up @@ -194,7 +220,7 @@ impl IntoIterator for Features {

impl Features {
///
pub const COUNT_MAX: u8 = 4;
pub const COUNT_MAX: u8 = 5;

/// Creates a new [`Features`] from a vec.
pub fn from_vec(features: Vec<Feature>) -> Result<Self, Error> {
Expand Down Expand Up @@ -248,6 +274,11 @@ impl Features {
pub fn tag(&self) -> Option<&TagFeature> {
self.get(TagFeature::KIND).map(Feature::as_tag)
}

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

#[inline]
Expand Down Expand Up @@ -284,7 +315,8 @@ mod test {
FeatureFlags::SENDER,
FeatureFlags::ISSUER,
FeatureFlags::METADATA,
FeatureFlags::TAG
FeatureFlags::TAG,
FeatureFlags::STAKING
]
);
}
Expand All @@ -299,7 +331,7 @@ pub mod dto {

pub use self::{
issuer::dto::IssuerFeatureDto, metadata::dto::MetadataFeatureDto, sender::dto::SenderFeatureDto,
tag::dto::TagFeatureDto,
staking::dto::StakingFeatureDto, tag::dto::TagFeatureDto,
};
use super::*;
use crate::types::block::{address::Address, Error};
Expand All @@ -314,6 +346,8 @@ pub mod dto {
Metadata(MetadataFeatureDto),
/// A tag feature.
Tag(TagFeatureDto),
/// A staking feature.
Staking(StakingFeatureDto),
}

impl<'de> Deserialize<'de> for FeatureDto {
Expand Down Expand Up @@ -342,6 +376,11 @@ pub mod dto {
TagFeatureDto::deserialize(value)
.map_err(|e| serde::de::Error::custom(format!("cannot deserialize tag feature: {e}")))?,
),
StakingFeature::KIND => {
Self::Staking(StakingFeatureDto::deserialize(value).map_err(|e| {
serde::de::Error::custom(format!("cannot deserialize staking feature: {e}"))
})?)
}
_ => return Err(serde::de::Error::custom("invalid feature type")),
},
)
Expand All @@ -360,6 +399,7 @@ pub mod dto {
T2(&'a IssuerFeatureDto),
T3(&'a MetadataFeatureDto),
T4(&'a TagFeatureDto),
T6(&'a StakingFeatureDto),
}
#[derive(Serialize)]
struct TypedFeature<'a> {
Expand All @@ -379,6 +419,9 @@ pub mod dto {
Self::Tag(o) => TypedFeature {
feature: FeatureDto_::T4(o),
},
Self::Staking(o) => TypedFeature {
feature: FeatureDto_::T6(o),
},
};
feature.serialize(serializer)
}
Expand All @@ -403,6 +446,13 @@ pub mod dto {
kind: TagFeature::KIND,
tag: v.to_string(),
}),
Feature::Staking(v) => Self::Staking(StakingFeatureDto {
kind: TagFeature::KIND,
staked_amount: v.staked_amount(),
fixed_cost: v.fixed_cost(),
start_epoch: v.start_epoch(),
end_epoch: v.end_epoch(),
}),
}
}
}
Expand All @@ -420,6 +470,12 @@ pub mod dto {
FeatureDto::Tag(v) => Self::Tag(TagFeature::new(
prefix_hex::decode::<Vec<u8>>(&v.tag).map_err(|_e| Error::InvalidField("TagFeature"))?,
)?),
FeatureDto::Staking(v) => Self::Staking(StakingFeature::new(
v.staked_amount,
v.fixed_cost,
v.start_epoch,
v.end_epoch,
)),
})
}
}
Expand All @@ -432,6 +488,7 @@ pub mod dto {
Self::Issuer(_) => IssuerFeature::KIND,
Self::Metadata(_) => MetadataFeature::KIND,
Self::Tag(_) => TagFeature::KIND,
Self::Staking(_) => StakingFeature::KIND,
}
}
}
Expand Down
Loading

0 comments on commit a1a4396

Please sign in to comment.