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

Use packable BTreeSet impls #1240

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1b3f128
Use BTreeSets where possible
Sep 15, 2023
038ee6d
fixes
Sep 15, 2023
9e466fd
Merge branch '2.0' into feat/btree-sets
Sep 15, 2023
5245219
Merge branch '2.0' into feat/btree-sets
Sep 18, 2023
7d69aaa
update packable
Sep 18, 2023
b22807f
Merge branch '2.0' into feat/btree-sets
Sep 18, 2023
c696600
Merge branch '2.0' into feat/btree-sets
Sep 19, 2023
75f6e67
error message
Sep 19, 2023
b93195f
Merge branch '2.0' into feat/btree-sets
Sep 19, 2023
7fe7339
Merge branch '2.0' into feat/btree-sets
Sep 20, 2023
2dede26
Merge branch '2.0' into feat/btree-sets
thibault-martinez Sep 20, 2023
edfb9e7
Merge branch '2.0' into feat/btree-sets
Sep 27, 2023
22016ab
Merge branch '2.0' into feat/btree-sets
Sep 27, 2023
18b3c20
Merge branch '2.0' into feat/btree-sets
thibault-martinez Sep 29, 2023
465a766
Merge branch '2.0' into feat/btree-sets
Sep 29, 2023
272d52e
clippy
Sep 29, 2023
b746395
comment
Sep 29, 2023
cd957b2
custom hash impls
Sep 29, 2023
bf618b6
error on dups
Sep 29, 2023
ce2087b
Merge branch '2.0' into feat/btree-sets
Oct 3, 2023
416bf62
Merge branch '2.0' into feat/btree-sets
Oct 4, 2023
edbb25e
Merge branch '2.0' into feat/btree-sets
Oct 5, 2023
f54ef47
fail on unordered too and fix tests
Oct 5, 2023
a7efcb9
Merge branch '2.0' into feat/btree-sets
Oct 6, 2023
646a59f
Merge branch '2.0' into feat/btree-sets
Oct 10, 2023
de0b01a
Merge branch '2.0' into feat/btree-sets
Oct 10, 2023
25be1a1
Merge branch '2.0' into feat/btree-sets
Oct 10, 2023
2bfaaa5
Merge branch '2.0' into feat/btree-sets
Oct 11, 2023
a3d4aa8
Merge branch '2.0' into feat/btree-sets
Oct 11, 2023
531f06d
Merge branch '2.0' into feat/btree-sets
Oct 13, 2023
e0d0c4f
Merge branch '2.0' into feat/btree-sets
Oct 13, 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
1 change: 0 additions & 1 deletion Cargo.lock

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

32 changes: 17 additions & 15 deletions bindings/core/src/method/client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use std::collections::BTreeSet;

