Skip to content

Commit

Permalink
Merge branch '2.0' into python-serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
Thoralf-M authored Jan 11, 2024
2 parents d63a8e5 + 381c972 commit 60c1835
Show file tree
Hide file tree
Showing 33 changed files with 513 additions and 307 deletions.
8 changes: 8 additions & 0 deletions bindings/core/src/method/secret_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ pub enum SecretManagerMethod {
#[derivative(Debug(format_with = "OmittedDebug::omitted_fmt"))]
mnemonic: String,
},
/// Set the stronghold password.
/// Expected response: [`Ok`](crate::Response::Ok)
#[cfg(feature = "stronghold")]
#[cfg_attr(docsrs, doc(cfg(feature = "stronghold")))]
SetStrongholdPassword {
#[derivative(Debug(format_with = "OmittedDebug::omitted_fmt"))]
password: String,
},
}

#[cfg(test)]
Expand Down
12 changes: 12 additions & 0 deletions bindings/core/src/method_handler/secret_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ where
return Err(iota_sdk::client::Error::SecretManagerMismatch.into());
}
}
#[cfg(feature = "stronghold")]
SecretManagerMethod::SetStrongholdPassword { 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.set_password(password).await?;
Response::Ok
}
};
Ok(response)
}
10 changes: 10 additions & 0 deletions bindings/nodejs/lib/secret_manager/secret-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,14 @@ export class SecretManager {

return JSON.parse(response).payload;
}

/**
* Set the Stronghold password.
*/
async setStrongholdPassword(password: string): Promise<void> {
await this.methodHandler.callMethod({
name: 'setStrongholdPassword',
data: { password },
});
}
}
4 changes: 4 additions & 0 deletions bindings/nodejs/lib/types/models/info/node-info-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ export interface RewardsParameters {
* in the pool rewards calculations.
*/
poolCoefficientExponent: number;
/**
* The number of epochs for which rewards are retained.
*/
retentionPeriod: number;
}

