Skip to content

Commit

Permalink
Merge branch '2.0' into fix/mana-calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Coats committed Jan 11, 2024
2 parents c22fee8 + 019d348 commit e9e35d9
Show file tree
Hide file tree
Showing 22 changed files with 3,053 additions and 2,465 deletions.
13 changes: 13 additions & 0 deletions bindings/core/src/method/secret_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,19 @@ pub enum SecretManagerMethod {
#[derivative(Debug(format_with = "OmittedDebug::omitted_fmt"))]
password: String,
},
/// Change the stronghold password.
/// Expected response: [`Ok`](crate::Response::Ok)
#[cfg(feature = "stronghold")]
#[cfg_attr(docsrs, doc(cfg(feature = "stronghold")))]
ChangeStrongholdPassword {
#[derivative(Debug(format_with = "OmittedDebug::omitted_fmt"))]
password: String,
},
/// Clear the stronghold password.
/// Expected response: [`Ok`](crate::Response::Ok)
#[cfg(feature = "stronghold")]
#[cfg_attr(docsrs, doc(cfg(feature = "stronghold")))]
ClearStrongholdPassword,
}

#[cfg(test)]
Expand Down
24 changes: 24 additions & 0 deletions bindings/core/src/method_handler/secret_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,30 @@ where
stronghold.set_password(password).await?;
Response::Ok
}
#[cfg(feature = "stronghold")]
SecretManagerMethod::ChangeStrongholdPassword { password } => {
let stronghold = if let Some(secret_manager) = secret_manager.downcast::<StrongholdSecretManager>() {
secret_manager
} else if let Some(SecretManager::Stronghold(secret_manager)) = secret_manager.downcast::<SecretManager>() {
secret_manager
} else {
return Err(iota_sdk::client::Error::SecretManagerMismatch.into());
};
stronghold.change_password(password).await?;
Response::Ok
}
#[cfg(feature = "stronghold")]
SecretManagerMethod::ClearStrongholdPassword => {
let stronghold = if let Some(secret_manager) = secret_manager.downcast::<StrongholdSecretManager>() {
secret_manager
} else if let Some(SecretManager::Stronghold(secret_manager)) = secret_manager.downcast::<SecretManager>() {
secret_manager
} else {
return Err(iota_sdk::client::Error::SecretManagerMismatch.into());
};
stronghold.clear_key().await;
Response::Ok
}
};
Ok(response)
}
19 changes: 19 additions & 0 deletions bindings/nodejs/lib/secret_manager/secret-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,4 +226,23 @@ export class SecretManager {
data: { password },
});
}

/**
* Change the Stronghold password.
*/
async changeStrongholdPassword(password: string): Promise<void> {
await this.methodHandler.callMethod({
name: 'changeStrongholdPassword',
data: { password },
});
}

/**
* Clear the Stronghold password.
*/
async clearStrongholdPassword(): Promise<void> {
await this.methodHandler.callMethod({
name: 'clearStrongholdPassword',
});
}
}
6 changes: 5 additions & 1 deletion bindings/nodejs/lib/types/secret_manager/bridge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import type {
__SignEd25519Method__,
__SignSecp256k1EcdsaMethod__,
__SetStrongholdPasswordMethod__,
__ChangeStrongholdPasswordMethod__,
__ClearStrongholdPasswordMethod__,
} from './secret-manager';

export type __SecretManagerMethods__ =
Expand All @@ -21,4 +23,6 @@ export type __SecretManagerMethods__ =
| __StoreMnemonicMethod__
| __SignEd25519Method__
| __SignSecp256k1EcdsaMethod__
| __SetStrongholdPasswordMethod__;
| __SetStrongholdPasswordMethod__
| __ChangeStrongholdPasswordMethod__
| __ClearStrongholdPasswordMethod__;
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,12 @@ export interface __SetStrongholdPasswordMethod__ {
name: 'setStrongholdPassword';
data: { password: string };
}

export interface __ChangeStrongholdPasswordMethod__ {
name: 'changeStrongholdPassword';
data: { password: string };
}

