Skip to content

Commit

Permalink
Merge branch '2.0' of https://github.com/iotaledger/iota-sdk into 500…
Browse files Browse the repository at this point in the history
…-error-patch
  • Loading branch information
marc2332 committed Feb 26, 2024
2 parents ddb3652 + 9e6976a commit 4570579
Show file tree
Hide file tree
Showing 14 changed files with 578 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ impl InputSelection {
let features = input.features().iter().filter(|feature| !feature.is_sender()).cloned();

let mut builder = AccountOutputBuilder::from(input)
.with_amount_or_minimum(input.amount(), self.protocol_parameters.storage_score_parameters())
.with_account_id(account_id)
.with_foundry_counter(u32::max(highest_foundry_serial_number, input.foundry_counter()))
.with_features(features);
Expand Down Expand Up @@ -102,6 +103,7 @@ impl InputSelection {
let features = input.features().iter().filter(|feature| !feature.is_sender()).cloned();

let output = NftOutputBuilder::from(input)
.with_amount_or_minimum(input.amount(), self.protocol_parameters.storage_score_parameters())
.with_nft_id(nft_id)
.with_features(features)
.finish_output()?;
Expand Down Expand Up @@ -139,7 +141,9 @@ impl InputSelection {
return Ok(None);
}

let output = FoundryOutputBuilder::from(input).finish_output()?;
let output = FoundryOutputBuilder::from(input)
.with_amount_or_minimum(input.amount(), self.protocol_parameters.storage_score_parameters())
.finish_output()?;

log::debug!("Automatic transition of {output_id:?}/{foundry_id:?}");

Expand Down
6 changes: 4 additions & 2 deletions sdk/src/client/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ impl ClientBuilder {

let node_sync_interval = self.node_manager_builder.node_sync_interval;
let ignore_node_health = self.node_manager_builder.ignore_node_health;
let nodes = self
let nodes: HashSet<Node> = self
.node_manager_builder
.primary_nodes
.iter()
Expand All @@ -207,7 +207,9 @@ impl ClientBuilder {
let (mqtt_event_tx, mqtt_event_rx) = tokio::sync::watch::channel(MqttEvent::Connected);

let client_inner = Arc::new(ClientInner {
node_manager: RwLock::new(self.node_manager_builder.build(HashSet::new())),
// Initially assume all nodes are healthy, so `fetch_network_info()` works. `sync_nodes()` will afterwards
// update the healthy nodes.
node_manager: RwLock::new(self.node_manager_builder.build(nodes.clone())),
api_timeout: RwLock::new(self.api_timeout),
#[cfg(feature = "mqtt")]
mqtt: super::MqttInner {
Expand Down
72 changes: 55 additions & 17 deletions sdk/src/types/block/core/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::types::block::{
block_id::{BlockHash, BlockId},
core::{BasicBlockBody, ValidationBlockBody},
output::AccountId,
payload::Payload,
protocol::ProtocolParameters,
signature::Signature,
slot::{SlotCommitmentId, SlotIndex},
Expand Down Expand Up @@ -56,8 +57,26 @@ impl UnsignedBlock {
[self.header.hash(), self.body.hash()].concat()
}

/// Finishes an [`UnsignedBlock`] into a [`Block`].
pub fn finish_with_params<'a>(
self,
signature: impl Into<Signature>,
params: impl Into<Option<&'a ProtocolParameters>>,
) -> Result<Block, Error> {
if let Some(params) = params.into() {
verify_block_slot(&self.header, &self.body, params)?;
}

Ok(Block {
header: self.header,
body: self.body,
signature: signature.into(),
})
}

/// Finishes an [`UnsignedBlock`] into a [`Block`] without protocol validation.
pub fn finish(self, signature: impl Into<Signature>) -> Result<Block, Error> {
Ok(Block::new(self.header, self.body, signature))
self.finish_with_params(signature, None)
}
}

Expand Down Expand Up @@ -154,18 +173,6 @@ impl Block {
/// The maximum number of bytes in a block.
pub const LENGTH_MAX: usize = 32768;

/// Creates a new [`Block`].
#[inline(always)]
pub fn new(header: BlockHeader, body: BlockBody, signature: impl Into<Signature>) -> Self {
let signature = signature.into();

Self {
header,
body,
signature,
}
}

/// Creates a new [`UnsignedBlock`].
#[inline(always)]
pub fn build(header: BlockHeader, body: BlockBody) -> UnsignedBlock {
Expand Down Expand Up @@ -288,7 +295,9 @@ impl Packable for Block {
signature,
};

if protocol_params.is_some() {
if let Some(protocol_params) = protocol_params {
verify_block_slot(&block.header, &block.body, &protocol_params).map_err(UnpackError::Packable)?;

let block_len = if let (Some(start), Some(end)) = (start_opt, unpacker.read_bytes()) {
end - start
} else {
Expand All @@ -304,6 +313,35 @@ impl Packable for Block {
}
}

fn verify_block_slot(header: &BlockHeader, body: &BlockBody, params: &ProtocolParameters) -> Result<(), Error> {
if let BlockBody::Basic(basic) = body {
if let Some(Payload::SignedTransaction(signed_transaction)) = basic.payload() {
let transaction = signed_transaction.transaction();
let block_slot = params.slot_index(header.issuing_time / 1_000_000_000);

if block_slot < transaction.creation_slot() {
return Err(Error::BlockSlotBeforeTransactionCreationSlot);
}

if let Some(commitment) = signed_transaction.transaction().context_inputs().commitment() {
let commitment_slot = commitment.slot_index();

if !(block_slot - params.max_committable_age()..=block_slot - params.min_committable_age())
.contains(&commitment_slot)
{
return Err(Error::TransactionCommitmentSlotNotInBlockSlotInterval);
}

if commitment_slot > header.slot_commitment_id.slot_index() {
return Err(Error::TransactionCommitmentSlotAfterBlockCommitmentSlot);
}
}
}
}

Ok(())
}

#[cfg(feature = "serde")]
pub(crate) mod dto {
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -366,11 +404,11 @@ pub(crate) mod dto {
}
}

Ok(Self::new(
UnsignedBlock::new(
BlockHeader::try_from_dto_with_params_inner(dto.inner.header, params)?,
BlockBody::try_from_dto_with_params_inner(dto.inner.body, params)?,
dto.signature,
))
)
.finish_with_params(dto.signature, params)
}
}

Expand Down
13 changes: 13 additions & 0 deletions sdk/src/types/block/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ pub enum Error {
},
TrailingCapabilityBytes,
RestrictedAddressCapability(AddressCapabilityFlag),
BlockSlotBeforeTransactionCreationSlot,
TransactionCommitmentSlotNotInBlockSlotInterval,
TransactionCommitmentSlotAfterBlockCommitmentSlot,
}

#[cfg(feature = "std")]
Expand Down Expand Up @@ -450,6 +453,16 @@ impl fmt::Display for Error {
}
Self::TrailingCapabilityBytes => write!(f, "capability bytes have trailing zeroes"),
Self::RestrictedAddressCapability(cap) => write!(f, "restricted address capability: {cap:?}"),
Self::BlockSlotBeforeTransactionCreationSlot => {
write!(f, "the block slot is before its contained transaction creation slot")
}
Self::TransactionCommitmentSlotNotInBlockSlotInterval => write!(
f,
"the transaction commitment slot is not in the allowed block slot interval"
),
Self::TransactionCommitmentSlotAfterBlockCommitmentSlot => {
write!(f, "the transaction commitment slot is after the block commitment slot")
}
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions sdk/src/types/block/output/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ impl AccountOutputBuilder {
Self::new(OutputBuilderAmount::Amount(amount), account_id)
}

/// Creates an [`AccountOutputBuilder`] with a provided amount, unless it is below the minimum.
pub fn new_with_amount_or_minimum(amount: u64, account_id: AccountId, params: StorageScoreParameters) -> Self {
Self::new(OutputBuilderAmount::AmountOrMinimum(amount, params), account_id)
}

/// Creates an [`AccountOutputBuilder`] with provided storage score parameters.
/// The amount will be set to the minimum required amount of the resulting output.
pub fn new_with_minimum_amount(params: StorageScoreParameters, account_id: AccountId) -> Self {
Expand All @@ -98,6 +103,13 @@ impl AccountOutputBuilder {
self
}

/// Sets the amount to the provided value, unless it is below the minimum.
#[inline(always)]
pub fn with_amount_or_minimum(mut self, amount: u64, params: StorageScoreParameters) -> Self {
self.amount = OutputBuilderAmount::AmountOrMinimum(amount, params);
self
}

/// Sets the amount to the minimum required amount.
#[inline(always)]
pub fn with_minimum_amount(mut self, params: StorageScoreParameters) -> Self {
Expand Down Expand Up @@ -246,6 +258,7 @@ impl AccountOutputBuilder {

output.amount = match self.amount {
OutputBuilderAmount::Amount(amount) => amount,
OutputBuilderAmount::AmountOrMinimum(amount, params) => output.minimum_amount(params).max(amount),
OutputBuilderAmount::MinimumAmount(params) => output.minimum_amount(params),
};

Expand Down
13 changes: 13 additions & 0 deletions sdk/src/types/block/output/anchor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ impl AnchorOutputBuilder {
Self::new(OutputBuilderAmount::Amount(amount), anchor_id)
}

/// Creates an [`AnchorOutputBuilder`] with a provided amount, unless it is below the minimum.
pub fn new_with_amount_or_minimum(amount: u64, anchor_id: AnchorId, params: StorageScoreParameters) -> Self {
Self::new(OutputBuilderAmount::AmountOrMinimum(amount, params), anchor_id)
}

/// Creates an [`AnchorOutputBuilder`] with provided storage score parameters.
/// The amount will be set to the minimum required amount of the resulting output.
#[inline(always)]
Expand All @@ -131,6 +136,13 @@ impl AnchorOutputBuilder {
self
}

/// Sets the amount to the provided value, unless it is below the minimum.
#[inline(always)]
pub fn with_amount_or_minimum(mut self, amount: u64, params: StorageScoreParameters) -> Self {
self.amount = OutputBuilderAmount::AmountOrMinimum(amount, params);
self
}

/// Sets the amount to the minimum required amount.
#[inline(always)]
pub fn with_minimum_amount(mut self, params: StorageScoreParameters) -> Self {
Expand Down Expand Up @@ -277,6 +289,7 @@ impl AnchorOutputBuilder {

output.amount = match self.amount {
OutputBuilderAmount::Amount(amount) => amount,
OutputBuilderAmount::AmountOrMinimum(amount, params) => output.minimum_amount(params).max(amount),
OutputBuilderAmount::MinimumAmount(params) => output.minimum_amount(params),
};

Expand Down
14 changes: 14 additions & 0 deletions sdk/src/types/block/output/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ impl BasicOutputBuilder {
Self::new(OutputBuilderAmount::Amount(amount))
}

/// Creates a [`BasicOutputBuilder`] with a provided amount, unless it is below the minimum.
pub fn new_with_amount_or_minimum(amount: u64, params: StorageScoreParameters) -> Self {
Self::new(OutputBuilderAmount::AmountOrMinimum(amount, params))
}

/// Creates an [`BasicOutputBuilder`] with provided storage score parameters.
/// The amount will be set to the minimum required amount of the resulting output.
#[inline(always)]
Expand All @@ -61,6 +66,13 @@ impl BasicOutputBuilder {
self
}

/// Sets the amount to the provided value, unless it is below the minimum.
#[inline(always)]
pub fn with_amount_or_minimum(mut self, amount: u64, params: StorageScoreParameters) -> Self {
self.amount = OutputBuilderAmount::AmountOrMinimum(amount, params);
self
}

/// Sets the amount to the minimum required amount.
#[inline(always)]
pub fn with_minimum_amount(mut self, params: StorageScoreParameters) -> Self {
Expand Down Expand Up @@ -182,6 +194,7 @@ impl BasicOutputBuilder {
self
}
}
OutputBuilderAmount::AmountOrMinimum(_, _) => self,
OutputBuilderAmount::MinimumAmount(_) => self,
})
}
Expand Down Expand Up @@ -211,6 +224,7 @@ impl BasicOutputBuilder {

output.amount = match self.amount {
OutputBuilderAmount::Amount(amount) => amount,
OutputBuilderAmount::AmountOrMinimum(amount, params) => output.minimum_amount(params).max(amount),
OutputBuilderAmount::MinimumAmount(params) => output.minimum_amount(params),
};

Expand Down
Loading

0 comments on commit 4570579

Please sign in to comment.