/**
Expand Down
4 changes: 3 additions & 1 deletion bindings/nodejs/lib/types/secret_manager/bridge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
__SignatureUnlockMethod__,
__SignEd25519Method__,
__SignSecp256k1EcdsaMethod__,
__SetStrongholdPasswordMethod__,
} from './secret-manager';

export type __SecretManagerMethods__ =
Expand All @@ -19,4 +20,5 @@ export type __SecretManagerMethods__ =
| __SignatureUnlockMethod__
| __StoreMnemonicMethod__
| __SignEd25519Method__
| __SignSecp256k1EcdsaMethod__;
| __SignSecp256k1EcdsaMethod__
| __SetStrongholdPasswordMethod__;
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,8 @@ export interface __SignSecp256k1EcdsaMethod__ {
export interface __GetLedgerNanoStatusMethod__ {
name: 'getLedgerNanoStatus';
}

export interface __SetStrongholdPasswordMethod__ {
name: 'setStrongholdPassword';
data: { password: string };
}
2 changes: 2 additions & 0 deletions bindings/python/iota_sdk/types/node_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ class RewardsParameters:
decay_balancing_constant_exponent: The exponent used for calculation of the initial reward.
decay_balancing_constant: An integer approximation which is calculated using the `decay_balancing_constant_exponent`.
pool_coefficient_exponent: The exponent used for shifting operation during the pool rewards calculations.
retention_period: The number of epochs for which rewards are retained.
"""
profit_margin_exponent: int
bootstrapping_duration: int
Expand All @@ -220,6 +221,7 @@ class RewardsParameters:
encoder=str
))
pool_coefficient_exponent: int
retention_period: int


@json
Expand Down
1 change: 1 addition & 0 deletions cli/src/wallet_cli/completer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use rustyline::{
const WALLET_COMMANDS: &[&str] = &[
"accounts",
"address",
"allot-mana",
"balance",
"burn-native-token",
"burn-nft",
Expand Down
54 changes: 49 additions & 5 deletions cli/src/wallet_cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use iota_sdk::{
api::plugins::participation::types::ParticipationEventId,
block::{
address::{Bech32Address, ToBech32Ext},
mana::ManaAllotment,
output::{
unlock_condition::AddressUnlockCondition, AccountId, BasicOutputBuilder, FoundryId, NativeToken,
NativeTokensBuilder, NftId, Output, OutputId, TokenId,
Expand Down Expand Up @@ -60,6 +61,8 @@ pub enum WalletCommand {
Accounts,
/// Print the wallet address.
Address,
/// Allots mana to an account.
AllotMana { mana: u64, account_id: Option<AccountId> },
/// Print the wallet balance.
Balance,
/// Burn an amount of native token.
Expand Down Expand Up @@ -325,12 +328,18 @@ pub async fn accounts_command(wallet: &Wallet) -> Result<(), Error> {
let output_id = account.output_id;
let account_id = account.output.as_account().account_id_non_null(&output_id);
let account_address = account_id.to_bech32(wallet.client().get_bech32_hrp().await?);
let bic = wallet
.client()
.get_account_congestion(&account_id)
.await?
.block_issuance_credits;

println_log_info!(
"{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n",
"{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n{:<16} {bic}\n",
"Output ID:",
"Account ID:",
"Account Address:"
"Account Address:",
"BIC:"
);
}

Expand All @@ -344,6 +353,32 @@ pub async fn address_command(wallet: &Wallet) -> Result<(), Error> {
Ok(())
}

// `allot-mana` command
pub async fn allot_mana_command(wallet: &Wallet, mana: u64, account_id: Option<AccountId>) -> Result<(), Error> {
let wallet_data = wallet.data().await;
let account_id = account_id
.or(wallet_data
.accounts()
.next()
.map(|o| o.output.as_account().account_id_non_null(&o.output_id)))
.or(wallet_data
.implicit_accounts()
.next()
.map(|o| AccountId::from(&o.output_id)))
.ok_or(WalletError::AccountNotFound)?;
drop(wallet_data);

let transaction = wallet.allot_mana([ManaAllotment::new(account_id, mana)?], None).await?;

println_log_info!(
"Mana allotment transaction sent:\n{:?}\n{:?}",
transaction.transaction_id,
transaction.block_id
);

Ok(())
}

// `balance` command
pub async fn balance_command(wallet: &Wallet) -> Result<(), Error> {
let balance = wallet.balance().await?;
Expand Down Expand Up @@ -497,7 +532,7 @@ pub async fn congestion_command(wallet: &Wallet, account_id: Option<AccountId>)
.next()
.map(|o| AccountId::from(&o.output_id))
})
.ok_or(WalletError::NoAccountToIssueBlock)?
.ok_or(WalletError::AccountNotFound)?
};

let congestion = wallet.client().get_account_congestion(&account_id).await?;
Expand Down Expand Up @@ -668,12 +703,18 @@ pub async fn implicit_accounts_command(wallet: &Wallet) -> Result<(), Error> {
let output_id = implicit_account.output_id;
let account_id = AccountId::from(&output_id);
let account_address = account_id.to_bech32(wallet.client().get_bech32_hrp().await?);
let bic = wallet
.client()
.get_account_congestion(&account_id)
.await?
.block_issuance_credits;

println_log_info!(
"{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n",
"{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n{:<16} {bic}\n",
"Output ID:",
"Account ID:",
"Account Address:"
"Account Address:",
"BIC:"
);
}

Expand Down Expand Up @@ -1173,6 +1214,9 @@ pub async fn prompt_internal(
match protocol_cli.command {
WalletCommand::Accounts => accounts_command(wallet).await,
WalletCommand::Address => address_command(wallet).await,
WalletCommand::AllotMana { mana, account_id } => {
allot_mana_command(wallet, mana, account_id).await
}
WalletCommand::Balance => balance_command(wallet).await,
WalletCommand::BurnNativeToken { token_id, amount } => {
burn_native_token_command(wallet, token_id, amount).await
Expand Down
15 changes: 13 additions & 2 deletions sdk/src/client/api/block_builder/input_selection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::{
types::block::{
address::{AccountAddress, Address, NftAddress},
input::INPUT_COUNT_RANGE,
mana::ManaAllotment,
output::{
AccountOutput, ChainId, FoundryOutput, NativeTokensBuilder, NftOutput, Output, OutputId, OUTPUT_COUNT_RANGE,
},
Expand All @@ -45,6 +46,7 @@ pub struct InputSelection {
slot_index: SlotIndex,
requirements: Vec<Requirement>,
automatically_transitioned: HashSet<ChainId>,
mana_allotments: u64,
}

/// Result of the input selection algorithm.
Expand Down Expand Up @@ -101,6 +103,8 @@ impl InputSelection {
}

fn init(&mut self) -> Result<(), Error> {
// Adds an initial mana requirement.
self.requirements.push(Requirement::Mana(self.mana_allotments));
// Adds an initial amount requirement.
self.requirements.push(Requirement::Amount);
// Adds an initial native tokens requirement.
Expand Down Expand Up @@ -190,6 +194,7 @@ impl InputSelection {
slot_index: SlotIndex::from(0),
requirements: Vec::new(),
automatically_transitioned: HashSet::new(),
mana_allotments: 0,
}
}

Expand Down Expand Up @@ -223,6 +228,12 @@ impl InputSelection {
self
}

/// Sets the mana allotments sum of an [`InputSelection`].
pub fn with_mana_allotments<'a>(mut self, mana_allotments: impl Iterator<Item = &'a ManaAllotment>) -> Self {
self.mana_allotments = mana_allotments.map(ManaAllotment::mana).sum();
self
}

fn filter_inputs(&mut self) {
self.available_inputs.retain(|input| {
// TODO what about other kinds?
Expand Down Expand Up @@ -373,8 +384,8 @@ impl InputSelection {
/// transaction. Also creates a remainder output and chain transition outputs if required.
pub fn select(mut self) -> Result<Selected, Error> {
if !OUTPUT_COUNT_RANGE.contains(&(self.outputs.len() as u16)) {
// If burn is provided, outputs will be added later
if !(self.outputs.is_empty() && self.burn.is_some()) {
// If burn or mana allotments are provided, outputs will be added later.
if !(self.outputs.is_empty() && (self.burn.is_some() || self.mana_allotments != 0)) {
return Err(Error::InvalidOutputCount(self.outputs.len()));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use super::{Error, InputSelection};
use crate::client::secret::types::InputSigningData;

impl InputSelection {
pub(crate) fn fulfill_mana_requirement(&mut self, allotments: u64) -> Result<Vec<InputSigningData>, Error> {
let required_mana = self.outputs.iter().map(|o| o.mana()).sum::<u64>() + allotments;
let mut selected_mana = self.selected_inputs.iter().map(|o| o.output.mana()).sum::<u64>();

if selected_mana >= required_mana {
log::debug!("Mana requirement already fulfilled");
Ok(Vec::new())
} else {
let mut inputs = Vec::new();

// TODO we should do as for the amount and have preferences on which inputs to pick.
while let Some(input) = self.available_inputs.pop() {
selected_mana += input.output.mana();
inputs.push(input);

if selected_mana >= required_mana {
break;
}
}

Ok(inputs)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub(crate) mod amount;
pub(crate) mod ed25519;
pub(crate) mod foundry;
pub(crate) mod issuer;
pub(crate) mod mana;
pub(crate) mod native_tokens;
pub(crate) mod nft;
pub(crate) mod sender;
Expand Down Expand Up @@ -39,6 +40,8 @@ pub enum Requirement {
NativeTokens,
/// Amount requirement.
Amount,
/// Mana requirement.
Mana(u64),
}

impl InputSelection {
Expand All @@ -56,6 +59,7 @@ impl InputSelection {
Requirement::Nft(nft_id) => self.fulfill_nft_requirement(nft_id),
Requirement::NativeTokens => self.fulfill_native_tokens_requirement(),
Requirement::Amount => self.fulfill_amount_requirement(),
Requirement::Mana(allotments) => self.fulfill_mana_requirement(allotments),
}
}

Expand Down
18 changes: 15 additions & 3 deletions sdk/src/client/api/block_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub mod transaction;

pub use self::transaction::verify_semantic;
use crate::{
client::{ClientInner, Result},
client::{constants::FIVE_MINUTES_IN_NANOSECONDS, ClientInner, Error, Result},
types::block::{
core::{BlockHeader, UnsignedBlock},
output::AccountId,
Expand All @@ -19,7 +19,6 @@ impl ClientInner {
pub async fn build_basic_block(&self, issuer_id: AccountId, payload: Option<Payload>) -> Result<UnsignedBlock> {
let issuance = self.get_issuance().await?;

// TODO https://github.com/iotaledger/iota-sdk/issues/1753
let issuing_time = {
#[cfg(feature = "std")]
let issuing_time = std::time::SystemTime::now()
Expand All @@ -30,7 +29,20 @@ impl ClientInner {
// https://github.com/iotaledger/iota-sdk/issues/647
#[cfg(not(feature = "std"))]
let issuing_time = 0;
issuing_time

// Check that the issuing_time is in the range of +-5 minutes of the node to prevent potential issues
if !(issuance.latest_parent_block_issuing_time - FIVE_MINUTES_IN_NANOSECONDS
..issuance.latest_parent_block_issuing_time + FIVE_MINUTES_IN_NANOSECONDS)
.contains(&issuing_time)
{
return Err(Error::TimeNotSynced {
current_time: issuing_time,
tangle_time: issuance.latest_parent_block_issuing_time,
});
}
// If timestamp is below latest_parent_block_issuing_time, just increase it to that +1 so the block doesn't
// get rejected
issuing_time.max(issuance.latest_parent_block_issuing_time + 1)
};

let protocol_params = self.get_protocol_parameters().await?;
Expand Down
Loading

0 comments on commit 60c1835

Please sign in to comment.