export interface __ClearStrongholdPasswordMethod__ {
name: 'clearStrongholdPassword';
}
6 changes: 3 additions & 3 deletions sdk/src/types/block/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ pub enum Error {
DuplicateOutputChain(ChainId),
InvalidField(&'static str),
NullDelegationValidatorId,
InvalidEpochDelta {
InvalidEpochDiff {
created: EpochIndex,
target: EpochIndex,
},
Expand Down Expand Up @@ -429,8 +429,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
30 changes: 18 additions & 12 deletions sdk/src/types/block/mana/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ impl ManaParameters {
(1 << self.bits_count) - 1
}

fn decay(&self, mut mana: u64, epoch_delta: u32) -> u64 {
if mana == 0 || epoch_delta == 0 || self.decay_factors().is_empty() {
fn decay(&self, mut mana: u64, epoch_diff: u32) -> u64 {
if mana == 0 || epoch_diff == 0 || self.decay_factors().is_empty() {
return mana;
}

// we keep applying the lookup table factors as long as n epochs are left
let mut remaining_epochs = epoch_delta;
let mut remaining_epochs = epoch_diff;

while remaining_epochs > 0 {
let epochs_to_decay = remaining_epochs.min(self.decay_factors().len() as u32);
Expand All @@ -85,13 +85,14 @@ impl ManaParameters {
mana
}

fn generate_mana(&self, amount: u64, slot_delta: u32) -> u64 {
if self.generation_rate() == 0 || slot_delta == 0 {
fn generate_mana(&self, amount: u64, slot_diff: u32) -> u64 {
if self.generation_rate() == 0 || slot_diff == 0 {
return 0;
}

fixed_point_multiply(
amount,
slot_delta * self.generation_rate() as u32,
slot_diff * self.generation_rate() as u32,
self.generation_rate_exponent(),
)
}
Expand Down Expand Up @@ -121,17 +122,18 @@ impl ProtocolParameters {
slot_index_created: impl Into<SlotIndex>,
slot_index_target: impl Into<SlotIndex>,
) -> Result<u64, Error> {
let (slot_index_created, slot_index_target) = (slot_index_created.into(), slot_index_target.into());
let (epoch_index_created, epoch_index_target) = (
self.epoch_index_of(slot_index_created),
self.epoch_index_of(slot_index_target),
);

if epoch_index_created > epoch_index_target {
return Err(Error::InvalidEpochDelta {
return Err(Error::InvalidEpochDiff {
created: epoch_index_created,
target: epoch_index_target,
});
}

Ok(self
.mana_parameters()
.decay(mana, epoch_index_target.0 - epoch_index_created.0))
Expand All @@ -145,12 +147,14 @@ impl ProtocolParameters {
claimed_epoch: impl Into<EpochIndex>,
) -> Result<u64, Error> {
let (reward_epoch, claimed_epoch) = (reward_epoch.into(), claimed_epoch.into());

if reward_epoch > claimed_epoch {
return Err(Error::InvalidEpochDelta {
return Err(Error::InvalidEpochDiff {
created: reward_epoch,
target: claimed_epoch,
});
}

Ok(self.mana_parameters().decay(reward, claimed_epoch.0 - reward_epoch.0))
}

Expand All @@ -167,15 +171,17 @@ impl ProtocolParameters {
self.epoch_index_of(slot_index_created),
self.epoch_index_of(slot_index_target),
);

if epoch_index_created > epoch_index_target {
return Err(Error::InvalidEpochDelta {
return Err(Error::InvalidEpochDiff {
created: epoch_index_created,
target: epoch_index_target,
});
}
if slot_index_created >= slot_index_target {
return Ok(0);
}

let mana_parameters = self.mana_parameters();

Ok(if epoch_index_created == epoch_index_target {
Expand Down Expand Up @@ -305,7 +311,7 @@ mod test {
stored_mana: 0,
created_slot: params().first_slot_of(2),
target_slot: params().first_slot_of(1),
err: Some(Error::InvalidEpochDelta {
err: Some(Error::InvalidEpochDiff {
created: 2.into(),
target: 1.into(),
}),
Expand Down Expand Up @@ -391,7 +397,7 @@ mod test {
amount: 0,
created_slot: params().first_slot_of(2),
target_slot: params().first_slot_of(1),
err: Some(Error::InvalidEpochDelta {
err: Some(Error::InvalidEpochDiff {
created: 2.into(),
target: 1.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 e9e35d9

Please sign in to comment.