From 61a0e831472f5b9715d06375dec1d0116bacb17c Mon Sep 17 00:00:00 2001 From: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> Date: Fri, 29 Sep 2023 10:18:07 +0200 Subject: [PATCH 1/2] Add and use Epoch- and SlotIndex (#1347) * Add and use Epoch- and SlotIndex * Change more fields * Fix * Change more things, that aren't actually an Epoch- or SlotIndex --- bindings/python/iota_sdk/types/common.py | 2 ++ bindings/python/iota_sdk/types/essence.py | 8 ++--- bindings/python/iota_sdk/types/feature.py | 11 +++--- bindings/python/iota_sdk/types/node_info.py | 22 +++++------- sdk/src/types/block/protocol.rs | 37 ++++++++++++--------- 5 files changed, 39 insertions(+), 41 deletions(-) diff --git a/bindings/python/iota_sdk/types/common.py b/bindings/python/iota_sdk/types/common.py index ab2e1e766c..96a5fdcfd4 100644 --- a/bindings/python/iota_sdk/types/common.py +++ b/bindings/python/iota_sdk/types/common.py @@ -7,6 +7,8 @@ from dataclasses_json import DataClassJsonMixin, dataclass_json, LetterCase, Undefined HexStr = NewType("HexStr", str) +EpochIndex = NewType("EpochIndex", int) +SlotIndex = NewType("SlotIndex", int) def json(cls): diff --git a/bindings/python/iota_sdk/types/essence.py b/bindings/python/iota_sdk/types/essence.py index a7f3f3bfc4..530b45713f 100644 --- a/bindings/python/iota_sdk/types/essence.py +++ b/bindings/python/iota_sdk/types/essence.py @@ -7,7 +7,7 @@ from dataclasses import dataclass, field -from iota_sdk.types.common import HexStr, json +from iota_sdk.types.common import HexStr, json, SlotIndex from iota_sdk.types.mana import ManaAllotment # TODO: Add missing output types in #1174 # pylint: disable=no-name-in-module @@ -54,11 +54,11 @@ class RegularTransactionEssence(TransactionEssence): payload: An optional tagged data payload """ network_id: str - # TODO: Replace with a proper SlotIndex type - creation_slot: HexStr + creation_slot: SlotIndex inputs: List[UtxoInput] inputs_commitment: HexStr - outputs: List[Union[BasicOutput, AccountOutput, FoundryOutput, NftOutput, DelegationOutput]] + outputs: List[Union[BasicOutput, AccountOutput, + FoundryOutput, NftOutput, DelegationOutput]] context_inputs: Optional[List[Union[CommitmentContextInput, BlockIssuanceCreditContextInput, RewardContextInput]]] = None allotments: Optional[List[ManaAllotment]] = None diff --git a/bindings/python/iota_sdk/types/feature.py b/bindings/python/iota_sdk/types/feature.py index d9f8e6a3d6..4fc675e145 100644 --- a/bindings/python/iota_sdk/types/feature.py +++ b/bindings/python/iota_sdk/types/feature.py @@ -6,7 +6,7 @@ from dataclasses import dataclass, field from iota_sdk.types.address import Ed25519Address, AccountAddress, NFTAddress -from iota_sdk.types.common import HexStr, json +from iota_sdk.types.common import EpochIndex, HexStr, json, SlotIndex class FeatureType(IntEnum): @@ -97,8 +97,7 @@ class BlockIssuer(Feature): expiry_slot: The slot index at which the Block Issuer Feature expires and can be removed. public_keys: The Block Issuer Keys. """ - # TODO Replace with a proper SlotIndex type - expiry_slot: str + expiry_slot: SlotIndex # TODO Replace with a list of PublicKey types public_keys: List[HexStr] type: int = field( @@ -119,10 +118,8 @@ class StakingFeature(Feature): """ staked_amount: str fixed_cost: str - # TODO Replace with an EpochIndex type - start_epoch: HexStr - # TODO Replace with an EpochIndex type - end_epoch: HexStr + start_epoch: EpochIndex + end_epoch: EpochIndex type: int = field( default_factory=lambda: int( FeatureType.Staking), diff --git a/bindings/python/iota_sdk/types/node_info.py b/bindings/python/iota_sdk/types/node_info.py index 8ad83cc791..24f17afffa 100644 --- a/bindings/python/iota_sdk/types/node_info.py +++ b/bindings/python/iota_sdk/types/node_info.py @@ -4,7 +4,7 @@ from __future__ import annotations from dataclasses import dataclass from typing import List, Optional -from iota_sdk.types.common import HexStr, json +from iota_sdk.types.common import EpochIndex, HexStr, json, SlotIndex @json @@ -22,7 +22,7 @@ class NodeInfoStatus: latest_finalized_slot: The index of the latest finalized slot. latest_accepted_block_slot: The slot index of the latest accepted block. latest_confirmed_block_slot: The slot index of the latest confirmed block. - pruning_epoch: The index of the slot before which the tangle history is pruned. + pruning_epoch: The index of the epoch before which the tangle history is pruned. """ is_healthy: bool accepted_tangle_time: str @@ -30,14 +30,10 @@ class NodeInfoStatus: confirmed_tangle_time: str relative_confirmed_tangle_time: str latest_commitment_id: HexStr - # TODO Replace with a proper SlotIndex type - latest_finalized_slot: str - # TODO Replace with a proper SlotIndex type - latest_accepted_block_slot: str - # TODO Replace with a proper SlotIndex type - latest_confirmed_block_slot: str - # TODO Replace with a proper SlotIndex type - pruning_epoch: str + latest_finalized_slot: SlotIndex + latest_accepted_block_slot: SlotIndex + latest_confirmed_block_slot: SlotIndex + pruning_epoch: EpochIndex @json @@ -217,11 +213,9 @@ class ProtocolParameters: staking_unbonding_period: str validation_blocks_per_slot: int punishment_epochs: str - staking_unbonding_period: str liveness_threshold: str min_committable_age: str max_committable_age: str - # TODO Replace with a proper SlotIndex type epoch_nearing_threshold: str congestion_control_parameters: CongestionControlParameters version_signaling: VersionSignaling @@ -236,7 +230,7 @@ class ProtocolParametersResponse: start_epoch: The start epoch of the set of protocol parameters. parameters: The protocol parameters. """ - start_epoch: str + start_epoch: EpochIndex parameters: ProtocolParameters @@ -255,9 +249,9 @@ class NodeInfoBaseToken: name: str ticker_symbol: str unit: str - subunit: Optional[str] = None decimals: int use_metric_prefix: bool + subunit: Optional[str] = None @json diff --git a/sdk/src/types/block/protocol.rs b/sdk/src/types/block/protocol.rs index 32d882a839..418e2afbbe 100644 --- a/sdk/src/types/block/protocol.rs +++ b/sdk/src/types/block/protocol.rs @@ -11,7 +11,7 @@ use packable::{prefix::StringPrefix, Packable, PackableExt}; use super::{ address::Hrp, mana::{ManaStructure, RewardsParameters}, - slot::{EpochIndex, SlotIndex}, + slot::SlotIndex, }; use crate::types::block::{helper::network_name_to_id, output::RentStructure, ConvertTo, Error, PROTOCOL_VERSION}; @@ -55,23 +55,28 @@ pub struct ProtocolParameters { #[getset(skip)] pub(crate) mana_structure: ManaStructure, /// The unbonding period in epochs before an account can stop staking. - pub(crate) staking_unbonding_period: EpochIndex, + #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] + pub(crate) staking_unbonding_period: u64, /// The number of validation blocks that each validator should issue each slot. pub(crate) validation_blocks_per_slot: u16, /// The number of epochs worth of Mana that a node is punished with for each additional validation block it issues. #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] pub(crate) punishment_epochs: u64, - /// The slot index used by tip-selection to determine if a block is eligible by evaluating issuing times - /// and commitments in its past-cone against accepted tangle time and last committed slot respectively. - pub(crate) liveness_threshold: SlotIndex, + /// Liveness Threshold is used by tip-selection to determine if a block is eligible by evaluating issuingTimes and + /// commitments in its past-cone to Accepted Tangle Time and lastCommittedSlot respectively. + #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] + pub(crate) liveness_threshold: u64, /// Minimum age relative to the accepted tangle time slot index that a slot can be committed. - pub(crate) min_committable_age: SlotIndex, + #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] + pub(crate) min_committable_age: u64, /// Maximum age for a slot commitment to be included in a block relative to the slot index of the block issuing /// time. - pub(crate) max_committable_age: SlotIndex, - /// The slot index used by the epoch orchestrator to detect the slot that should trigger a new + #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] + pub(crate) max_committable_age: u64, + /// Epoch Nearing Threshold is used by the epoch orchestrator to detect the slot that should trigger a new /// committee selection for the next and upcoming epoch. - pub(crate) epoch_nearing_threshold: SlotIndex, + #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] + pub(crate) epoch_nearing_threshold: u64, /// Parameters used to calculate the Reference Mana Cost (RMC). pub(crate) congestion_control_parameters: CongestionControlParameters, /// Defines the parameters used to signal a protocol parameters upgrade. @@ -100,15 +105,15 @@ impl Default for ProtocolParameters { token_supply: 1_813_620_509_061_365, genesis_unix_timestamp: 1582328545, slot_duration_in_seconds: 10, - epoch_nearing_threshold: 20.into(), + epoch_nearing_threshold: 20, slots_per_epoch_exponent: Default::default(), mana_structure: Default::default(), - staking_unbonding_period: 10.into(), + staking_unbonding_period: 10, validation_blocks_per_slot: 10, punishment_epochs: 9, - liveness_threshold: 5.into(), - min_committable_age: 10.into(), - max_committable_age: 20.into(), + liveness_threshold: 5, + min_committable_age: 10, + max_committable_age: 20, congestion_control_parameters: Default::default(), version_signaling: Default::default(), rewards_parameters: Default::default(), @@ -127,7 +132,7 @@ impl ProtocolParameters { token_supply: u64, genesis_unix_timestamp: u64, slot_duration_in_seconds: u8, - epoch_nearing_threshold: impl Into, + epoch_nearing_threshold: u64, ) -> Result { Ok(Self { version, @@ -137,7 +142,7 @@ impl ProtocolParameters { token_supply, genesis_unix_timestamp, slot_duration_in_seconds, - epoch_nearing_threshold: epoch_nearing_threshold.into(), + epoch_nearing_threshold, ..Default::default() }) } From 6ecd1ccce1074c18e59535282b7c38827fc03fd5 Mon Sep 17 00:00:00 2001 From: DaughterOfMars Date: Fri, 29 Sep 2023 06:40:28 -0400 Subject: [PATCH 2/2] Separate block parent type defs (#1345) * make parents go through an arduous legal separation (BasicBlock got the kids) * use a trait * Revert "use a trait" This reverts commit 3ec3958636e001d2381d3ab145901a750ca3aa6f. * PR suggestions * move validation fn --------- Co-authored-by: Thibault Martinez --- .../client/block/02_block_custom_parents.rs | 2 +- sdk/examples/client/get_block.rs | 2 +- .../client/node_api_core/06_get_block.rs | 2 +- .../client/node_api_core/07_get_block_raw.rs | 2 +- .../node_api_core/08_get_block_metadata.rs | 2 +- sdk/src/client/api/block_builder/mod.rs | 34 +++++++----------- sdk/src/types/api/core/response.rs | 33 ++++++++++++++--- sdk/src/types/block/core/basic.rs | 12 ++++--- sdk/src/types/block/core/mod.rs | 29 ++++----------- sdk/src/types/block/{ => core}/parent.rs | 18 ++++++++-- sdk/src/types/block/core/validation.rs | 12 ++++--- sdk/src/types/block/mod.rs | 2 -- sdk/src/types/block/rand/block.rs | 5 ++- sdk/src/types/block/rand/parents.rs | 6 ++-- sdk/tests/types/parents.rs | 35 ++++++++++--------- 15 files changed, 106 insertions(+), 90 deletions(-) rename sdk/src/types/block/{ => core}/parent.rs (82%) diff --git a/sdk/examples/client/block/02_block_custom_parents.rs b/sdk/examples/client/block/02_block_custom_parents.rs index 59d2e1fcf1..823da8d391 100644 --- a/sdk/examples/client/block/02_block_custom_parents.rs +++ b/sdk/examples/client/block/02_block_custom_parents.rs @@ -30,7 +30,7 @@ async fn main() -> Result<()> { todo!("issuer id"), todo!("block signature"), todo!("issuing time"), - Some(issuance.strong_parents), + Some(issuance.strong_parents()?), None, ) .await?; diff --git a/sdk/examples/client/get_block.rs b/sdk/examples/client/get_block.rs index 91d52ce065..6805bc42a0 100644 --- a/sdk/examples/client/get_block.rs +++ b/sdk/examples/client/get_block.rs @@ -22,7 +22,7 @@ async fn main() -> Result<()> { .await?; // Fetch a block ID from the node. - let block_id = client.get_issuance().await?.strong_parents[0]; + let block_id = client.get_issuance().await?.strong_parents.into_iter().next().unwrap(); // Get the block. let block = client.get_block(&block_id).await?; diff --git a/sdk/examples/client/node_api_core/06_get_block.rs b/sdk/examples/client/node_api_core/06_get_block.rs index f08ac5c8f3..e5462cdfe1 100644 --- a/sdk/examples/client/node_api_core/06_get_block.rs +++ b/sdk/examples/client/node_api_core/06_get_block.rs @@ -28,7 +28,7 @@ async fn main() -> Result<()> { block_id } else { // ... fetch one from the node. - client.get_issuance().await?.strong_parents[0] + client.get_issuance().await?.strong_parents.into_iter().next().unwrap() }; // Get the block. diff --git a/sdk/examples/client/node_api_core/07_get_block_raw.rs b/sdk/examples/client/node_api_core/07_get_block_raw.rs index 30d9972bf8..06cdb557dd 100644 --- a/sdk/examples/client/node_api_core/07_get_block_raw.rs +++ b/sdk/examples/client/node_api_core/07_get_block_raw.rs @@ -28,7 +28,7 @@ async fn main() -> Result<()> { block_id } else { // ... fetch one from the node. - client.get_issuance().await?.strong_parents[0] + client.get_issuance().await?.strong_parents.into_iter().next().unwrap() }; // Get the block as raw bytes. diff --git a/sdk/examples/client/node_api_core/08_get_block_metadata.rs b/sdk/examples/client/node_api_core/08_get_block_metadata.rs index 49c20cd5c0..a337fdb7f3 100644 --- a/sdk/examples/client/node_api_core/08_get_block_metadata.rs +++ b/sdk/examples/client/node_api_core/08_get_block_metadata.rs @@ -28,7 +28,7 @@ async fn main() -> Result<()> { block_id } else { // ... fetch one from the node. - client.get_issuance().await?.strong_parents[0] + client.get_issuance().await?.strong_parents.into_iter().next().unwrap() }; // Send the request. diff --git a/sdk/src/client/api/block_builder/mod.rs b/sdk/src/client/api/block_builder/mod.rs index e315648f3f..9b4dfd91e2 100644 --- a/sdk/src/client/api/block_builder/mod.rs +++ b/sdk/src/client/api/block_builder/mod.rs @@ -7,15 +7,11 @@ pub mod transaction; pub use self::transaction::verify_semantic; use crate::{ client::{ClientInner, Result}, - types::{ - api::core::response::IssuanceBlockHeaderResponse, - block::{ - core::{Block, BlockWrapper}, - parent::StrongParents, - payload::Payload, - signature::Ed25519Signature, - IssuerId, - }, + types::block::{ + core::{basic, Block, BlockWrapper}, + payload::Payload, + signature::Ed25519Signature, + IssuerId, }, }; @@ -25,17 +21,11 @@ impl ClientInner { issuer_id: IssuerId, signature: Ed25519Signature, issuing_time: Option, - strong_parents: Option, + strong_parents: Option, payload: Option, ) -> Result { - let IssuanceBlockHeaderResponse { - strong_parents: default_strong_parents, - weak_parents, - shallow_like_parents, - latest_finalized_slot, - commitment, - } = self.get_issuance().await?; - let strong_parents = strong_parents.unwrap_or(default_strong_parents); + let issuance = self.get_issuance().await?; + let strong_parents = strong_parents.unwrap_or(issuance.strong_parents()?); let issuing_time = issuing_time.unwrap_or_else(|| { #[cfg(feature = "std")] @@ -56,13 +46,13 @@ impl ClientInner { protocol_parameters.version(), protocol_parameters.network_id(), issuing_time, - commitment.id(), - latest_finalized_slot, + issuance.commitment.id(), + issuance.latest_finalized_slot, issuer_id, // TODO correct value for burned_mana Block::build_basic(strong_parents, 0) - .with_weak_parents(weak_parents) - .with_shallow_like_parents(shallow_like_parents) + .with_weak_parents(issuance.weak_parents()?) + .with_shallow_like_parents(issuance.shallow_like_parents()?) .with_payload(payload) .finish_block()?, signature, diff --git a/sdk/src/types/api/core/response.rs b/sdk/src/types/api/core/response.rs index 7998f3f271..b6f073d67a 100644 --- a/sdk/src/types/api/core/response.rs +++ b/sdk/src/types/api/core/response.rs @@ -1,14 +1,19 @@ // Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec}; +use alloc::{ + boxed::Box, + collections::{BTreeMap, BTreeSet}, + string::String, + vec::Vec, +}; use serde::{Deserialize, Serialize}; use crate::{ types::block::{ + core::Parents, output::{dto::OutputDto, AccountId, OutputId, OutputMetadata, OutputWithMetadata}, - parent::{ShallowLikeParents, StrongParents, WeakParents}, protocol::ProtocolParameters, semantic::TransactionFailureReason, slot::{EpochIndex, SlotCommitment, SlotCommitmentId, SlotIndex}, @@ -262,17 +267,35 @@ pub struct ValidatorResponse { #[serde(rename_all = "camelCase")] pub struct IssuanceBlockHeaderResponse { /// Blocks that are strongly directly approved. - pub strong_parents: StrongParents, + pub strong_parents: BTreeSet, /// Blocks that are weakly directly approved. - pub weak_parents: WeakParents, + pub weak_parents: BTreeSet, /// Blocks that are directly referenced to adjust opinion. - pub shallow_like_parents: ShallowLikeParents, + pub shallow_like_parents: BTreeSet, /// The slot index of the latest finalized slot. pub latest_finalized_slot: SlotIndex, /// The most recent slot commitment. pub commitment: SlotCommitment, } +impl IssuanceBlockHeaderResponse { + pub fn strong_parents( + &self, + ) -> Result, crate::types::block::Error> { + Parents::from_set(self.strong_parents.clone()) + } + + pub fn weak_parents(&self) -> Result, crate::types::block::Error> { + Parents::from_set(self.weak_parents.clone()) + } + + pub fn shallow_like_parents( + &self, + ) -> Result, crate::types::block::Error> { + Parents::from_set(self.shallow_like_parents.clone()) + } +} + /// Response of GET /api/core/v3/accounts/{accountId}/congestion. /// Provides the cost and readiness to issue estimates. #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] diff --git a/sdk/src/types/block/core/basic.rs b/sdk/src/types/block/core/basic.rs index 0478cb8d30..1efbe72af2 100644 --- a/sdk/src/types/block/core/basic.rs +++ b/sdk/src/types/block/core/basic.rs @@ -9,13 +9,16 @@ use packable::{ }; use crate::types::block::{ - core::{verify_parents, Block}, - parent::{ShallowLikeParents, StrongParents, WeakParents}, + core::{parent::verify_parents_sets, Block, Parents}, payload::{OptionalPayload, Payload}, protocol::ProtocolParameters, Error, }; +pub type StrongParents = Parents<1, 8>; +pub type WeakParents = Parents<0, 8>; +pub type ShallowLikeParents = Parents<0, 8>; + /// A builder for a [`BasicBlock`]. pub struct BasicBlockBuilder { strong_parents: StrongParents, @@ -75,7 +78,7 @@ impl BasicBlockBuilder { /// Finishes the builder into a [`BasicBlock`]. pub fn finish(self) -> Result { - verify_parents(&self.strong_parents, &self.weak_parents, &self.shallow_like_parents)?; + verify_parents_sets(&self.strong_parents, &self.weak_parents, &self.shallow_like_parents)?; Ok(BasicBlock { strong_parents: self.strong_parents, @@ -164,7 +167,8 @@ impl Packable for BasicBlock { let shallow_like_parents = ShallowLikeParents::unpack::<_, VERIFY>(unpacker, &())?; if VERIFY { - verify_parents(&strong_parents, &weak_parents, &shallow_like_parents).map_err(UnpackError::Packable)?; + verify_parents_sets(&strong_parents, &weak_parents, &shallow_like_parents) + .map_err(UnpackError::Packable)?; } let payload = OptionalPayload::unpack::<_, VERIFY>(unpacker, visitor)?; diff --git a/sdk/src/types/block/core/mod.rs b/sdk/src/types/block/core/mod.rs index ab486fd883..3bb75269f4 100644 --- a/sdk/src/types/block/core/mod.rs +++ b/sdk/src/types/block/core/mod.rs @@ -1,8 +1,9 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -mod basic; -mod validation; +pub mod basic; +mod parent; +pub mod validation; mod wrapper; use alloc::boxed::Box; @@ -18,11 +19,11 @@ use packable::{ pub use self::{ basic::{BasicBlock, BasicBlockBuilder}, + parent::Parents, validation::{ValidationBlock, ValidationBlockBuilder}, wrapper::{BlockHeader, BlockWrapper}, }; use crate::types::block::{ - parent::{ShallowLikeParents, StrongParents, WeakParents}, protocol::{ProtocolParameters, ProtocolParametersHash}, Error, }; @@ -56,14 +57,14 @@ impl Block { /// Creates a new [`BasicBlockBuilder`]. #[inline(always)] - pub fn build_basic(strong_parents: StrongParents, burned_mana: u64) -> BasicBlockBuilder { + pub fn build_basic(strong_parents: self::basic::StrongParents, burned_mana: u64) -> BasicBlockBuilder { BasicBlockBuilder::new(strong_parents, burned_mana) } /// Creates a new [`ValidationBlockBuilder`]. #[inline(always)] pub fn build_validation( - strong_parents: StrongParents, + strong_parents: self::validation::StrongParents, highest_supported_version: u8, protocol_parameters_hash: ProtocolParametersHash, ) -> ValidationBlockBuilder { @@ -136,24 +137,6 @@ impl Packable for Block { } } -pub(crate) fn verify_parents( - strong_parents: &StrongParents, - weak_parents: &WeakParents, - shallow_like_parents: &ShallowLikeParents, -) -> Result<(), Error> { - let (strong_parents, weak_parents, shallow_like_parents) = ( - strong_parents.to_set(), - weak_parents.to_set(), - shallow_like_parents.to_set(), - ); - - if !weak_parents.is_disjoint(&strong_parents) || !weak_parents.is_disjoint(&shallow_like_parents) { - return Err(Error::NonDisjointParents); - } - - Ok(()) -} - #[cfg(feature = "serde")] pub(crate) mod dto { use alloc::format; diff --git a/sdk/src/types/block/parent.rs b/sdk/src/types/block/core/parent.rs similarity index 82% rename from sdk/src/types/block/parent.rs rename to sdk/src/types/block/core/parent.rs index 7c2116f319..80f7cf30d6 100644 --- a/sdk/src/types/block/parent.rs +++ b/sdk/src/types/block/core/parent.rs @@ -89,6 +89,18 @@ impl Default for Parents<0, MAX> { } } -pub type StrongParents = Parents<1, 8>; -pub type WeakParents = Parents<0, 8>; -pub type ShallowLikeParents = Parents<0, 8>; +pub(crate) fn verify_parents_sets( + strong_parents: &[BlockId], + weak_parents: &[BlockId], + shallow_like_parents: &[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); + } + + Ok(()) +} diff --git a/sdk/src/types/block/core/validation.rs b/sdk/src/types/block/core/validation.rs index 5fa03fd65c..4e37a68bab 100644 --- a/sdk/src/types/block/core/validation.rs +++ b/sdk/src/types/block/core/validation.rs @@ -9,12 +9,15 @@ use packable::{ }; use crate::types::block::{ - core::{verify_parents, Block}, - parent::{ShallowLikeParents, StrongParents, WeakParents}, + core::{parent::verify_parents_sets, Block, Parents}, protocol::{ProtocolParameters, ProtocolParametersHash}, Error, }; +pub type StrongParents = Parents<1, 50>; +pub type WeakParents = Parents<0, 50>; +pub type ShallowLikeParents = Parents<0, 50>; + /// A builder for a [`ValidationBlock`]. pub struct ValidationBlockBuilder { strong_parents: StrongParents, @@ -78,7 +81,7 @@ impl ValidationBlockBuilder { /// Finishes the builder into a [`ValidationBlock`]. pub fn finish(self) -> Result { - verify_parents(&self.strong_parents, &self.weak_parents, &self.shallow_like_parents)?; + verify_parents_sets(&self.strong_parents, &self.weak_parents, &self.shallow_like_parents)?; Ok(ValidationBlock { strong_parents: self.strong_parents, @@ -169,7 +172,8 @@ impl Packable for ValidationBlock { let shallow_like_parents = ShallowLikeParents::unpack::<_, VERIFY>(unpacker, &())?; if VERIFY { - verify_parents(&strong_parents, &weak_parents, &shallow_like_parents).map_err(UnpackError::Packable)?; + verify_parents_sets(&strong_parents, &weak_parents, &shallow_like_parents) + .map_err(UnpackError::Packable)?; } let highest_supported_version = u8::unpack::<_, VERIFY>(unpacker, &()).coerce()?; diff --git a/sdk/src/types/block/mod.rs b/sdk/src/types/block/mod.rs index 0fccfd5c75..de471203d6 100644 --- a/sdk/src/types/block/mod.rs +++ b/sdk/src/types/block/mod.rs @@ -24,8 +24,6 @@ pub mod input; pub mod mana; /// A module that provides types and syntactic validations of outputs. pub mod output; -/// A module that provides types and syntactic validations of parents. -pub mod parent; /// A module that provides types and syntactic validations of payloads. pub mod payload; /// A module that provides types and syntactic validations of protocol parameters. diff --git a/sdk/src/types/block/rand/block.rs b/sdk/src/types/block/rand/block.rs index eaeea31346..c1de20b13d 100644 --- a/sdk/src/types/block/rand/block.rs +++ b/sdk/src/types/block/rand/block.rs @@ -4,8 +4,7 @@ use alloc::vec::Vec; use crate::types::block::{ - core::{BasicBlockBuilder, Block, BlockWrapper}, - parent::StrongParents, + core::{basic, BasicBlockBuilder, Block, BlockWrapper}, protocol::ProtocolParameters, rand::{ bytes::rand_bytes_array, @@ -32,7 +31,7 @@ pub fn rand_block_ids(len: usize) -> Vec { } /// Generates a random basic block with given strong parents. -pub fn rand_basic_block_builder_with_strong_parents(strong_parents: StrongParents) -> BasicBlockBuilder { +pub fn rand_basic_block_builder_with_strong_parents(strong_parents: basic::StrongParents) -> BasicBlockBuilder { Block::build_basic(strong_parents, rand_number()).with_payload(rand_payload_for_block()) } diff --git a/sdk/src/types/block/rand/parents.rs b/sdk/src/types/block/rand/parents.rs index 2b9040d396..9aa721d350 100644 --- a/sdk/src/types/block/rand/parents.rs +++ b/sdk/src/types/block/rand/parents.rs @@ -2,11 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 use crate::types::block::{ - parent::StrongParents, + core::Parents, rand::{block::rand_block_ids, number::rand_number_range}, }; /// Generates random strong parents. -pub fn rand_strong_parents() -> StrongParents { - StrongParents::from_vec(rand_block_ids(rand_number_range(StrongParents::COUNT_RANGE).into())).unwrap() +pub fn rand_strong_parents() -> Parents<1, MAX> { + Parents::from_vec(rand_block_ids(rand_number_range(Parents::<1, MAX>::COUNT_RANGE).into())).unwrap() } diff --git a/sdk/tests/types/parents.rs b/sdk/tests/types/parents.rs index e3c746ccbb..f85f16ec61 100644 --- a/sdk/tests/types/parents.rs +++ b/sdk/tests/types/parents.rs @@ -5,7 +5,7 @@ use core::ops::Deref; use std::collections::BTreeSet; use iota_sdk::types::block::{ - parent::StrongParents, + core::basic, rand::block::{rand_block_id, rand_block_ids}, BlockId, Error, }; @@ -14,14 +14,14 @@ use packable::{error::UnpackError, prefix::VecPrefix, PackableExt}; #[test] fn len() { for i in 1..=8 { - assert_eq!(StrongParents::from_vec(rand_block_ids(i)).unwrap().len(), i); + assert_eq!(basic::StrongParents::from_vec(rand_block_ids(i)).unwrap().len(), i); } } #[test] fn new_valid_iter() { let inner = rand_block_ids(8); - let parents = StrongParents::from_vec(inner.clone()).unwrap(); + let parents = basic::StrongParents::from_vec(inner.clone()).unwrap(); let parents_vec = parents.iter().copied().collect::>(); @@ -31,7 +31,7 @@ fn new_valid_iter() { #[test] fn new_from_set() { let inner = rand_block_ids(8); - let parents = StrongParents::from_set(BTreeSet::from_iter(inner.clone())).unwrap(); + let parents = basic::StrongParents::from_set(BTreeSet::from_iter(inner.clone())).unwrap(); assert_eq!(*parents.to_vec(), inner); } @@ -39,7 +39,7 @@ fn new_from_set() { #[test] fn new_valid_deref() { let inner = rand_block_ids(8); - let parents = StrongParents::from_vec(inner.clone()).unwrap(); + let parents = basic::StrongParents::from_vec(inner.clone()).unwrap(); assert_eq!(parents.deref(), &inner.into_boxed_slice()); } @@ -49,7 +49,7 @@ fn new_invalid_more_than_max() { let mut inner = vec![rand_block_id()]; for _ in 0..8 { - StrongParents::from_vec(inner.clone()).unwrap(); + basic::StrongParents::from_vec(inner.clone()).unwrap(); inner.push(rand_block_id()); inner.sort(); } @@ -59,7 +59,10 @@ fn new_invalid_more_than_max() { // Parents::from_vec(inner), // Err(Error::InvalidParentCount(TryIntoBoundedU8Error::Invalid(9))) // )); - assert!(matches!(StrongParents::from_vec(inner), Err(Error::InvalidParentCount))); + assert!(matches!( + basic::StrongParents::from_vec(inner), + Err(Error::InvalidParentCount) + )); } #[test] @@ -68,7 +71,7 @@ fn new_not_sorted() { let inner_2 = inner_1.clone(); inner_1.reverse(); - let parents = StrongParents::from_vec(inner_1).unwrap(); + let parents = basic::StrongParents::from_vec(inner_1).unwrap(); assert_eq!(*parents.to_vec(), inner_2); } @@ -79,14 +82,14 @@ fn new_not_unique() { let inner_2 = inner_1.clone(); inner_1.push(*inner_1.last().unwrap()); - let parents = StrongParents::from_vec(inner_1).unwrap(); + let parents = basic::StrongParents::from_vec(inner_1).unwrap(); assert_eq!(*parents.to_vec(), inner_2); } #[test] fn packed_len() { - let parents = StrongParents::from_vec(rand_block_ids(5)).unwrap(); + let parents = basic::StrongParents::from_vec(rand_block_ids(5)).unwrap(); assert_eq!(parents.packed_len(), 1 + 5 * 40); assert_eq!(parents.pack_to_vec().len(), 1 + 5 * 40); @@ -94,8 +97,8 @@ fn packed_len() { #[test] fn pack_unpack_valid() { - let parents_1 = StrongParents::from_vec(rand_block_ids(8)).unwrap(); - let parents_2 = StrongParents::unpack_verified(parents_1.pack_to_vec().as_slice(), &()).unwrap(); + let parents_1 = basic::StrongParents::from_vec(rand_block_ids(8)).unwrap(); + let parents_2 = basic::StrongParents::unpack_verified(parents_1.pack_to_vec().as_slice(), &()).unwrap(); assert_eq!(parents_1, parents_2); } @@ -116,7 +119,7 @@ fn pack_unpack_invalid_less_than_min() { // ))) // )); assert!(matches!( - StrongParents::unpack_verified(bytes.as_slice(), &()), + basic::StrongParents::unpack_verified(bytes.as_slice(), &()), Err(UnpackError::Packable(Error::InvalidParentCount)) )); } @@ -137,7 +140,7 @@ fn pack_unpack_invalid_more_than_max() { // ))) // )); assert!(matches!( - StrongParents::unpack_verified(bytes.as_slice(), &()), + basic::StrongParents::unpack_verified(bytes.as_slice(), &()), Err(UnpackError::Packable(Error::InvalidParentCount)) )); } @@ -149,7 +152,7 @@ fn unpack_invalid_not_sorted() { let inner = VecPrefix::<_, u8>::try_from(inner).unwrap(); let packed = inner.pack_to_vec(); - let parents = StrongParents::unpack_verified(packed.as_slice(), &()); + let parents = basic::StrongParents::unpack_verified(packed.as_slice(), &()); assert!(matches!( parents, @@ -164,7 +167,7 @@ fn unpack_invalid_not_unique() { let inner = VecPrefix::<_, u8>::try_from(inner).unwrap(); let packed = inner.pack_to_vec(); - let parents = StrongParents::unpack_verified(packed.as_slice(), &()); + let parents = basic::StrongParents::unpack_verified(packed.as_slice(), &()); assert!(matches!( parents,