Skip to content

Commit

Permalink
Merge branch '2.0' into refactor-MetadataFeature
Browse files Browse the repository at this point in the history
  • Loading branch information
Thoralf-M authored Jan 12, 2024
2 parents 8ea060d + fe776bd commit 77cb1b2
Show file tree
Hide file tree
Showing 18 changed files with 3,303 additions and 2,613 deletions.
6 changes: 3 additions & 3 deletions sdk/src/types/block/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ pub enum Error {
DuplicateOutputChain(ChainId),
InvalidField(&'static str),
NullDelegationValidatorId,
InvalidEpochDelta {
InvalidEpochDiff {
created: EpochIndex,
target: EpochIndex,
},
Expand Down Expand Up @@ -447,8 +447,8 @@ impl fmt::Display for Error {
Self::DuplicateOutputChain(chain_id) => write!(f, "duplicate output chain {chain_id}"),
Self::InvalidField(field) => write!(f, "invalid field: {field}"),
Self::NullDelegationValidatorId => write!(f, "null delegation validator ID"),
Self::InvalidEpochDelta { created, target } => {
write!(f, "invalid epoch delta: created {created}, target {target}")
Self::InvalidEpochDiff { created, target } => {
write!(f, "invalid epoch diff: created {created}, target {target}")
}
Self::TrailingCapabilityBytes => write!(f, "capability bytes have trailing zeroes"),
Self::RestrictedAddressCapability(cap) => write!(f, "restricted address capability: {cap:?}"),
Expand Down
459 changes: 298 additions & 161 deletions sdk/src/types/block/mana/parameters.rs

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions sdk/src/types/block/protocol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,51 @@ impl ProtocolParameters {
epoch_index.into().last_slot_index(self.slots_per_epoch_exponent())
}

/// Calculates the number of slots before the next epoch.
pub fn slots_before_next_epoch(&self, slot_index: impl Into<SlotIndex>) -> u32 {
let slot_index = slot_index.into();

if slot_index.0 < self.genesis_slot() {
0
} else {
self.genesis_slot() + self.first_slot_of(self.epoch_index_of(slot_index) + 1).0 - slot_index.0
}
}

/// Calculates the number of slots since the start of the epoch.
pub fn slots_since_epoch_start(&self, slot_index: impl Into<SlotIndex>) -> u32 {
let slot_index = slot_index.into();

if slot_index.0 < self.genesis_slot() {
0
} else {
self.genesis_slot() + slot_index.0 - self.first_slot_of(self.epoch_index_of(slot_index)).0
}
}

/// Gets the [`EpochIndex`] of a given [`SlotIndex`].
pub fn epoch_index_of(&self, slot_index: impl Into<SlotIndex>) -> EpochIndex {
EpochIndex::from_slot_index(slot_index.into(), self.slots_per_epoch_exponent())
}

/// Calculates the duration of an epoch in seconds.
pub fn epoch_duration_in_seconds(&self) -> u64 {
self.slot_duration_in_seconds() as u64 * self.slots_per_epoch() as u64
}

/// Calculates the number of epochs per year.
pub fn epochs_per_year(&self) -> f64 {
(365_u64 * 24 * 60 * 60) as f64 / self.epoch_duration_in_seconds() as f64
}

/// Calculates the decay per epoch based on the annual decay factor and number of epochs in a year.
#[cfg(feature = "std")]
pub fn decay_per_epoch(&self) -> f64 {
self.mana_parameters()
.annual_decay_factor()
.powf(self.epochs_per_year().recip())
}

/// Returns the hash of the [`ProtocolParameters`].
pub fn hash(&self) -> ProtocolParametersHash {
ProtocolParametersHash::new(Blake2b256::digest(self.pack_to_vec()).into())
Expand Down
13 changes: 11 additions & 2 deletions sdk/src/types/block/rand/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
// Copyright 2020-2021 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use crate::types::block::{payload::signed_transaction::TransactionId, rand::bytes::rand_bytes_array};
use crate::types::block::{
payload::signed_transaction::{TransactionHash, TransactionId},
rand::{bytes::rand_bytes_array, number::rand_number},
slot::SlotIndex,
};

/// Generates a random transaction id with a given slot index.
pub fn rand_transaction_id_with_slot_index(slot_index: impl Into<SlotIndex>) -> TransactionId {
TransactionHash::new(rand_bytes_array()).into_transaction_id(slot_index.into())
}

/// Generates a random transaction id.
pub fn rand_transaction_id() -> TransactionId {
TransactionId::new(rand_bytes_array())
rand_transaction_id_with_slot_index(rand_number::<u32>())
}
61 changes: 54 additions & 7 deletions sdk/src/types/block/semantic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ pub use self::{
};
use crate::types::block::{
address::Address,
output::{AccountId, AnchorOutput, ChainId, FoundryId, NativeTokens, Output, OutputId, TokenId},
output::{
AccountId, AnchorOutput, ChainId, FoundryId, MinimumOutputAmount, NativeTokens, Output, OutputId, TokenId,
},
payload::signed_transaction::{Transaction, TransactionCapabilityFlag, TransactionSigningHash},
protocol::ProtocolParameters,
unlock::Unlock,
Expand Down Expand Up @@ -160,7 +162,37 @@ impl<'a> SemanticValidationContext<'a> {
.checked_add(amount)
.ok_or(Error::ConsumedAmountOverflow)?;

self.input_mana = self.input_mana.checked_add(mana).ok_or(Error::ConsumedManaOverflow)?;
let potential_mana = {
// Deposit amount doesn't generate mana
let min_deposit = consumed_output.minimum_amount(self.protocol_parameters.storage_score_parameters());
let generation_amount = consumed_output.amount().saturating_sub(min_deposit);

self.protocol_parameters.generate_mana_with_decay(
generation_amount,
output_id.transaction_id().slot_index(),
self.transaction.creation_slot(),
)
}?;

// Add potential mana
self.input_mana = self
.input_mana
.checked_add(potential_mana)
.ok_or(Error::ConsumedManaOverflow)?;

let stored_mana = self.protocol_parameters.mana_with_decay(
mana,
output_id.transaction_id().slot_index(),
self.transaction.creation_slot(),
)?;

// Add stored mana
self.input_mana = self
.input_mana
.checked_add(stored_mana)
.ok_or(Error::ConsumedManaOverflow)?;

// TODO: Add reward mana https://github.com/iotaledger/iota-sdk/issues/1310

if let Some(consumed_native_token) = consumed_native_token {
let native_token_amount = self
Expand Down Expand Up @@ -221,8 +253,17 @@ impl<'a> SemanticValidationContext<'a> {
.checked_add(amount)
.ok_or(Error::CreatedAmountOverflow)?;

// Add stored mana
self.output_mana = self.output_mana.checked_add(mana).ok_or(Error::CreatedManaOverflow)?;

// Add allotted mana
for mana_allotment in self.transaction.allotments() {
self.output_mana = self
.output_mana
.checked_add(mana_allotment.mana())
.ok_or(Error::CreatedManaOverflow)?;
}

if let Some(created_native_token) = created_native_token {
let native_token_amount = self
.output_native_tokens
Expand Down Expand Up @@ -251,11 +292,17 @@ impl<'a> SemanticValidationContext<'a> {
return Ok(Some(TransactionFailureReason::SumInputsOutputsAmountMismatch));
}

// TODO re-enable with https://github.com/iotaledger/iota-sdk/issues/1692
// if self.input_mana > self.output_mana &&
// !self.transaction.has_capability(TransactionCapabilityFlag::BurnMana) { // TODO: add a variant https://github.com/iotaledger/iota-sdk/issues/1430
// return Ok(Some(TransactionFailureReason::SemanticValidationFailed));
// }
if self.input_mana != self.output_mana {
if self.input_mana > self.output_mana {
if !self.transaction.has_capability(TransactionCapabilityFlag::BurnMana) {
return Ok(Some(
TransactionFailureReason::TransactionCapabilityManaBurningNotAllowed,
));
}
} else {
return Ok(Some(TransactionFailureReason::InvalidManaAmount));
}
}

// Validation of input native tokens.
let mut native_token_ids = self.input_native_tokens.keys().collect::<HashSet<_>>();
Expand Down
Loading

0 comments on commit 77cb1b2

Please sign in to comment.