From b6b4b3286cb90f9171aafbf97c71e7aac6db0812 Mon Sep 17 00:00:00 2001 From: Thoralf-M Date: Wed, 31 Mar 2021 21:30:32 +0200 Subject: [PATCH] update type names and add dust_allowed field --- bindings/nodejs/README.md | 10 +++++- bindings/nodejs/lib/types/models.d.ts | 2 +- .../nodejs/native/src/classes/client/api.rs | 8 ++--- .../nodejs/native/src/classes/client/dto.rs | 8 +++-- .../src/classes/client/message_sender.rs | 6 ++-- .../nodejs/native/src/classes/client/mod.rs | 6 ++-- bindings/python/README.md | 13 ++++---- .../python/native/src/client/full_node_api.rs | 18 +++++----- .../native/src/client/high_level_api.rs | 5 +-- bindings/python/native/src/client/mod.rs | 4 +-- bindings/python/native/src/client/types.rs | 33 ++++++++++--------- examples/custom_inputs.rs | 22 ++++--------- examples/dust.rs | 17 ++++------ examples/send_all.rs | 2 +- examples/split_outputs_single_address.rs | 4 +-- examples/txspam.rs | 27 +++++++-------- iota-client/Cargo.toml | 6 ++-- iota-client/src/api/message_builder.rs | 33 +++++++++++-------- iota-client/src/client.rs | 19 +++++------ iota-client/src/lib.rs | 2 +- iota-client/src/node/address.rs | 16 ++++----- iota-client/src/node/message.rs | 4 +-- iota-client/tests/node_api.rs | 2 +- iota-core/Cargo.toml | 4 +-- specs/iota-rs-ENGINEERING-SPEC-0000.md | 12 ++++--- 25 files changed, 142 insertions(+), 141 deletions(-) diff --git a/bindings/nodejs/README.md b/bindings/nodejs/README.md index a436ca4c6..c8acd7ea3 100644 --- a/bindings/nodejs/README.md +++ b/bindings/nodejs/README.md @@ -332,7 +332,7 @@ Gets the UTXO outputs associated with the given address. **Returns** a promise resolving to a list of output ids. -#### getAddressBalance(address): Promise +#### getAddressBalance(address): Promise Gets the balance of the given address. @@ -885,6 +885,14 @@ Gets the metadata of the given message. | index | string | Indexation key | | data | Uint8Array | Indexation data | +##### AddressBalance + +| Field | Type | Description | +| ------------ | -------------------- | ---------------------- | +| address | string | Bech32 encoded address | +| balance | number | Address balance | +| dustAllowed | boolean | Dust allowed | + ### MessageMetadata | Field | Type | Description | diff --git a/bindings/nodejs/lib/types/models.d.ts b/bindings/nodejs/lib/types/models.d.ts index 7ba0de908..9eb769f29 100644 --- a/bindings/nodejs/lib/types/models.d.ts +++ b/bindings/nodejs/lib/types/models.d.ts @@ -52,7 +52,7 @@ export declare interface BrokerOptions { export declare type Address = 'string' export declare interface AddressBalance { - type: number address: Address balance: number + dust_allowed: boolean } diff --git a/bindings/nodejs/native/src/classes/client/api.rs b/bindings/nodejs/native/src/classes/client/api.rs index 55d6d72bb..57264f648 100644 --- a/bindings/nodejs/native/src/classes/client/api.rs +++ b/bindings/nodejs/native/src/classes/client/api.rs @@ -7,7 +7,7 @@ use super::MessageDto; use crate::classes::client::dto::MessageWrapper; use iota::{ - Address, AddressOutputsOptions, ClientMiner, MessageBuilder, MessageId, Parents, Seed, TransactionId, UTXOInput, + Address, AddressOutputsOptions, ClientMiner, MessageBuilder, MessageId, Parents, Seed, TransactionId, UtxoInput, }; use neon::prelude::*; @@ -20,7 +20,7 @@ pub(crate) enum Api { parents: Option>, account_index: Option, initial_address_index: Option, - inputs: Vec, + inputs: Vec, outputs: Vec<(Address, u64)>, dust_allowance_outputs: Vec<(Address, u64)>, }, @@ -57,9 +57,9 @@ pub(crate) enum Api { GetMessageMetadata(MessageId), GetRawMessage(MessageId), GetMessageChildren(MessageId), - GetOutput(UTXOInput), + GetOutput(UtxoInput), FindOutputs { - outputs: Vec, + outputs: Vec, addresses: Vec, }, GetAddressBalance(String), diff --git a/bindings/nodejs/native/src/classes/client/dto.rs b/bindings/nodejs/native/src/classes/client/dto.rs index 4421161b9..35b8d51fd 100644 --- a/bindings/nodejs/native/src/classes/client/dto.rs +++ b/bindings/nodejs/native/src/classes/client/dto.rs @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 use iota::{ - AddressDto, BalanceForAddressResponse as AddressBalancePair, Ed25519Signature, Essence, IndexationPayload, Input, + AddressDto, BalanceAddressResponse as AddressBalancePair, Ed25519Signature, Essence, IndexationPayload, Input, Message, MessageId, Output, OutputDto as BeeOutput, OutputResponse as OutputMetadata, Payload, ReferenceUnlock, - RegularEssence, SignatureUnlock, TransactionPayload, UTXOInput, UnlockBlock, UnlockBlocks, + RegularEssence, SignatureUnlock, TransactionPayload, UnlockBlock, UnlockBlocks, UtxoInput, }; use serde::{Deserialize, Serialize}; @@ -37,7 +37,7 @@ impl TryFrom for RegularEssence { .into_vec() .into_iter() .map(|input| { - UTXOInput::from_str(&input) + UtxoInput::from_str(&input) .unwrap_or_else(|_| panic!("invalid input: {}", input)) .into() }) @@ -214,6 +214,7 @@ impl From for OutputMetadataDto { pub(super) struct AddressBalanceDto { address: String, balance: u64, + dustAllowed: bool, } impl From for AddressBalanceDto { @@ -221,6 +222,7 @@ impl From for AddressBalanceDto { Self { address: value.address.to_string(), balance: value.balance, + dustAllowed: value.dust_allowed, } } } diff --git a/bindings/nodejs/native/src/classes/client/message_sender.rs b/bindings/nodejs/native/src/classes/client/message_sender.rs index b6b2c9933..e391d2ac0 100644 --- a/bindings/nodejs/native/src/classes/client/message_sender.rs +++ b/bindings/nodejs/native/src/classes/client/message_sender.rs @@ -1,7 +1,7 @@ // Copyright 2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota::{Address, MessageId, Seed, TransactionId, UTXOInput}; +use iota::{Address, MessageId, Seed, TransactionId, UtxoInput}; use neon::prelude::*; use super::{parse_address, Api, ClientTask}; @@ -16,7 +16,7 @@ pub struct MessageSender { seed: Option, account_index: Option, initial_address_index: Option, - inputs: Vec, + inputs: Vec, input_range: Range, outputs: Vec<(Address, u64)>, dust_allowance_outputs: Vec<(Address, u64)>, @@ -174,7 +174,7 @@ declare_types! { let mut this = cx.this(); let guard = cx.lock(); let inputs = &mut this.borrow_mut(&guard).inputs; - inputs.push(UTXOInput::new(transaction_id, index).expect("invalid UTXO input")); + inputs.push(UtxoInput::new(transaction_id, index).expect("invalid UTXO input")); } Ok(cx.this().upcast()) diff --git a/bindings/nodejs/native/src/classes/client/mod.rs b/bindings/nodejs/native/src/classes/client/mod.rs index 6782f3c76..4f4453a0e 100644 --- a/bindings/nodejs/native/src/classes/client/mod.rs +++ b/bindings/nodejs/native/src/classes/client/mod.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use iota::{ - message::prelude::{Address, MessageId, TransactionId, UTXOInput}, + message::prelude::{Address, MessageId, TransactionId, UtxoInput}, AddressOutputsOptions, OutputType, Seed, }; use neon::prelude::*; @@ -357,7 +357,7 @@ declare_types! { method getOutput(mut cx) { let output_id = cx.argument::(0)?.value(); - let output_id = UTXOInput::from_str(output_id.as_str()).expect("invalid output id"); + let output_id = UtxoInput::from_str(output_id.as_str()).expect("invalid output id"); let cb = cx.argument::(1)?; { let this = cx.this(); @@ -379,7 +379,7 @@ declare_types! { let mut outputs = vec![]; for js_output_id in js_output_ids { let output_id: Handle = js_output_id.downcast_or_throw(&mut cx)?; - let output_id = UTXOInput::from_str(output_id.value().as_str()).expect("invalid output id"); + let output_id = UtxoInput::from_str(output_id.value().as_str()).expect("invalid output id"); outputs.push(output_id); } diff --git a/bindings/python/README.md b/bindings/python/README.md index 78ec5e83d..01f2340a1 100644 --- a/bindings/python/README.md +++ b/bindings/python/README.md @@ -247,7 +247,7 @@ Gets the UTXO outputs associated with the given output id. **Returns** the OutputResponse[#outputresponse]. -#### get_address_balance(address): BalanceForAddressResponse +#### get_address_balance(address): BalanceAddressResponse Gets the balance in the address. @@ -255,9 +255,9 @@ Gets the balance in the address. | --------- | ---------------------- | ---------------------- | ------------------------- | | [address] | list[str] | undefined | The address Bech32 string | -**Returns** the [BalanceForAddressResponse](#balanceforaddressresponse). +**Returns** the [BalanceAddressResponse](#BalanceAddressResponse). -#### get_address_outputs(address, options (optional)): list[UTXOInput] +#### get_address_outputs(address, options (optional)): list[UtxoInput] Gets the UTXO outputs associated with the given address. @@ -266,7 +266,7 @@ Gets the UTXO outputs associated with the given address. | [address] | str | undefined | The address Bech32 string | | [options] | [[AddressOutputsOptions](#addressoutputsoptions)] | undefined | The query filters | -**Returns** the list of [UTXOInput](#utxoinput). +**Returns** the list of [UtxoInput](#UtxoInput). #### find_outputs(output_ids (optional), addresses (optional)): list[OutputResponse] @@ -564,7 +564,7 @@ message_metadata_response = { Please refer to [LedgerInclusionStateDto](#ledgerinclusionstatedto) for the details of this type. -#### BalanceForAddressResponse +#### BalanceAddressResponse A dict with the following key/value pairs. @@ -584,6 +584,7 @@ A dict with the following key/value pairs. address_balance_pair = { 'address': str, 'balance': int + 'dust_allowed': bool } ``` @@ -633,7 +634,7 @@ treasuryResponse = { } ``` -#### UTXOInput +#### UtxoInput A dict with the following key/value pairs. diff --git a/bindings/python/native/src/client/full_node_api.rs b/bindings/python/native/src/client/full_node_api.rs index 99665ac96..0457ca3a8 100644 --- a/bindings/python/native/src/client/full_node_api.rs +++ b/bindings/python/native/src/client/full_node_api.rs @@ -2,12 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use crate::client::{ - error::Result, AddressOutputsOptions, BalanceForAddressResponse, Client, InfoResponse, Message, MilestoneDto, - MilestoneUTXOChanges, OutputResponse, PeerDto, ReceiptDto, TreasuryResponse, UTXOInput, + error::Result, AddressOutputsOptions, BalanceAddressResponse, Client, InfoResponse, Message, MilestoneDto, + MilestoneUTXOChanges, OutputResponse, PeerDto, ReceiptDto, TreasuryResponse, UtxoInput, }; use iota::{ ClientMiner as RustClientMiner, MessageBuilder as RustMessageBuilder, MessageId as RustMessageId, Parents, - TransactionId as RustTransactionId, UTXOInput as RustUTXOInput, + TransactionId as RustTransactionId, UtxoInput as RustUtxoInput, }; use pyo3::prelude::*; @@ -53,12 +53,12 @@ impl Client { Ok(crate::block_on(async { self.client.post_message(&msg).await })?.to_string()) } fn get_output(&self, output_id: String) -> Result { - Ok(crate::block_on(async { self.client.get_output(&RustUTXOInput::from_str(&output_id)?).await })?.into()) + Ok(crate::block_on(async { self.client.get_output(&RustUtxoInput::from_str(&output_id)?).await })?.into()) } - fn get_address_balance(&self, address: &str) -> Result { + fn get_address_balance(&self, address: &str) -> Result { Ok(crate::block_on(async { self.client.get_address().balance(&String::from(address)).await })?.into()) } - fn get_address_outputs(&self, address: &str, options: Option) -> Result> { + fn get_address_outputs(&self, address: &str, options: Option) -> Result> { let outputs = crate::block_on(async { self.client .get_address() @@ -68,7 +68,7 @@ impl Client { Ok((*outputs) .to_vec() .iter() - .map(|output| UTXOInput { + .map(|output| UtxoInput { transaction_id: output.output_id().transaction_id().as_ref().to_vec(), index: output.output_id().index(), }) @@ -79,10 +79,10 @@ impl Client { output_ids: Option>, addresses: Option>, ) -> Result> { - let output_ids: Vec = output_ids + let output_ids: Vec = output_ids .unwrap_or_default() .iter() - .map(|input| RustUTXOInput::from_str(input).unwrap_or_else(|_| panic!("invalid input: {}", input))) + .map(|input| RustUtxoInput::from_str(input).unwrap_or_else(|_| panic!("invalid input: {}", input))) .collect(); let addresses: Vec = addresses .unwrap_or_default() diff --git a/bindings/python/native/src/client/high_level_api.rs b/bindings/python/native/src/client/high_level_api.rs index 431d72cbe..4c813f1dd 100644 --- a/bindings/python/native/src/client/high_level_api.rs +++ b/bindings/python/native/src/client/high_level_api.rs @@ -6,7 +6,7 @@ use crate::client::{ AddressBalancePair, Client, Input, Message, MessageMetadataResponse, Output, }; use iota::{ - MessageId as RustMessageId, Seed as RustSeed, TransactionId as RustTransactionId, UTXOInput as RustUTXOInput, + MessageId as RustMessageId, Seed as RustSeed, TransactionId as RustTransactionId, UtxoInput as RustUtxoInput, }; use pyo3::{exceptions, prelude::*}; use std::{ @@ -50,7 +50,7 @@ impl Client { } if let Some(inputs) = inputs { for input in inputs { - send_builder = send_builder.with_input(RustUTXOInput::new( + send_builder = send_builder.with_input(RustUtxoInput::new( RustTransactionId::from_str(&input.transaction_id[..])?, input.index, )?); @@ -286,6 +286,7 @@ impl Client { .map(|address_balance| AddressBalancePair { address: address_balance.address.clone(), balance: address_balance.balance, + dust_allowed: address_balance.dust_allowed, }) .collect()) } diff --git a/bindings/python/native/src/client/mod.rs b/bindings/python/native/src/client/mod.rs index ee72394ff..f23a7f1af 100644 --- a/bindings/python/native/src/client/mod.rs +++ b/bindings/python/native/src/client/mod.rs @@ -10,9 +10,9 @@ use iota::{Api, BrokerOptions as RustBrokerOptions, Client as RustClient}; use pyo3::prelude::*; use std::{collections::HashMap, time::Duration}; use types::{ - AddressBalancePair, AddressOutputsOptions, BalanceForAddressResponse, BrokerOptions, InfoResponse, Input, Message, + AddressBalancePair, AddressOutputsOptions, BalanceAddressResponse, BrokerOptions, InfoResponse, Input, Message, MessageMetadataResponse, MilestoneDto, MilestoneUTXOChanges, Output, OutputResponse, PeerDto, ReceiptDto, - TreasuryResponse, UTXOInput, BECH32_HRP, + TreasuryResponse, UtxoInput, BECH32_HRP, }; /// Client builder diff --git a/bindings/python/native/src/client/types.rs b/bindings/python/native/src/client/types.rs index 38528dd98..33d790297 100644 --- a/bindings/python/native/src/client/types.rs +++ b/bindings/python/native/src/client/types.rs @@ -19,10 +19,9 @@ use iota::{ TreasuryTransactionPayloadDto as RustTreasuryTransactionPayloadDto, }, responses::{ - BalanceForAddressResponse as RustBalanceForAddressResponse, InfoResponse as RustInfoResponse, - MessageMetadataResponse as RustMessageMetadataResponse, - MilestoneUtxoChangesResponse as RustMilestoneUTXOChanges, OutputResponse as RustOutputResponse, - TreasuryResponse as RustTreasuryResponse, + BalanceAddressResponse as RustBalanceAddressResponse, InfoResponse as RustInfoResponse, + MessageMetadataResponse as RustMessageMetadataResponse, OutputResponse as RustOutputResponse, + TreasuryResponse as RustTreasuryResponse, UtxoChangesResponse as RustMilestoneUTXOChanges, }, }, builder::NetworkInfo as RustNetworkInfo, @@ -33,8 +32,8 @@ use iota::{ Output as RustOutput, OutputType, Payload as RustPayload, ReferenceUnlock as RustReferenceUnlock, RegularEssence as RustRegularEssence, SignatureLockedSingleOutput as RustSignatureLockedSingleOutput, SignatureUnlock as RustSignatureUnlock, TransactionId as RustTransactionId, - TransactionPayload as RustTransactionPayload, UTXOInput as RustUTXOInput, UnlockBlock as RustUnlockBlock, - UnlockBlocks as RustUnlockBlocks, + TransactionPayload as RustTransactionPayload, UnlockBlock as RustUnlockBlock, UnlockBlocks as RustUnlockBlocks, + UtxoInput as RustUtxoInput, }; use std::{ @@ -62,7 +61,7 @@ pub struct MessageMetadataResponse { } #[derive(Debug, Clone, DeriveFromPyObject, DeriveIntoPyObject)] -pub struct BalanceForAddressResponse { +pub struct BalanceAddressResponse { // The type of the address (1=Ed25519). pub address_type: u8, // hex encoded address @@ -76,6 +75,8 @@ pub struct AddressBalancePair { pub address: String, /// Balance in the address pub balance: u64, + /// If dust is allowed on the address + pub dust_allowed: bool, } #[derive(Debug, Clone, DeriveFromPyObject, DeriveIntoPyObject)] @@ -94,12 +95,12 @@ pub struct MilestoneUTXOChanges { #[derive(Debug, Clone, DeriveFromPyObject, DeriveIntoPyObject)] pub struct InputDto { - pub utxo: Option, + pub utxo: Option, pub treasury: Option, } #[derive(Debug, Clone, DeriveFromPyObject, DeriveIntoPyObject)] -pub struct UTXOInput { +pub struct UtxoInput { pub transaction_id: Vec, pub index: u16, } @@ -478,9 +479,9 @@ impl From for AddressDto { } } -impl From for BalanceForAddressResponse { - fn from(balance_for_address_response: RustBalanceForAddressResponse) -> Self { - BalanceForAddressResponse { +impl From for BalanceAddressResponse { + fn from(balance_for_address_response: RustBalanceAddressResponse) -> Self { + BalanceAddressResponse { address_type: balance_for_address_response.address_type, address: balance_for_address_response.address, balance: balance_for_address_response.balance, @@ -650,7 +651,7 @@ impl TryFrom for RegularEssence { .iter() .cloned() .map(|input| { - if let RustInput::UTXO(input) = input { + if let RustInput::Utxo(input) = input { Input { transaction_id: input.output_id().transaction_id().to_string(), index: input.output_id().index(), @@ -877,10 +878,10 @@ impl TryFrom for RustRegularEssence { .inputs .iter() .map(|input| { - RustUTXOInput::new( + RustUtxoInput::new( RustTransactionId::from_str(&input.transaction_id[..]).unwrap_or_else(|_| { panic!( - "invalid UTXOInput transaction_id: {} with input index {}", + "invalid UtxoInput transaction_id: {} with input index {}", input.transaction_id, input.index ) }), @@ -888,7 +889,7 @@ impl TryFrom for RustRegularEssence { ) .unwrap_or_else(|_| { panic!( - "invalid UTXOInput transaction_id: {} with input index {}", + "invalid UtxoInput transaction_id: {} with input index {}", input.transaction_id, input.index ) }) diff --git a/examples/custom_inputs.rs b/examples/custom_inputs.rs index 640f613e8..415e0794a 100644 --- a/examples/custom_inputs.rs +++ b/examples/custom_inputs.rs @@ -14,26 +14,20 @@ use std::env; async fn main() -> Result<()> { // Create a client instance let iota = Client::builder() - .with_node("https://api.lb-0.testnet.chrysalis2.com") // Insert your node URL here - .unwrap() + .with_node("https://api.lb-0.testnet.chrysalis2.com")? // Insert your node URL here .finish() - .await - .unwrap(); + .await?; // This example uses dotenv, which is not safe for use in production dotenv().ok(); // First address from the seed below is atoi1qzt0nhsf38nh6rs4p6zs5knqp6psgha9wsv74uajqgjmwc75ugupx3y7x0r - let seed = Seed::from_bytes(&hex::decode(env::var("NONSECURE_USE_OF_DEVELOPMENT_SEED_1").unwrap()).unwrap()); + let seed = Seed::from_bytes(&hex::decode(env::var("NONSECURE_USE_OF_DEVELOPMENT_SEED_1").unwrap())?); - let addresses = iota.get_addresses(&seed).with_range(0..1).finish().await.unwrap(); + let addresses = iota.get_addresses(&seed).with_range(0..1).finish().await?; println!("{:?}", addresses[0]); - let outputs = iota - .get_address() - .outputs(&addresses[0], Default::default()) - .await - .unwrap(); + let outputs = iota.get_address().outputs(&addresses[0], Default::default()).await?; println!("{:?}", outputs); let message = iota @@ -44,11 +38,9 @@ async fn main() -> Result<()> { .with_output( "atoi1qzt0nhsf38nh6rs4p6zs5knqp6psgha9wsv74uajqgjmwc75ugupx3y7x0r", 1_000_000, - ) - .unwrap() + )? .finish() - .await - .unwrap(); + .await?; println!( "Transaction sent: https://explorer.iota.org/chrysalis/message/{}", diff --git a/examples/dust.rs b/examples/dust.rs index 19e4aa620..896b92d48 100644 --- a/examples/dust.rs +++ b/examples/dust.rs @@ -13,16 +13,14 @@ use std::env; async fn main() -> Result<()> { // Create a client instance let iota = Client::builder() - .with_node("https://api.lb-0.testnet.chrysalis2.com") // Insert your node URL here - .unwrap() + .with_node("https://api.lb-0.testnet.chrysalis2.com")? // Insert your node URL here .finish() - .await - .unwrap(); + .await?; // This example uses dotenv, which is not safe for use in production dotenv().ok(); - let seed = Seed::from_bytes(&hex::decode(env::var("NONSECURE_USE_OF_DEVELOPMENT_SEED_1").unwrap()).unwrap()); + let seed = Seed::from_bytes(&hex::decode(env::var("NONSECURE_USE_OF_DEVELOPMENT_SEED_1").unwrap())?); let message = iota .message() @@ -30,13 +28,10 @@ async fn main() -> Result<()> { .with_dust_allowance_output( &"atoi1qpnrumvaex24dy0duulp4q07lpa00w20ze6jfd0xly422kdcjxzakzsz5kf", 1_000_000, - ) - .unwrap() - .with_output(&"atoi1qpnrumvaex24dy0duulp4q07lpa00w20ze6jfd0xly422kdcjxzakzsz5kf", 1) - .unwrap() + )? + .with_output(&"atoi1qpnrumvaex24dy0duulp4q07lpa00w20ze6jfd0xly422kdcjxzakzsz5kf", 1)? .finish() - .await - .unwrap(); + .await?; println!( "First transaction sent: https://explorer.iota.org/chrysalis/message/{}", diff --git a/examples/send_all.rs b/examples/send_all.rs index 9c065a323..1a5003765 100644 --- a/examples/send_all.rs +++ b/examples/send_all.rs @@ -23,7 +23,7 @@ async fn main() -> Result<()> { // Configure your own seed in ".env". Since the output amount cannot be zero, the seed must contain non-zero balance dotenv().ok(); - let seed = Seed::from_bytes(&hex::decode(env::var("NONSECURE_USE_OF_DEVELOPMENT_SEED_2").unwrap())?); + let seed = Seed::from_bytes(&hex::decode(env::var("NONSECURE_USE_OF_DEVELOPMENT_SEED_1").unwrap())?); let total_balance = iota.get_balance(&seed).with_initial_address_index(0).finish().await?; println!("Total balance: {}", total_balance); diff --git a/examples/split_outputs_single_address.rs b/examples/split_outputs_single_address.rs index 912abe563..6de5224c9 100644 --- a/examples/split_outputs_single_address.rs +++ b/examples/split_outputs_single_address.rs @@ -3,7 +3,7 @@ //! cargo run --example split_outputs_single_address --release -use iota::{client::Result, Client, Essence, Output, Payload, Seed, UTXOInput}; +use iota::{client::Result, Client, Essence, Output, Payload, Seed, UtxoInput}; extern crate dotenv; use dotenv::dotenv; use std::env; @@ -58,7 +58,7 @@ async fn main() -> Result<()> { // Only include 1 Mi outputs, otherwise it fails for the remainder address if let Output::SignatureLockedSingle(output) = output { if output.amount() == 1_000_000 { - initial_outputs.push(UTXOInput::new(tx.id(), index as u16).unwrap()); + initial_outputs.push(UtxoInput::new(tx.id(), index as u16).unwrap()); } } } diff --git a/examples/txspam.rs b/examples/txspam.rs index 9c3ddaccf..54e9445eb 100644 --- a/examples/txspam.rs +++ b/examples/txspam.rs @@ -3,7 +3,7 @@ //! cargo run --example txspam --release -use iota::{client::Result, Client, Essence, Payload, Seed, UTXOInput}; +use iota::{client::Result, Client, Essence, Payload, Seed, UtxoInput}; extern crate dotenv; use dotenv::dotenv; use std::env; @@ -15,16 +15,14 @@ use std::env; async fn main() -> Result<()> { // Create a client instance let iota = Client::builder() - .with_node("https://api.lb-0.testnet.chrysalis2.com") // Insert your node URL here - .unwrap() + .with_node("https://api.lb-0.testnet.chrysalis2.com")? // Insert your node URL here .finish() - .await - .unwrap(); + .await?; // This example uses dotenv, which is not safe for use in production dotenv().ok(); - let seed = Seed::from_bytes(&hex::decode(env::var("NONSECURE_USE_OF_DEVELOPMENT_SEED_1").unwrap()).unwrap()); + let seed = Seed::from_bytes(&hex::decode(env::var("NONSECURE_USE_OF_DEVELOPMENT_SEED_1").unwrap())?); // Split funds to own addresses let addresses = iota @@ -32,21 +30,20 @@ async fn main() -> Result<()> { .with_account_index(0) .with_range(0..10) .finish() - .await - .unwrap(); + .await?; let mut message_builder = iota.message().with_seed(&seed); for address in &addresses { - message_builder = message_builder.with_output(address, 1_000_000).unwrap(); + message_builder = message_builder.with_output(address, 1_000_000)?; } - let message = message_builder.finish().await.unwrap(); + let message = message_builder.finish().await?; println!( "First transaction sent: https://explorer.iota.org/chrysalis/message/{}", message.id().0 ); - let _ = iota.retry_until_included(&message.id().0, None, None).await.unwrap(); + let _ = iota.retry_until_included(&message.id().0, None, None).await?; // At this point we have 10 Mi on 10 addresses and we will just send it to their addresses again // Use own outputs directly so we don't double spend them @@ -55,7 +52,7 @@ async fn main() -> Result<()> { match tx.essence() { Essence::Regular(essence) => { for (index, _output) in essence.outputs().iter().enumerate() { - initial_outputs.push(UTXOInput::new(tx.id(), index as u16).unwrap()); + initial_outputs.push(UtxoInput::new(tx.id(), index as u16)?); } } _ => { @@ -69,11 +66,9 @@ async fn main() -> Result<()> { .message() .with_seed(&seed) .with_input(initial_outputs[index].clone()) - .with_output(&address, 1_000_000) - .unwrap() + .with_output(&address, 1_000_000)? .finish() - .await - .unwrap(); + .await?; println!( "Transaction sent: https://explorer.iota.org/chrysalis/message/{}", message.id().0 diff --git a/iota-client/Cargo.toml b/iota-client/Cargo.toml index d5bcfd7c5..3b10af9a9 100644 --- a/iota-client/Cargo.toml +++ b/iota-client/Cargo.toml @@ -13,9 +13,9 @@ license = "Apache-2.0" name = "iota_client" [dependencies] -bee-rest-api = { git = "https://github.com/iotaledger/bee.git", rev = "517d26ea51c39bdd57443f5cbf9ba02555bd083d"} -bee-message = { git = "https://github.com/iotaledger/bee.git", rev = "517d26ea51c39bdd57443f5cbf9ba02555bd083d" } -bee-pow = { git = "https://github.com/iotaledger/bee.git", rev = "517d26ea51c39bdd57443f5cbf9ba02555bd083d" } +bee-rest-api = { git = "https://github.com/iotaledger/bee.git", rev = "cd6d7fa453b3350cc3bc2e82560c9595438d6ab7"} +bee-message = { git = "https://github.com/iotaledger/bee.git", rev = "cd6d7fa453b3350cc3bc2e82560c9595438d6ab7" } +bee-pow = { git = "https://github.com/iotaledger/bee.git", rev = "cd6d7fa453b3350cc3bc2e82560c9595438d6ab7" } bee-common = { git = "https://github.com/iotaledger/bee.git", branch = "dev" } bee-crypto = { git = "https://github.com/iotaledger/bee.git", rev = "c42171ff33c80cc2efb183e244dc79b7f58d9ac4" } iota-crypto = { git = "https://github.com/iotaledger/crypto.rs.git", rev = "b849861b86c3f7357b7477de4253b7352b363627", features = ["std", "blake2b", "ed25519", "random", "slip10"]} diff --git a/iota-client/src/api/message_builder.rs b/iota-client/src/api/message_builder.rs index 17007ac3d..a60364c27 100644 --- a/iota-client/src/api/message_builder.rs +++ b/iota-client/src/api/message_builder.rs @@ -38,7 +38,7 @@ pub struct ClientMessageBuilder<'a> { seed: Option<&'a Seed>, account_index: Option, initial_address_index: Option, - inputs: Option>, + inputs: Option>, input_range: Range, outputs: Vec, index: Option>, @@ -82,7 +82,7 @@ impl<'a> ClientMessageBuilder<'a> { } /// Set a custom input(transaction output) - pub fn with_input(mut self, input: UTXOInput) -> Self { + pub fn with_input(mut self, input: UtxoInput) -> Self { self.inputs = match self.inputs { Some(mut inputs) => { inputs.push(input); @@ -250,8 +250,8 @@ impl<'a> ClientMessageBuilder<'a> { internal as u32, address_index as u32, ]); - let input = Input::UTXO( - UTXOInput::new(TransactionId::from_str(&output.transaction_id)?, output.output_index) + let input = Input::Utxo( + UtxoInput::new(TransactionId::from_str(&output.transaction_id)?, output.output_index) .map_err(|_| Error::TransactionError)?, ); inputs_for_essence.push(input.clone()); @@ -343,8 +343,8 @@ impl<'a> ClientMessageBuilder<'a> { *internal as u32, address_index as u32, ]); - let input = Input::UTXO( - UTXOInput::new( + let input = Input::Utxo( + UtxoInput::new( TransactionId::from_str(&output.transaction_id)?, output.output_index, ) @@ -559,17 +559,22 @@ async fn is_dust_allowed(client: &Client, address: Address, outputs: Vec<(u64, A } } - // If we create a dust allowance and a dust output we can allow it since we can't have more outputs to the same - // address in this transaction - if dust_outputs_amount > 0 && dust_allowance_balance > 0 { - return Ok(()); - } - let bech32_hrp = client.get_bech32_hrp().await?; - // If we only create a single dust output and dust is allowed we don't need to check more outputs + let address_data = client.get_address().balance(&address.to_bech32(&bech32_hrp)).await?; - if address_data.dustAllowed && dust_outputs_amount == 1 && dust_allowance_balance >= 0 { + // If we create a dust output and a dust allowance output we don't need to check more outputs if the balance/100_000 + // is < 100 because then we are sure that we didn't reach the max dust outputs + if address_data.dust_allowed + && dust_outputs_amount == 1 + && dust_allowance_balance >= 0 + && address_data.balance / 100_000 < 100 + { return Ok(()); + } else if !address_data.dust_allowed && dust_outputs_amount == 1 && dust_allowance_balance <= 0 { + return Err(Error::DustError(format!( + "No dust output allowed on address {}", + address.to_bech32(&bech32_hrp) + ))); } // Check all outputs of the address because we want to consume a dust allowance output and don't know if we are diff --git a/iota-client/src/client.rs b/iota-client/src/client.rs index 5bfcd2e7f..5932fce16 100644 --- a/iota-client/src/client.rs +++ b/iota-client/src/client.rs @@ -9,14 +9,13 @@ use crate::{ node::*, }; use bee_common::packable::Packable; -use bee_message::prelude::{Address, Message, MessageBuilder, MessageId, Parents, TransactionId, UTXOInput}; +use bee_message::prelude::{Address, Message, MessageBuilder, MessageId, Parents, TransactionId, UtxoInput}; use bee_pow::providers::{MinerBuilder, Provider as PowProvider, ProviderBuilder as PowProviderBuilder}; use bee_rest_api::types::{ dtos::{MessageDto, PeerDto, ReceiptDto}, responses::{ - BalanceForAddressResponse, InfoResponse as NodeInfo, MilestoneResponse as MilestoneResponseDto, - MilestoneUtxoChangesResponse as MilestoneUTXOChanges, OutputResponse, ReceiptsResponse, TipsResponse, - TreasuryResponse, + BalanceAddressResponse, InfoResponse as NodeInfo, MilestoneResponse as MilestoneResponseDto, OutputResponse, + ReceiptsResponse, TipsResponse, TreasuryResponse, UtxoChangesResponse as MilestoneUTXOChanges, }, }; use crypto::{ @@ -781,7 +780,7 @@ impl Client { /// GET /api/v1/outputs/{outputId} endpoint /// Find an output by its transaction_id and corresponding output_index. - pub async fn get_output(&self, output_id: &UTXOInput) -> Result { + pub async fn get_output(&self, output_id: &UtxoInput) -> Result { let mut url = self.get_node().await?; let path = &format!( "api/v1/outputs/{}{}", @@ -806,18 +805,18 @@ impl Client { /// Find all outputs based on the requests criteria. This method will try to query multiple nodes if /// the request amount exceeds individual node limit. - pub async fn find_outputs(&self, outputs: &[UTXOInput], addresses: &[String]) -> Result> { + pub async fn find_outputs(&self, outputs: &[UtxoInput], addresses: &[String]) -> Result> { let mut output_metadata = Vec::::new(); // Use a `HashSet` to prevent duplicate output. - let mut output_to_query = HashSet::::new(); + let mut output_to_query = HashSet::::new(); - // Collect the `UTXOInput` in the HashSet. + // Collect the `UtxoInput` in the HashSet. for output in outputs { output_to_query.insert(output.to_owned()); } // Use `get_address()` API to get the address outputs first, - // then collect the `UTXOInput` in the HashSet. + // then collect the `UtxoInput` in the HashSet. for address in addresses { let address_outputs = self.get_address().outputs(&address, Default::default()).await?; for output in address_outputs.iter() { @@ -1101,7 +1100,7 @@ impl Client { /// Return the balance in iota for the given addresses; No seed or security level needed to do this /// since we are only checking and already know the addresses. - pub async fn get_address_balances(&self, addresses: &[String]) -> Result> { + pub async fn get_address_balances(&self, addresses: &[String]) -> Result> { let mut address_balance_pairs = Vec::new(); for address in addresses { let balance_response = self.get_address().balance(&address).await?; diff --git a/iota-client/src/lib.rs b/iota-client/src/lib.rs index 4a812280e..543ab1ee0 100644 --- a/iota-client/src/lib.rs +++ b/iota-client/src/lib.rs @@ -23,7 +23,7 @@ pub use bee_rest_api::{ self, types::{ dtos::{AddressDto, OutputDto}, - responses::{BalanceForAddressResponse, OutputResponse}, + responses::{BalanceAddressResponse, OutputResponse}, }, }; // pub use bee_signing_ext::{self, binary::BIP32Path,}; diff --git a/iota-client/src/node/address.rs b/iota-client/src/node/address.rs index 5258985d6..628facd84 100644 --- a/iota-client/src/node/address.rs +++ b/iota-client/src/node/address.rs @@ -3,9 +3,9 @@ use crate::{Api, Client, Error, Result}; -use bee_message::prelude::{TransactionId, UTXOInput}; +use bee_message::prelude::{TransactionId, UtxoInput}; -use bee_rest_api::types::responses::{BalanceForAddressResponse, OutputsForAddressResponse}; +use bee_rest_api::types::responses::{BalanceAddressResponse, OutputsAddressResponse}; use std::convert::TryInto; @@ -70,14 +70,14 @@ impl<'a> GetAddressBuilder<'a> { /// Consume the builder and get the balance of a given Bech32 encoded address. /// If count equals maxResults, then there might be more outputs available but those were skipped for performance /// reasons. User should sweep the address to reduce the amount of outputs. - pub async fn balance(self, address: &str) -> Result { + pub async fn balance(self, address: &str) -> Result { let mut url = self.client.get_node().await?; let path = &format!("api/v1/addresses/{}", address); url.set_path(path); #[derive(Debug, Serialize, Deserialize)] struct ResponseWrapper { - data: BalanceForAddressResponse, + data: BalanceAddressResponse, } let resp: ResponseWrapper = self .client @@ -93,7 +93,7 @@ impl<'a> GetAddressBuilder<'a> { /// Consume the builder and get all outputs that use a given address. /// If count equals maxResults, then there might be more outputs available but those were skipped for performance /// reasons. User should sweep the address to reduce the amount of outputs. - pub async fn outputs(self, address: &str, options: OutputsOptions) -> Result> { + pub async fn outputs(self, address: &str, options: OutputsOptions) -> Result> { let mut url = self.client.get_node().await?; let path = &format!("api/v1/addresses/{}/outputs", address); url.set_path(path); @@ -101,7 +101,7 @@ impl<'a> GetAddressBuilder<'a> { #[derive(Debug, Serialize, Deserialize)] struct ResponseWrapper { - data: OutputsForAddressResponse, + data: OutputsAddressResponse, } let resp: ResponseWrapper = self @@ -124,11 +124,11 @@ impl<'a> GetAddressBuilder<'a> { .try_into() .map_err(|_| Error::InvalidParameter("index"))?, ); - Ok(UTXOInput::new(TransactionId::new(transaction_id), index)?) + Ok(UtxoInput::new(TransactionId::new(transaction_id), index)?) } else { Err(Error::OutputError("Invalid output length from API response")) } }) - .collect::>>() + .collect::>>() } } diff --git a/iota-client/src/node/message.rs b/iota-client/src/node/message.rs index 6699322f6..6e93b9182 100644 --- a/iota-client/src/node/message.rs +++ b/iota-client/src/node/message.rs @@ -5,7 +5,7 @@ use crate::{Api, Client, Result}; use bee_message::{Message, MessageId}; use bee_rest_api::types::{ dtos::MessageDto, - responses::{MessageChildrenResponse, MessageMetadataResponse as MessageMetadata, MessagesForIndexResponse}, + responses::{MessageChildrenResponse, MessageMetadataResponse as MessageMetadata, MessagesFindResponse}, }; use std::convert::TryFrom; @@ -31,7 +31,7 @@ impl<'a> GetMessageBuilder<'a> { #[derive(Debug, Serialize, Deserialize)] struct ResponseWrapper { - data: MessagesForIndexResponse, + data: MessagesFindResponse, } let resp: ResponseWrapper = self .client diff --git a/iota-client/tests/node_api.rs b/iota-client/tests/node_api.rs index d270fecda..368a15152 100644 --- a/iota-client/tests/node_api.rs +++ b/iota-client/tests/node_api.rs @@ -253,7 +253,7 @@ async fn test_get_output() { .await .unwrap() .get_output( - &UTXOInput::new( + &UtxoInput::new( TransactionId::from_str("0000000000000000000000000000000000000000000000000000000000000000").unwrap(), 0, ) diff --git a/iota-core/Cargo.toml b/iota-core/Cargo.toml index 4a8c4d4aa..0af08de33 100644 --- a/iota-core/Cargo.toml +++ b/iota-core/Cargo.toml @@ -12,8 +12,8 @@ homepage = "https://iota.org" name = "iota" [dependencies] -bee-message = { git = "https://github.com/iotaledger/bee.git", rev = "517d26ea51c39bdd57443f5cbf9ba02555bd083d" } -bee-pow = { git = "https://github.com/iotaledger/bee.git", rev = "517d26ea51c39bdd57443f5cbf9ba02555bd083d" } +bee-message = { git = "https://github.com/iotaledger/bee.git", rev = "cd6d7fa453b3350cc3bc2e82560c9595438d6ab7" } +bee-pow = { git = "https://github.com/iotaledger/bee.git", rev = "cd6d7fa453b3350cc3bc2e82560c9595438d6ab7" } bee-common = { git = "https://github.com/iotaledger/bee.git", rev = "c42171ff33c80cc2efb183e244dc79b7f58d9ac4" } iota-client = { version = "0.5.0-alpha", path = "../iota-client", default-features = false } diff --git a/specs/iota-rs-ENGINEERING-SPEC-0000.md b/specs/iota-rs-ENGINEERING-SPEC-0000.md index 6510567ea..6929291cf 100644 --- a/specs/iota-rs-ENGINEERING-SPEC-0000.md +++ b/specs/iota-rs-ENGINEERING-SPEC-0000.md @@ -118,7 +118,7 @@ A generic send function for easily sending a message. | **seed** | ✘ | None | [Seed] | The seed of the account we are going to spend, only needed for transactions | | **account_index** | ✘ | 0 | usize | The account index, responsible for the value `✘` in the Bip32Path `m/44'/4218'/✘'/0'/0'`. | | **initial_address_index** | ✘ | 0 | usize | The index from where to start looking for balance. Responsible for the value `✘` in the Bip32Path `m/44'/4218'/0'/0'/✘'`. | -| **input** | ✘ | None | UTXOInput | Users can manually select their UTXOInputs instead of having automatically selected inputs. | +| **input** | ✘ | None | UtxoInput | Users can manually select their UtxoInputs instead of having automatically selected inputs. | | **input_range** | ✘ | 0..100 | Range | Custom range to search for the input addresses if custom inputs are provided. | | **output** | ✘ | None | address: &[String],
amount: u64 | Address to send to and amount to send. Address needs to be Bech32 encoded. | | **output_hex** | ✘ | None | address: &str,
amount: u64 | Address to send to and amount to send. Address needs to be hex encoded. | @@ -500,7 +500,7 @@ Get the producer of the output, the corresponding address, amount and spend stat | Parameter | Required | Type | Definition | | - | - | - | - | -| **output_id** | ✔ | UTXOInput | Identifier of the output. | +| **output_id** | ✔ | UtxoInput | Identifier of the output. | ### Returns @@ -521,7 +521,7 @@ An [OutputMetadata](#OutputMetadata) that contains various information about the Depend on the final calling method, users could get different outputs they need: * `balance()`: Return confirmed balance of the address. -* `outputs([options])`: Return UTXOInput array (transaction IDs with corresponding output index). +* `outputs([options])`: Return UtxoInput array (transaction IDs with corresponding output index). ## `find_outputs()` @@ -531,7 +531,7 @@ Find all outputs based on the requests criteria. | Parameter | Required | Type | Definition | | - | - | - | - | -| **output_id** | ✘ | [UTXOInput] | The identifier of output. | +| **output_id** | ✘ | [UtxoInput] | The identifier of output. | | **addresses** | ✘ | [[String]] | The Bech32 encoded address. | ### Returns @@ -706,7 +706,7 @@ struct TransactionPayloadEssence { } enum Input { - UTXO(UTXOInput(OutputId)), + UTXO(UtxoInput(OutputId)), } struct OutputId { @@ -808,6 +808,8 @@ pub struct AddressBalancePair { pub address: String, /// Balance in the address pub balance: u64, + /// If dust is allowed on the address + pub dust_allowed: bool, } ```