use derivative::Derivative;
#[cfg(feature = "mqtt")]
use iota_sdk::client::mqtt::Topic;
Expand Down Expand Up @@ -36,14 +38,14 @@ pub enum ClientMethod {
// TODO: Determine if `default` is wanted here
#[serde(default, with = "string")]
mana: u64,
native_tokens: Option<Vec<NativeToken>>,
native_tokens: Option<BTreeSet<NativeToken>>,
account_id: AccountId,
state_index: Option<u32>,
state_metadata: Option<String>,
foundry_counter: Option<u32>,
unlock_conditions: Vec<UnlockConditionDto>,
features: Option<Vec<Feature>>,
immutable_features: Option<Vec<Feature>>,
unlock_conditions: BTreeSet<UnlockConditionDto>,
features: Option<BTreeSet<Feature>>,
immutable_features: Option<BTreeSet<Feature>>,
},
/// Build a BasicOutput.
/// Expected response: [`Output`](crate::Response::Output)
Expand All @@ -56,9 +58,9 @@ pub enum ClientMethod {
// TODO: Determine if `default` is wanted here
#[serde(default, with = "string")]
mana: u64,
native_tokens: Option<Vec<NativeToken>>,
unlock_conditions: Vec<UnlockConditionDto>,
features: Option<Vec<Feature>>,
native_tokens: Option<BTreeSet<NativeToken>>,
unlock_conditions: BTreeSet<UnlockConditionDto>,
features: Option<BTreeSet<Feature>>,
},
/// Build a FoundryOutput.
/// Expected response: [`Output`](crate::Response::Output)
Expand All @@ -68,12 +70,12 @@ pub enum ClientMethod {
// If not provided, minimum storage deposit will be used
#[serde(default, with = "option_string")]
amount: Option<u64>,
native_tokens: Option<Vec<NativeToken>>,
native_tokens: Option<BTreeSet<NativeToken>>,
serial_number: u32,
token_scheme: TokenScheme,
unlock_conditions: Vec<UnlockConditionDto>,
features: Option<Vec<Feature>>,
immutable_features: Option<Vec<Feature>>,
unlock_conditions: BTreeSet<UnlockConditionDto>,
features: Option<BTreeSet<Feature>>,
immutable_features: Option<BTreeSet<Feature>>,
},
/// Build an NftOutput.
/// Expected response: [`Output`](crate::Response::Output)
Expand All @@ -86,11 +88,11 @@ pub enum ClientMethod {
// TODO: Determine if `default` is wanted here
#[serde(default, with = "string")]
mana: u64,
native_tokens: Option<Vec<NativeToken>>,
native_tokens: Option<BTreeSet<NativeToken>>,
nft_id: NftId,
unlock_conditions: Vec<UnlockConditionDto>,
features: Option<Vec<Feature>>,
immutable_features: Option<Vec<Feature>>,
unlock_conditions: BTreeSet<UnlockConditionDto>,
features: Option<BTreeSet<Feature>>,
immutable_features: Option<BTreeSet<Feature>>,
},
/// Removes all listeners for the provided topics.
/// Expected response: [`Ok`](crate::Response::Ok)
Expand Down
1 change: 0 additions & 1 deletion sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ iota-crypto = { version = "0.23.0", default-features = false, features = [
"ed25519",
"secp256k1",
] }
iterator-sorted = { version = "0.1.0", default-features = false }
packable = { version = "0.8.3", default-features = false, features = [
"primitive-types",
] }
Expand Down
6 changes: 3 additions & 3 deletions sdk/examples/wallet/17_check_unlock_conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use iota_sdk::{
types::block::{
address::Bech32Address,
output::{unlock_condition::AddressUnlockCondition, BasicOutputBuilder, UnlockCondition},
output::{unlock_condition::AddressUnlockCondition, BasicOutputBuilder},
},
wallet::Result,
Wallet,
Expand Down Expand Up @@ -46,10 +46,10 @@ async fn main() -> Result<()> {
.add_unlock_condition(AddressUnlockCondition::new(*account_addresses[0].as_ref()))
.finish_output(account.client().get_token_supply().await?)?;

let controlled_by_account = if let [UnlockCondition::Address(address_unlock_condition)] = output
let controlled_by_account = if let Ok(address_unlock_condition) = output
.unlock_conditions()
.expect("output needs to have unlock conditions")
.as_ref()
.single_address()
{
// Check that address in the unlock condition belongs to the account
account_addresses
Expand Down
6 changes: 3 additions & 3 deletions sdk/src/types/block/core/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,9 @@ pub(crate) mod dto {
fn from(value: &BasicBlock) -> Self {
Self {
kind: BasicBlock::KIND,
strong_parents: value.strong_parents.to_set(),
weak_parents: value.weak_parents.to_set(),
shallow_like_parents: value.shallow_like_parents.to_set(),
strong_parents: value.strong_parents.as_set().clone(),
weak_parents: value.weak_parents.as_set().clone(),
shallow_like_parents: value.shallow_like_parents.as_set().clone(),
payload: value.payload.as_ref().map(Into::into),
burned_mana: value.burned_mana,
}
Expand Down
76 changes: 39 additions & 37 deletions sdk/src/types/block/core/parent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@

//! The parents module defines the core data type for storing the blocks directly approved by a block.

use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};
use alloc::{collections::BTreeSet, vec::Vec};
use core::ops::RangeInclusive;

use derive_more::Deref;
use iterator_sorted::is_unique_sorted;
use packable::{bounded::BoundedU8, prefix::BoxedSlicePrefix, Packable};
use packable::{
bounded::BoundedU8,
prefix::BTreeSetPrefix,
set::{UnpackOrderedSetError, UnpackSetError},
Packable,
};

use crate::types::block::{BlockId, Error};

Expand All @@ -21,42 +25,43 @@ use crate::types::block::{BlockId, Error};
#[derive(Clone, Debug, Eq, PartialEq, Deref, Packable)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[deref(forward)]
#[packable(unpack_error = Error, with = |_| Error::InvalidParentCount)]
pub struct Parents<const MIN: u8, const MAX: u8>(
#[packable(verify_with = verify_parents)] BoxedSlicePrefix<BlockId, BoundedU8<MIN, MAX>>,
);
#[packable(unpack_error = Error, with = map_parents_set_error)]
pub struct Parents<const MIN: u8, const MAX: u8>(BTreeSetPrefix<BlockId, BoundedU8<MIN, MAX>>);

fn map_parents_set_error<T, P>(error: UnpackOrderedSetError<T, Error, P>) -> Error {
match error {
UnpackOrderedSetError::Set(e) => match e {
UnpackSetError::DuplicateItem(_) => Error::ParentsNotUniqueSorted,
UnpackSetError::Item(e) => e,
UnpackSetError::Prefix(_) => Error::InvalidParentCount,
},
UnpackOrderedSetError::Unordered => Error::ParentsNotUniqueSorted,
}
}

impl<const MIN: u8, const MAX: u8> Parents<MIN, MAX> {
/// The range representing the valid number of parents.
pub const COUNT_RANGE: RangeInclusive<u8> = MIN..=MAX;

/// Creates new [`Parents`] from a vec.
pub fn from_vec(mut inner: Vec<BlockId>) -> Result<Self, Error> {
inner.sort_unstable();
inner.dedup();

pub fn from_vec(inner: Vec<BlockId>) -> Result<Self, Error> {
Ok(Self(
inner
.into_boxed_slice()
.into_iter()
.collect::<BTreeSet<_>>()
.try_into()
.map_err(|_| Error::InvalidParentCount)?,
))
}

/// Creates new [`Parents`] from an ordered set.
pub fn from_set(inner: BTreeSet<BlockId>) -> Result<Self, Error> {
Ok(Self(
inner
.into_iter()
.collect::<Box<[_]>>()
.try_into()
.map_err(|_| Error::InvalidParentCount)?,
))
Ok(Self(inner.try_into().map_err(|_| Error::InvalidParentCount)?))
}

/// Returns the unique, ordered set of parents.
pub fn to_set(&self) -> BTreeSet<BlockId> {
self.0.iter().copied().collect()
/// Gets the underlying set.
pub fn as_set(&self) -> &BTreeSet<BlockId> {
&self.0
}

/// Returns the number of parents.
Expand All @@ -75,29 +80,26 @@ impl<const MIN: u8, const MAX: u8> Parents<MIN, MAX> {
}
}

fn verify_parents<const VERIFY: bool>(parents: &[BlockId], _: &()) -> Result<(), Error> {
if VERIFY && !is_unique_sorted(parents.iter().map(AsRef::as_ref)) {
Err(Error::ParentsNotUniqueSorted)
} else {
Ok(())
}
}

impl<const MAX: u8> Default for Parents<0, MAX> {
fn default() -> Self {
Self(Default::default())
}
}

impl<const MIN: u8, const MAX: u8> IntoIterator for Parents<MIN, MAX> {
type Item = BlockId;
type IntoIter = alloc::collections::btree_set::IntoIter<Self::Item>;

fn into_iter(self) -> Self::IntoIter {
BTreeSet::from(self.0).into_iter()
}
}

pub(crate) fn verify_parents_sets(
strong_parents: &[BlockId],
weak_parents: &[BlockId],
shallow_like_parents: &[BlockId],
strong_parents: &BTreeSet<BlockId>,
weak_parents: &BTreeSet<BlockId>,
shallow_like_parents: &BTreeSet<BlockId>,
) -> Result<(), Error> {
let strong_parents: BTreeSet<_> = strong_parents.iter().copied().collect();
let weak_parents: BTreeSet<_> = weak_parents.iter().copied().collect();
let shallow_like_parents: BTreeSet<_> = shallow_like_parents.iter().copied().collect();

if !weak_parents.is_disjoint(&strong_parents) || !weak_parents.is_disjoint(&shallow_like_parents) {
return Err(Error::NonDisjointParents);
}
Expand Down
6 changes: 3 additions & 3 deletions sdk/src/types/block/core/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,9 @@ pub(crate) mod dto {
fn from(value: &ValidationBlock) -> Self {
Self {
kind: ValidationBlock::KIND,
strong_parents: value.strong_parents.to_set(),
weak_parents: value.weak_parents.to_set(),
shallow_like_parents: value.shallow_like_parents.to_set(),
strong_parents: value.strong_parents.as_set().clone(),
weak_parents: value.weak_parents.as_set().clone(),
shallow_like_parents: value.shallow_like_parents.as_set().clone(),
highest_supported_version: value.highest_supported_version,
protocol_parameters_hash: value.protocol_parameters_hash,
}
Expand Down
8 changes: 5 additions & 3 deletions sdk/src/types/block/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,11 @@ pub enum Error {
index: usize,
kind: u8,
},
UnallowedUnlockCondition {
DisallowedUnlockCondition {
index: usize,
kind: u8,
},
TooManyUnlockConditions,
UnlockConditionsNotUniqueSorted,
UnsupportedOutputKind(u8),
DuplicateOutputChain(ChainId),
Expand Down Expand Up @@ -365,9 +366,10 @@ impl fmt::Display for Error {
Self::UnallowedFeature { index, kind } => {
write!(f, "unallowed feature at index {index} with kind {kind}")
}
Self::UnallowedUnlockCondition { index, kind } => {
write!(f, "unallowed unlock condition at index {index} with kind {kind}")
Self::DisallowedUnlockCondition { index, kind } => {
write!(f, "disallowed unlock condition at index {index} with kind {kind}")
}
Self::TooManyUnlockConditions => write!(f, "too many unlock conditions"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we want max/current added?

Self::UnlockConditionsNotUniqueSorted => write!(f, "unlock conditions are not unique and/or sorted"),
Self::UnsupportedOutputKind(k) => write!(f, "unsupported output kind: {k}"),
Self::DuplicateOutputChain(chain_id) => write!(f, "duplicate output chain {chain_id}"),
Expand Down
6 changes: 6 additions & 0 deletions sdk/src/types/block/mana/allotment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ impl Ord for ManaAllotment {
}
}

impl core::borrow::Borrow<AccountId> for ManaAllotment {
fn borrow(&self) -> &AccountId {
&self.account_id
}
}

impl ManaAllotment {
pub fn new(account_id: AccountId, mana: u64, protocol_params: &ProtocolParameters) -> Result<Self, Error> {
if mana > protocol_params.mana_structure().max_mana() {
Expand Down
Loading
Loading