From 13a7f81475a3bf40405ea156ec8dfdbd19c23e58 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 18 Oct 2023 11:57:22 -0400 Subject: [PATCH 01/20] add client + secret manager methods --- bindings/core/src/lib.rs | 7 +- bindings/core/src/method/client.rs | 7 +- bindings/core/src/method/client_secret.rs | 25 ++++++ bindings/core/src/method/mod.rs | 5 +- .../core/src/method_handler/call_method.rs | 42 ++++++++-- bindings/core/src/method_handler/client.rs | 22 +---- .../core/src/method_handler/client_secret.rs | 50 ++++++++++++ bindings/core/src/method_handler/mod.rs | 4 +- .../core/src/method_handler/secret_manager.rs | 80 ++++++++++++++----- bindings/core/tests/combined.rs | 69 +++++++++++++++- bindings/core/tests/secrets_manager.rs | 11 +-- bindings/nodejs/src/secret_manager.rs | 5 +- bindings/python/src/secret_manager.rs | 6 +- bindings/wasm/src/secret_manager.rs | 5 +- .../client/block/00_block_no_payload.rs | 15 ++-- .../block/01_block_confirmation_time.rs | 12 +-- .../client/block/02_block_custom_parents.rs | 10 ++- .../client/block/03_block_custom_payload.rs | 10 ++- .../client/block/04_block_tagged_data.rs | 10 ++- .../client/node_api_core/04_post_block.rs | 15 ++-- .../client/node_api_core/05_post_block_raw.rs | 15 ++-- sdk/src/types/block/macro.rs | 8 +- sdk/tests/client/node_api/mod.rs | 6 +- 23 files changed, 316 insertions(+), 123 deletions(-) create mode 100644 bindings/core/src/method/client_secret.rs create mode 100644 bindings/core/src/method_handler/client_secret.rs diff --git a/bindings/core/src/lib.rs b/bindings/core/src/lib.rs index 75ab8c4288..9e9f1f408b 100644 --- a/bindings/core/src/lib.rs +++ b/bindings/core/src/lib.rs @@ -26,8 +26,11 @@ pub use self::method_handler::listen_mqtt; pub use self::method_handler::CallMethod; pub use self::{ error::{Error, Result}, - method::{AccountMethod, ClientMethod, SecretManagerMethod, UtilsMethod, WalletMethod}, - method_handler::{call_client_method, call_secret_manager_method, call_utils_method, call_wallet_method}, + method::{AccountMethod, ClientMethod, ClientSecretMethod, SecretManagerMethod, UtilsMethod, WalletMethod}, + method_handler::{ + call_client_method, call_client_secret_method, call_secret_manager_method, call_utils_method, + call_wallet_method, + }, response::Response, }; diff --git a/bindings/core/src/method/client.rs b/bindings/core/src/method/client.rs index 3488f4f04e..e175fd3bba 100644 --- a/bindings/core/src/method/client.rs +++ b/bindings/core/src/method/client.rs @@ -12,7 +12,7 @@ use iota_sdk::{ dto::OutputDto, feature::Feature, unlock_condition::dto::UnlockConditionDto, AccountId, FoundryId, NativeToken, NftId, OutputId, TokenScheme, }, - payload::{dto::PayloadDto, transaction::TransactionId}, + payload::transaction::TransactionId, BlockId, BlockWrapperDto, }, utils::serde::{option_string, string}, @@ -122,11 +122,6 @@ pub enum ClientMethod { query_params: Vec, request_object: Option, }, - /// Build a block containing the specified payload and post it to the network. - PostBlockPayload { - /// The payload to send - payload: PayloadDto, - }, ////////////////////////////////////////////////////////////////////// // Node core API ////////////////////////////////////////////////////////////////////// diff --git a/bindings/core/src/method/client_secret.rs b/bindings/core/src/method/client_secret.rs new file mode 100644 index 0000000000..34baf9c770 --- /dev/null +++ b/bindings/core/src/method/client_secret.rs @@ -0,0 +1,25 @@ +// Copyright 2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use crypto::keys::bip44::Bip44; +use derivative::Derivative; +use iota_sdk::types::block::{core::basic, payload::dto::PayloadDto, IssuerId}; +use serde::{Deserialize, Serialize}; + +/// Each public client + secret manager method. +#[derive(Clone, Derivative, Serialize, Deserialize)] +#[derivative(Debug)] +#[serde(tag = "name", content = "data", rename_all = "camelCase")] +#[non_exhaustive] +pub enum ClientSecretMethod { + /// Build a basic block containing the specified payload and post it to the network. + PostBasicBlockPayload { + /// The issuer's ID. + issuer_id: IssuerId, + strong_parents: Option, + /// The payload to send. + payload: PayloadDto, + /// The Bip44 chain to use when signing the block. + chain: Bip44, + }, +} diff --git a/bindings/core/src/method/mod.rs b/bindings/core/src/method/mod.rs index 966b583013..dfe40fdb62 100644 --- a/bindings/core/src/method/mod.rs +++ b/bindings/core/src/method/mod.rs @@ -3,11 +3,12 @@ mod account; mod client; +mod client_secret; mod secret_manager; mod utils; mod wallet; pub use self::{ - account::AccountMethod, client::ClientMethod, secret_manager::SecretManagerMethod, utils::UtilsMethod, - wallet::WalletMethod, + account::AccountMethod, client::ClientMethod, client_secret::ClientSecretMethod, + secret_manager::SecretManagerMethod, utils::UtilsMethod, wallet::WalletMethod, }; diff --git a/bindings/core/src/method_handler/call_method.rs b/bindings/core/src/method_handler/call_method.rs index b0202468a1..1a1ec27893 100644 --- a/bindings/core/src/method_handler/call_method.rs +++ b/bindings/core/src/method_handler/call_method.rs @@ -5,16 +5,19 @@ use std::pin::Pin; use futures::Future; use iota_sdk::{ - client::{secret::SecretManager, Client}, + client::{ + secret::{DowncastSecretManager, SecretManage}, + Client, + }, wallet::Wallet, }; -use tokio::sync::RwLock; use crate::{ - method::{ClientMethod, SecretManagerMethod, WalletMethod}, + method::{ClientMethod, ClientSecretMethod, SecretManagerMethod, WalletMethod}, method_handler::{ - client::call_client_method_internal, secret_manager::call_secret_manager_method_internal, - utils::call_utils_method_internal, wallet::call_wallet_method_internal, + client::call_client_method_internal, client_secret::call_client_secret_method_internal, + secret_manager::call_secret_manager_method_internal, utils::call_utils_method_internal, + wallet::call_wallet_method_internal, }, panic::{convert_async_panics, convert_panics}, response::Response, @@ -78,10 +81,13 @@ pub fn call_utils_method(method: UtilsMethod) -> Response { } /// Call a secret manager method. -pub async fn call_secret_manager_method( - secret_manager: &RwLock, +pub async fn call_secret_manager_method( + secret_manager: &S, method: SecretManagerMethod, -) -> Response { +) -> Response +where + iota_sdk::client::Error: From, +{ log::debug!("Secret manager method: {method:?}"); let result = convert_async_panics(|| async { call_secret_manager_method_internal(secret_manager, method).await }).await; @@ -91,3 +97,23 @@ pub async fn call_secret_manager_method( log::debug!("Secret manager response: {response:?}"); response } + +/// Call a client + secret manager method. +pub async fn call_client_secret_method( + client: &Client, + secret_manager: &S, + method: ClientSecretMethod, +) -> Response +where + iota_sdk::client::Error: From, +{ + log::debug!("Client method: {method:?}"); + let result = + convert_async_panics(|| async { call_client_secret_method_internal(client, secret_manager, method).await }) + .await; + + let response = result.unwrap_or_else(Response::Error); + + log::debug!("Client response: {response:?}"); + response +} diff --git a/bindings/core/src/method_handler/client.rs b/bindings/core/src/method_handler/client.rs index 5c1845d46d..6cdffdb633 100644 --- a/bindings/core/src/method_handler/client.rs +++ b/bindings/core/src/method_handler/client.rs @@ -4,14 +4,13 @@ #[cfg(feature = "mqtt")] use iota_sdk::client::mqtt::{MqttPayload, Topic}; use iota_sdk::{ - client::{request_funds_from_faucet, secret::SecretManager, Client}, + client::{request_funds_from_faucet, Client}, types::{ api::core::response::OutputWithMetadataResponse, block::{ output::{ dto::OutputDto, AccountOutput, BasicOutput, FoundryOutput, NftOutput, Output, OutputBuilderAmount, Rent, }, - payload::Payload, BlockWrapper, BlockWrapperDto, }, TryFromDto, @@ -171,25 +170,6 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM ClientMethod::GetNetworkId => Response::NetworkId(client.get_network_id().await?.to_string()), ClientMethod::GetBech32Hrp => Response::Bech32Hrp(client.get_bech32_hrp().await?), ClientMethod::GetProtocolParameters => Response::ProtocolParameters(client.get_protocol_parameters().await?), - ClientMethod::PostBlockPayload { payload } => { - let block = client - .build_basic_block::( - todo!("issuer id"), - todo!("issuing time"), - None, - Some(Payload::try_from_dto_with_params( - payload, - &client.get_protocol_parameters().await?, - )?), - todo!("secret manager"), - todo!("chain"), - ) - .await?; - - let block_id = client.block_id(&block).await?; - - Response::BlockIdWithBlock(block_id, BlockWrapperDto::from(&block)) - } #[cfg(not(target_family = "wasm"))] ClientMethod::UnhealthyNodes => Response::UnhealthyNodes(client.unhealthy_nodes().await.into_iter().collect()), ClientMethod::GetHealth { url } => Response::Bool(client.get_health(&url).await?), diff --git a/bindings/core/src/method_handler/client_secret.rs b/bindings/core/src/method_handler/client_secret.rs new file mode 100644 index 0000000000..25f9e3ec42 --- /dev/null +++ b/bindings/core/src/method_handler/client_secret.rs @@ -0,0 +1,50 @@ +// Copyright 2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_sdk::{ + client::{secret::SecretManage, Client}, + types::{ + block::{payload::Payload, BlockWrapperDto}, + TryFromDto, + }, +}; + +use crate::{method::ClientSecretMethod, Response, Result}; + +/// Call a secret manager method. +pub(crate) async fn call_client_secret_method_internal( + client: &Client, + secret_manager: &S, + method: ClientSecretMethod, +) -> Result +where + iota_sdk::client::Error: From, +{ + let response = match method { + ClientSecretMethod::PostBasicBlockPayload { + issuer_id, + strong_parents, + payload, + chain, + } => { + let block = client + .build_basic_block( + issuer_id, + None, + strong_parents, + Some(Payload::try_from_dto_with_params( + payload, + &client.get_protocol_parameters().await?, + )?), + secret_manager, + chain, + ) + .await?; + + let block_id = client.block_id(&block).await?; + + Response::BlockIdWithBlock(block_id, BlockWrapperDto::from(&block)) + } + }; + Ok(response) +} diff --git a/bindings/core/src/method_handler/mod.rs b/bindings/core/src/method_handler/mod.rs index 49be54cf5e..340ff728ce 100644 --- a/bindings/core/src/method_handler/mod.rs +++ b/bindings/core/src/method_handler/mod.rs @@ -4,12 +4,14 @@ mod account; mod call_method; mod client; +mod client_secret; mod secret_manager; mod utils; mod wallet; pub use call_method::{ - call_client_method, call_secret_manager_method, call_utils_method, call_wallet_method, CallMethod, + call_client_method, call_client_secret_method, call_secret_manager_method, call_utils_method, call_wallet_method, + CallMethod, }; #[cfg(feature = "mqtt")] pub use client::listen_mqtt; diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index ff26572766..d6f559684e 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -3,33 +3,69 @@ use iota_sdk::{ client::{ - api::PreparedTransactionData, - secret::{SecretManage, SecretManager}, + api::{GetAddressesOptions, PreparedTransactionData}, + secret::{ + ledger_nano::LedgerSecretManager, stronghold::StrongholdSecretManager, DowncastSecretManager, SecretManage, + }, + }, + types::{ + block::{address::ToBech32Ext, unlock::Unlock}, + TryFromDto, }, - types::{block::unlock::Unlock, TryFromDto}, }; -use tokio::sync::RwLock; use crate::{method::SecretManagerMethod, response::Response, Result}; /// Call a secret manager method. -pub(crate) async fn call_secret_manager_method_internal( - secret_manager: &RwLock, +pub(crate) async fn call_secret_manager_method_internal( + secret_manager: &S, method: SecretManagerMethod, -) -> Result { - let secret_manager = secret_manager.read().await; +) -> Result +where + iota_sdk::client::Error: From, +{ let response = match method { - SecretManagerMethod::GenerateEd25519Addresses { options } => { - let addresses = secret_manager.generate_ed25519_addresses(options).await?; + SecretManagerMethod::GenerateEd25519Addresses { + options: + GetAddressesOptions { + coin_type, + account_index, + range, + bech32_hrp, + options, + }, + } => { + let addresses = secret_manager + .generate_ed25519_addresses(coin_type, account_index, range, options) + .await + .map_err(iota_sdk::client::Error::from)? + .into_iter() + .map(|a| a.to_bech32(bech32_hrp)) + .collect(); Response::GeneratedEd25519Addresses(addresses) } - SecretManagerMethod::GenerateEvmAddresses { options } => { - let addresses = secret_manager.generate_evm_addresses(options).await?; + SecretManagerMethod::GenerateEvmAddresses { + options: + GetAddressesOptions { + coin_type, + account_index, + range, + bech32_hrp: _, + options, + }, + } => { + let addresses = secret_manager + .generate_evm_addresses(coin_type, account_index, range, options) + .await + .map_err(iota_sdk::client::Error::from)? + .into_iter() + .map(|a| prefix_hex::encode(a.as_ref())) + .collect(); Response::GeneratedEvmAddresses(addresses) } #[cfg(feature = "ledger_nano")] SecretManagerMethod::GetLedgerNanoStatus => { - if let SecretManager::LedgerNano(secret_manager) = &*secret_manager { + if let Some(secret_manager) = secret_manager.downcast::() { Response::LedgerNanoStatus(secret_manager.get_ledger_nano_status().await) } else { return Err(iota_sdk::client::Error::SecretManagerMismatch.into()); @@ -40,7 +76,8 @@ pub(crate) async fn call_secret_manager_method_internal( } => { let transaction = &secret_manager .sign_transaction(PreparedTransactionData::try_from_dto(prepared_transaction_data)?) - .await?; + .await + .map_err(iota_sdk::client::Error::from)?; Response::SignedTransaction(transaction.into()) } SecretManagerMethod::SignatureUnlock { @@ -50,18 +87,25 @@ pub(crate) async fn call_secret_manager_method_internal( let transaction_essence_hash: [u8; 32] = prefix_hex::decode(transaction_essence_hash)?; let unlock: Unlock = secret_manager .signature_unlock(&transaction_essence_hash, chain) - .await?; + .await + .map_err(iota_sdk::client::Error::from)?; Response::SignatureUnlock(unlock) } SecretManagerMethod::SignEd25519 { message, chain } => { let msg: Vec = prefix_hex::decode(message)?; - let signature = secret_manager.sign_ed25519(&msg, chain).await?; + let signature = secret_manager + .sign_ed25519(&msg, chain) + .await + .map_err(iota_sdk::client::Error::from)?; Response::Ed25519Signature(signature) } SecretManagerMethod::SignSecp256k1Ecdsa { message, chain } => { let msg: Vec = prefix_hex::decode(message)?; - let (public_key, signature) = secret_manager.sign_secp256k1_ecdsa(&msg, chain).await?; + let (public_key, signature) = secret_manager + .sign_secp256k1_ecdsa(&msg, chain) + .await + .map_err(iota_sdk::client::Error::from)?; Response::Secp256k1EcdsaSignature { public_key: prefix_hex::encode(public_key.to_bytes()), signature: prefix_hex::encode(signature.to_bytes()), @@ -70,7 +114,7 @@ pub(crate) async fn call_secret_manager_method_internal( #[cfg(feature = "stronghold")] SecretManagerMethod::StoreMnemonic { mnemonic } => { let mnemonic = crypto::keys::bip39::Mnemonic::from(mnemonic); - if let SecretManager::Stronghold(secret_manager) = &*secret_manager { + if let Some(secret_manager) = secret_manager.downcast::() { secret_manager.store_mnemonic(mnemonic).await?; Response::Ok } else { diff --git a/bindings/core/tests/combined.rs b/bindings/core/tests/combined.rs index 97c8ea9109..c014a1e3a9 100644 --- a/bindings/core/tests/combined.rs +++ b/bindings/core/tests/combined.rs @@ -3,11 +3,26 @@ use std::collections::BTreeMap; +use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::SHIMMER_COIN_TYPE, secret::SecretManagerDto, ClientBuilder}, + client::{ + constants::{IOTA_COIN_TYPE, SHIMMER_COIN_TYPE}, + secret::{mnemonic::MnemonicSecretManager, SecretManagerDto}, + ClientBuilder, + }, + types::{ + block::{ + payload::{dto::PayloadDto, Payload, TaggedDataPayload}, + BlockDto, BlockWrapper, IssuerId, + }, + TryFromDto, + }, wallet::account::types::AccountIdentifier, }; -use iota_sdk_bindings_core::{AccountMethod, CallMethod, Response, Result, WalletMethod, WalletOptions}; +use iota_sdk_bindings_core::{ + call_client_secret_method, AccountMethod, CallMethod, ClientSecretMethod, Response, Result, WalletMethod, + WalletOptions, +}; #[tokio::test] async fn create_account() -> Result<()> { @@ -232,3 +247,53 @@ async fn client_from_wallet() -> Result<()> { std::fs::remove_dir_all(storage_path).ok(); Ok(()) } + +#[tokio::test] +async fn post_block() -> Result<()> { + let storage_path = "test-storage/client_from_wallet"; + std::fs::remove_dir_all(storage_path).ok(); + + let secret_manager = MnemonicSecretManager::try_from_mnemonic( + "about solution utility exist rail budget vacuum major survey clerk pave ankle wealth gym gossip still medal expect strong rely amazing inspire lazy lunar", + ).unwrap(); + let client = ClientBuilder::default() + .with_nodes(&["http://localhost:14265"]) + .unwrap() + .finish() + .await + .unwrap(); + + let payload = PayloadDto::from(&Payload::from( + TaggedDataPayload::new("Hello".as_bytes(), "Tangle".as_bytes()).unwrap(), + )); + + let response = call_client_secret_method( + &client, + &secret_manager, + ClientSecretMethod::PostBasicBlockPayload { + issuer_id: IssuerId::null(), + strong_parents: None, + payload: payload.clone(), + chain: Bip44::new(IOTA_COIN_TYPE), + }, + ) + .await; + + match response { + Response::BlockIdWithBlock(block_id, block) => { + match &block.block { + BlockDto::Basic(b) => assert_eq!(b.payload, Some(payload)), + BlockDto::Validation(v) => panic!("unexpected block {v:?}"), + } + assert_eq!( + block_id, + BlockWrapper::try_from_dto(block) + .unwrap() + .id(&client.get_protocol_parameters().await.unwrap()) + ); + } + _ => panic!("unexpected response {response:?}"), + } + + Ok(()) +} diff --git a/bindings/core/tests/secrets_manager.rs b/bindings/core/tests/secrets_manager.rs index 7ff91e891f..1a251cf54a 100644 --- a/bindings/core/tests/secrets_manager.rs +++ b/bindings/core/tests/secrets_manager.rs @@ -1,17 +1,14 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use std::sync::Arc; - use iota_sdk::client::{api::GetAddressesOptions, constants::ETHER_COIN_TYPE, secret::SecretManager}; use iota_sdk_bindings_core::{call_secret_manager_method, Response, Result, SecretManagerMethod}; -use tokio::sync::RwLock; #[tokio::test] async fn generate_ed25519_addresses() -> Result<()> { - let secret_manager = Arc::new(RwLock::new(SecretManager::try_from_mnemonic( + let secret_manager = SecretManager::try_from_mnemonic( "endorse answer radar about source reunion marriage tag sausage weekend frost daring base attack because joke dream slender leisure group reason prepare broken river".to_owned(), - )?)); + )?; let method = SecretManagerMethod::GenerateEd25519Addresses { options: GetAddressesOptions::default().with_range(0..1), @@ -31,9 +28,9 @@ async fn generate_ed25519_addresses() -> Result<()> { #[tokio::test] async fn generate_evm_addresses() -> Result<()> { - let secret_manager = Arc::new(RwLock::new(SecretManager::try_from_mnemonic( + let secret_manager = SecretManager::try_from_mnemonic( "endorse answer radar about source reunion marriage tag sausage weekend frost daring base attack because joke dream slender leisure group reason prepare broken river".to_owned(), - )?)); + )?; let method = SecretManagerMethod::GenerateEvmAddresses { options: GetAddressesOptions::default() diff --git a/bindings/nodejs/src/secret_manager.rs b/bindings/nodejs/src/secret_manager.rs index 7c5531638f..cc134ebbe0 100644 --- a/bindings/nodejs/src/secret_manager.rs +++ b/bindings/nodejs/src/secret_manager.rs @@ -42,7 +42,10 @@ impl SecretManagerMethodHandler { async fn call_method(&self, method: String) -> (String, bool) { match serde_json::from_str::(&method) { Ok(method) => { - let res = rust_call_secret_manager_method(&self.secret_manager, method).await; + let res = { + let secret_manager = self.secret_manager.read().await; + rust_call_secret_manager_method(&*secret_manager, method).await + }; let mut is_err = matches!(res, Response::Error(_) | Response::Panic(_)); let msg = match serde_json::to_string(&res) { diff --git a/bindings/python/src/secret_manager.rs b/bindings/python/src/secret_manager.rs index a1bbadf1a2..18af2f17f0 100644 --- a/bindings/python/src/secret_manager.rs +++ b/bindings/python/src/secret_manager.rs @@ -31,8 +31,10 @@ pub fn create_secret_manager(options: String) -> Result { #[pyfunction] pub fn call_secret_manager_method(secret_manager: &SecretManager, method: String) -> Result { let method = serde_json::from_str::(&method)?; - let response = - crate::block_on(async { rust_call_secret_manager_method(&secret_manager.secret_manager, method).await }); + let response = crate::block_on(async { + let secret_manager = secret_manager.secret_manager.read().await; + rust_call_secret_manager_method(&*secret_manager, method).await + }); Ok(serde_json::to_string(&response)?) } diff --git a/bindings/wasm/src/secret_manager.rs b/bindings/wasm/src/secret_manager.rs index ab08a2b2df..f60e6aa4d1 100644 --- a/bindings/wasm/src/secret_manager.rs +++ b/bindings/wasm/src/secret_manager.rs @@ -45,7 +45,10 @@ pub fn call_secret_manager_method_async( let promise: js_sys::Promise = future_to_promise(async move { let method: SecretManagerMethod = serde_json::from_str(&method).map_err(|err| err.to_string())?; - let response = call_secret_manager_method(&secret_manager, method).await; + let response = { + let secret_manager = secret_manager.read().await; + call_secret_manager_method(&*secret_manager, method).await + }; let ser = JsValue::from(serde_json::to_string(&response).map_err(|err| err.to_string())?); match response { Response::Error(_) | Response::Panic(_) => Err(ser), diff --git a/sdk/examples/client/block/00_block_no_payload.rs b/sdk/examples/client/block/00_block_no_payload.rs index ce029516bc..337fa799d3 100644 --- a/sdk/examples/client/block/00_block_no_payload.rs +++ b/sdk/examples/client/block/00_block_no_payload.rs @@ -9,7 +9,10 @@ //! ``` use crypto::keys::bip44::Bip44; -use iota_sdk::client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}; +use iota_sdk::{ + client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, + types::block::IssuerId, +}; #[tokio::main] async fn main() -> Result<()> { @@ -17,6 +20,7 @@ async fn main() -> Result<()> { dotenvy::dotenv().ok(); let node_url = std::env::var("NODE_URL").unwrap(); + let issuer_id = std::env::var("ISSUER_ID").unwrap().parse::().unwrap(); // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; @@ -25,14 +29,7 @@ async fn main() -> Result<()> { // Create and send the block. let block = client - .build_basic_block( - todo!("issuer id"), - todo!("issuing time"), - None, - None, - &secret_manager, - Bip44::new(IOTA_COIN_TYPE), - ) + .build_basic_block(issuer_id, None, None, None, &secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; println!("{block:#?}"); diff --git a/sdk/examples/client/block/01_block_confirmation_time.rs b/sdk/examples/client/block/01_block_confirmation_time.rs index 6b6b961dc8..97e65f7912 100644 --- a/sdk/examples/client/block/01_block_confirmation_time.rs +++ b/sdk/examples/client/block/01_block_confirmation_time.rs @@ -11,7 +11,7 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, - types::api::core::response::BlockState, + types::{api::core::response::BlockState, block::IssuerId}, }; #[tokio::main] @@ -20,6 +20,7 @@ async fn main() -> Result<()> { dotenvy::dotenv().ok(); let node_url = std::env::var("NODE_URL").unwrap(); + let issuer_id = std::env::var("ISSUER_ID").unwrap().parse::().unwrap(); // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; @@ -28,14 +29,7 @@ async fn main() -> Result<()> { // Create and send a block. let block = client - .build_basic_block( - todo!("issuer id"), - todo!("issuing time"), - None, - None, - &secret_manager, - Bip44::new(IOTA_COIN_TYPE), - ) + .build_basic_block(issuer_id, None, None, None, &secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; let block_id = client.block_id(&block).await?; diff --git a/sdk/examples/client/block/02_block_custom_parents.rs b/sdk/examples/client/block/02_block_custom_parents.rs index 2a01e8f95b..88b607e2d9 100644 --- a/sdk/examples/client/block/02_block_custom_parents.rs +++ b/sdk/examples/client/block/02_block_custom_parents.rs @@ -9,7 +9,10 @@ //! ``` use crypto::keys::bip44::Bip44; -use iota_sdk::client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}; +use iota_sdk::{ + client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, + types::block::IssuerId, +}; #[tokio::main] async fn main() -> Result<()> { @@ -17,6 +20,7 @@ async fn main() -> Result<()> { dotenvy::dotenv().ok(); let node_url = std::env::var("NODE_URL").unwrap(); + let issuer_id = std::env::var("ISSUER_ID").unwrap().parse::().unwrap(); // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; @@ -30,8 +34,8 @@ async fn main() -> Result<()> { // Create and send the block with custom parents. let block = client .build_basic_block( - todo!("issuer id"), - todo!("issuing time"), + issuer_id, + None, Some(issuance.strong_parents()?), None, &secret_manager, diff --git a/sdk/examples/client/block/03_block_custom_payload.rs b/sdk/examples/client/block/03_block_custom_payload.rs index b27c5a289c..5bfe3853be 100644 --- a/sdk/examples/client/block/03_block_custom_payload.rs +++ b/sdk/examples/client/block/03_block_custom_payload.rs @@ -11,7 +11,10 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, - types::block::payload::{Payload, TaggedDataPayload}, + types::block::{ + payload::{Payload, TaggedDataPayload}, + IssuerId, + }, }; #[tokio::main] @@ -20,6 +23,7 @@ async fn main() -> Result<()> { dotenvy::dotenv().ok(); let node_url = std::env::var("NODE_URL").unwrap(); + let issuer_id = std::env::var("ISSUER_ID").unwrap().parse::().unwrap(); // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; @@ -32,8 +36,8 @@ async fn main() -> Result<()> { // Create and send the block with the custom payload. let block = client .build_basic_block( - todo!("issuer id"), - todo!("issuing time"), + issuer_id, + None, None, Some(Payload::from(tagged_data_payload)), &secret_manager, diff --git a/sdk/examples/client/block/04_block_tagged_data.rs b/sdk/examples/client/block/04_block_tagged_data.rs index 2fc25aa84f..736c47fd9d 100644 --- a/sdk/examples/client/block/04_block_tagged_data.rs +++ b/sdk/examples/client/block/04_block_tagged_data.rs @@ -11,7 +11,10 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, - types::block::payload::{Payload, TaggedDataPayload}, + types::block::{ + payload::{Payload, TaggedDataPayload}, + IssuerId, + }, }; #[tokio::main] @@ -20,6 +23,7 @@ async fn main() -> Result<()> { dotenvy::dotenv().ok(); let node_url = std::env::var("NODE_URL").unwrap(); + let issuer_id = std::env::var("ISSUER_ID").unwrap().parse::().unwrap(); // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; @@ -29,8 +33,8 @@ async fn main() -> Result<()> { // Create and send the block with tag and data. let block = client .build_basic_block( - todo!("issuer id"), - todo!("issuing time"), + issuer_id, + None, None, Some(Payload::TaggedData(Box::new( TaggedDataPayload::new( diff --git a/sdk/examples/client/node_api_core/04_post_block.rs b/sdk/examples/client/node_api_core/04_post_block.rs index 414e3ca7cf..f29da0eb40 100644 --- a/sdk/examples/client/node_api_core/04_post_block.rs +++ b/sdk/examples/client/node_api_core/04_post_block.rs @@ -9,7 +9,10 @@ //! ``` use crypto::keys::bip44::Bip44; -use iota_sdk::client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}; +use iota_sdk::{ + client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, + types::block::IssuerId, +}; #[tokio::main] async fn main() -> Result<()> { @@ -20,6 +23,7 @@ async fn main() -> Result<()> { let node_url = std::env::args() .nth(1) .unwrap_or_else(|| std::env::var("NODE_URL").unwrap()); + let issuer_id = std::env::var("ISSUER_ID").unwrap().parse::().unwrap(); // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; @@ -28,14 +32,7 @@ async fn main() -> Result<()> { // Create the block. let block = client - .build_basic_block( - todo!("issuer id"), - todo!("issuing time"), - None, - None, - &secret_manager, - Bip44::new(IOTA_COIN_TYPE), - ) + .build_basic_block(issuer_id, None, None, None, &secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; // Post the block. let block_id = client.post_block(&block).await?; diff --git a/sdk/examples/client/node_api_core/05_post_block_raw.rs b/sdk/examples/client/node_api_core/05_post_block_raw.rs index a20a0ad257..f1f697581f 100644 --- a/sdk/examples/client/node_api_core/05_post_block_raw.rs +++ b/sdk/examples/client/node_api_core/05_post_block_raw.rs @@ -9,7 +9,10 @@ //! ``` use crypto::keys::bip44::Bip44; -use iota_sdk::client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}; +use iota_sdk::{ + client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, + types::block::IssuerId, +}; #[tokio::main] async fn main() -> Result<()> { @@ -20,6 +23,7 @@ async fn main() -> Result<()> { let node_url = std::env::args() .nth(1) .unwrap_or_else(|| std::env::var("NODE_URL").unwrap()); + let issuer_id = std::env::var("ISSUER_ID").unwrap().parse::().unwrap(); // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; @@ -28,14 +32,7 @@ async fn main() -> Result<()> { // Create the block. let block = client - .build_basic_block( - todo!("issuer id"), - todo!("issuing time"), - None, - None, - &secret_manager, - Bip44::new(IOTA_COIN_TYPE), - ) + .build_basic_block(issuer_id, None, None, None, &secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; // Post the block as raw bytes. let block_id = client.post_block_raw(&block).await?; diff --git a/sdk/src/types/block/macro.rs b/sdk/src/types/block/macro.rs index 99f8d737a9..87c2cf18d5 100644 --- a/sdk/src/types/block/macro.rs +++ b/sdk/src/types/block/macro.rs @@ -27,13 +27,13 @@ macro_rules! impl_id { $vis const LENGTH: usize = $length; #[doc = concat!("Creates a new [`", stringify!($ty),"`].")] - $vis fn new(bytes: [u8; $name::LENGTH]) -> Self { - Self::from(bytes) + $vis const fn new(bytes: [u8; $name::LENGTH]) -> Self { + Self(bytes) } #[doc = concat!("Creates a null [`", stringify!($ty),"`].")] - pub fn null() -> Self { - Self::from([0u8; $name::LENGTH]) + pub const fn null() -> Self { + Self([0u8; $name::LENGTH]) } #[doc = concat!("Checks if the [`", stringify!($ty),"`] is null.")] diff --git a/sdk/tests/client/node_api/mod.rs b/sdk/tests/client/node_api/mod.rs index 5d27084a7b..20cfe27041 100644 --- a/sdk/tests/client/node_api/mod.rs +++ b/sdk/tests/client/node_api/mod.rs @@ -14,7 +14,7 @@ use iota_sdk::{ }, types::block::{ payload::{tagged_data::TaggedDataPayload, transaction::TransactionId, Payload}, - BlockId, + BlockId, IssuerId, }, }; @@ -31,8 +31,8 @@ async fn setup_tagged_data_block(secret_manager: &SecretManager) -> BlockId { client .build_basic_block( - todo!("issuer id"), - todo!("issuing time"), + IssuerId::null(), + None, None, Some(Payload::TaggedData(Box::new( TaggedDataPayload::new(b"Hello".to_vec(), b"Tangle".to_vec()).unwrap(), From 933ded1f547c35d0e410566f65172f7e33ed1eef Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 25 Oct 2023 13:38:49 -0400 Subject: [PATCH 02/20] rework block signing and rename wrapper to signed block --- bindings/core/src/lib.rs | 7 +- bindings/core/src/method/client.rs | 16 ++- bindings/core/src/method/client_secret.rs | 25 ---- bindings/core/src/method/mod.rs | 5 +- bindings/core/src/method/secret_manager.rs | 8 ++ bindings/core/src/method/utils.rs | 4 +- .../core/src/method_handler/call_method.rs | 27 +--- bindings/core/src/method_handler/client.rs | 38 +++-- .../core/src/method_handler/client_secret.rs | 50 ------- bindings/core/src/method_handler/mod.rs | 4 +- .../core/src/method_handler/secret_manager.rs | 8 +- bindings/core/src/method_handler/utils.rs | 4 +- bindings/core/src/response.rs | 12 +- bindings/core/tests/combined.rs | 62 ++++++-- bindings/nodejs/examples/client/10-mqtt.ts | 4 +- bindings/nodejs/lib/client/client.ts | 36 +++-- bindings/nodejs/lib/types/block/core/index.ts | 2 +- .../core/{wrapper.ts => signed-block.ts} | 10 +- .../nodejs/lib/types/utils/bridge/utils.ts | 4 +- bindings/nodejs/lib/utils/utils.ts | 4 +- bindings/python/iota_sdk/__init__.py | 2 +- .../python/iota_sdk/client/_high_level_api.py | 6 +- .../python/iota_sdk/client/_node_core_api.py | 12 +- bindings/python/iota_sdk/client/client.py | 6 +- .../block/{wrapper.py => signed_block.py} | 6 +- bindings/python/iota_sdk/utils.py | 4 +- bindings/python/tests/test_block.py | 20 +-- .../client/block/00_block_no_payload.rs | 10 +- .../block/01_block_confirmation_time.rs | 10 +- .../client/block/02_block_custom_parents.rs | 17 ++- .../client/block/03_block_custom_payload.rs | 17 ++- .../client/block/04_block_tagged_data.rs | 10 +- .../client/node_api_core/04_post_block.rs | 10 +- .../client/node_api_core/05_post_block_raw.rs | 10 +- sdk/src/client/api/block_builder/mod.rs | 24 +--- .../client/api/block_builder/transaction.rs | 4 +- sdk/src/client/api/high_level.rs | 10 +- sdk/src/client/node_api/core/routes.rs | 20 +-- sdk/src/client/secret/mod.rs | 14 +- sdk/src/client/utils.rs | 4 +- sdk/src/types/block/core/mod.rs | 6 +- .../core/{wrapper.rs => signed_block.rs} | 134 +++++++++++++----- sdk/src/types/block/error.rs | 4 +- sdk/src/types/block/mod.rs | 4 +- .../types/block/payload/tagged_data/mod.rs | 4 +- sdk/src/types/block/rand/block.rs | 28 ++-- sdk/src/wallet/account/operations/reissue.rs | 11 +- .../account/operations/syncing/outputs.rs | 6 +- .../transaction/submit_transaction.rs | 5 +- sdk/tests/client/node_api/core.rs | 4 +- sdk/tests/client/node_api/mod.rs | 13 +- sdk/tests/types/block.rs | 22 +-- sdk/tests/types/block_id.rs | 12 +- sdk/tests/types/tagged_data_payload.rs | 6 +- 54 files changed, 435 insertions(+), 370 deletions(-) delete mode 100644 bindings/core/src/method/client_secret.rs delete mode 100644 bindings/core/src/method_handler/client_secret.rs rename bindings/nodejs/lib/types/block/core/{wrapper.ts => signed-block.ts} (93%) rename bindings/python/iota_sdk/types/block/{wrapper.py => signed_block.py} (89%) rename sdk/src/types/block/core/{wrapper.rs => signed_block.rs} (74%) diff --git a/bindings/core/src/lib.rs b/bindings/core/src/lib.rs index 9e9f1f408b..75ab8c4288 100644 --- a/bindings/core/src/lib.rs +++ b/bindings/core/src/lib.rs @@ -26,11 +26,8 @@ pub use self::method_handler::listen_mqtt; pub use self::method_handler::CallMethod; pub use self::{ error::{Error, Result}, - method::{AccountMethod, ClientMethod, ClientSecretMethod, SecretManagerMethod, UtilsMethod, WalletMethod}, - method_handler::{ - call_client_method, call_client_secret_method, call_secret_manager_method, call_utils_method, - call_wallet_method, - }, + method::{AccountMethod, ClientMethod, SecretManagerMethod, UtilsMethod, WalletMethod}, + method_handler::{call_client_method, call_secret_manager_method, call_utils_method, call_wallet_method}, response::Response, }; diff --git a/bindings/core/src/method/client.rs b/bindings/core/src/method/client.rs index e175fd3bba..c67e499099 100644 --- a/bindings/core/src/method/client.rs +++ b/bindings/core/src/method/client.rs @@ -8,12 +8,13 @@ use iota_sdk::{ client::{node_api::indexer::query_parameters::QueryParameter, node_manager::node::NodeAuth}, types::block::{ address::{Bech32Address, Hrp}, + core::basic, output::{ dto::OutputDto, feature::Feature, unlock_condition::dto::UnlockConditionDto, AccountId, FoundryId, NativeToken, NftId, OutputId, TokenScheme, }, - payload::transaction::TransactionId, - BlockId, BlockWrapperDto, + payload::{dto::PayloadDto, transaction::TransactionId}, + BlockId, IssuerId, SignedBlockDto, }, utils::serde::{option_string, string}, }; @@ -122,6 +123,13 @@ pub enum ClientMethod { query_params: Vec, request_object: Option, }, + BuildBasicBlock { + /// The issuer's ID. + issuer_id: IssuerId, + strong_parents: Option, + /// The block payload. + payload: PayloadDto, + }, ////////////////////////////////////////////////////////////////////// // Node core API ////////////////////////////////////////////////////////////////////// @@ -146,7 +154,7 @@ pub enum ClientMethod { /// Post block (JSON) PostBlock { /// Block - block: BlockWrapperDto, + block: SignedBlockDto, }, /// Post block (raw) #[serde(rename_all = "camelCase")] @@ -328,6 +336,6 @@ pub enum ClientMethod { /// Returns a block ID from a block BlockId { /// Block - block: BlockWrapperDto, + signed_block: SignedBlockDto, }, } diff --git a/bindings/core/src/method/client_secret.rs b/bindings/core/src/method/client_secret.rs deleted file mode 100644 index 34baf9c770..0000000000 --- a/bindings/core/src/method/client_secret.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2023 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use crypto::keys::bip44::Bip44; -use derivative::Derivative; -use iota_sdk::types::block::{core::basic, payload::dto::PayloadDto, IssuerId}; -use serde::{Deserialize, Serialize}; - -/// Each public client + secret manager method. -#[derive(Clone, Derivative, Serialize, Deserialize)] -#[derivative(Debug)] -#[serde(tag = "name", content = "data", rename_all = "camelCase")] -#[non_exhaustive] -pub enum ClientSecretMethod { - /// Build a basic block containing the specified payload and post it to the network. - PostBasicBlockPayload { - /// The issuer's ID. - issuer_id: IssuerId, - strong_parents: Option, - /// The payload to send. - payload: PayloadDto, - /// The Bip44 chain to use when signing the block. - chain: Bip44, - }, -} diff --git a/bindings/core/src/method/mod.rs b/bindings/core/src/method/mod.rs index dfe40fdb62..966b583013 100644 --- a/bindings/core/src/method/mod.rs +++ b/bindings/core/src/method/mod.rs @@ -3,12 +3,11 @@ mod account; mod client; -mod client_secret; mod secret_manager; mod utils; mod wallet; pub use self::{ - account::AccountMethod, client::ClientMethod, client_secret::ClientSecretMethod, - secret_manager::SecretManagerMethod, utils::UtilsMethod, wallet::WalletMethod, + account::AccountMethod, client::ClientMethod, secret_manager::SecretManagerMethod, utils::UtilsMethod, + wallet::WalletMethod, }; diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index e4d548d052..351026c265 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -5,6 +5,7 @@ use crypto::keys::bip44::Bip44; use derivative::Derivative; use iota_sdk::{ client::api::{GetAddressesOptions, PreparedTransactionDataDto}, + types::block::UnsignedBlockDto, utils::serde::bip44::Bip44Def, }; use serde::{Deserialize, Serialize}; @@ -61,6 +62,13 @@ pub enum SecretManagerMethod { /// Prepared transaction data prepared_transaction_data: PreparedTransactionDataDto, }, + // Sign a block. + SignBlock { + unsigned_block: UnsignedBlockDto, + /// Chain to sign the essence hash with + #[serde(with = "Bip44Def")] + chain: Bip44, + }, /// Store a mnemonic in the Stronghold vault #[cfg(feature = "stronghold")] #[cfg_attr(docsrs, doc(cfg(feature = "stronghold")))] diff --git a/bindings/core/src/method/utils.rs b/bindings/core/src/method/utils.rs index 938b33b293..935d8f81ed 100644 --- a/bindings/core/src/method/utils.rs +++ b/bindings/core/src/method/utils.rs @@ -12,7 +12,7 @@ use iota_sdk::types::block::{ protocol::ProtocolParameters, signature::Ed25519Signature, slot::SlotCommitment, - BlockWrapperDto, + SignedBlockDto, }; use serde::{Deserialize, Serialize}; @@ -83,7 +83,7 @@ pub enum UtilsMethod { #[serde(rename_all = "camelCase")] BlockId { /// Block - block: BlockWrapperDto, + block: SignedBlockDto, /// Network Protocol Parameters protocol_parameters: ProtocolParameters, }, diff --git a/bindings/core/src/method_handler/call_method.rs b/bindings/core/src/method_handler/call_method.rs index 1a1ec27893..44e3574d40 100644 --- a/bindings/core/src/method_handler/call_method.rs +++ b/bindings/core/src/method_handler/call_method.rs @@ -13,11 +13,10 @@ use iota_sdk::{ }; use crate::{ - method::{ClientMethod, ClientSecretMethod, SecretManagerMethod, WalletMethod}, + method::{ClientMethod, SecretManagerMethod, WalletMethod}, method_handler::{ - client::call_client_method_internal, client_secret::call_client_secret_method_internal, - secret_manager::call_secret_manager_method_internal, utils::call_utils_method_internal, - wallet::call_wallet_method_internal, + client::call_client_method_internal, secret_manager::call_secret_manager_method_internal, + utils::call_utils_method_internal, wallet::call_wallet_method_internal, }, panic::{convert_async_panics, convert_panics}, response::Response, @@ -97,23 +96,3 @@ where log::debug!("Secret manager response: {response:?}"); response } - -/// Call a client + secret manager method. -pub async fn call_client_secret_method( - client: &Client, - secret_manager: &S, - method: ClientSecretMethod, -) -> Response -where - iota_sdk::client::Error: From, -{ - log::debug!("Client method: {method:?}"); - let result = - convert_async_panics(|| async { call_client_secret_method_internal(client, secret_manager, method).await }) - .await; - - let response = result.unwrap_or_else(Response::Error); - - log::debug!("Client response: {response:?}"); - response -} diff --git a/bindings/core/src/method_handler/client.rs b/bindings/core/src/method_handler/client.rs index 6cdffdb633..ced5a7603c 100644 --- a/bindings/core/src/method_handler/client.rs +++ b/bindings/core/src/method_handler/client.rs @@ -11,7 +11,8 @@ use iota_sdk::{ output::{ dto::OutputDto, AccountOutput, BasicOutput, FoundryOutput, NftOutput, Output, OutputBuilderAmount, Rent, }, - BlockWrapper, BlockWrapperDto, + payload::Payload, + SignedBlock, SignedBlockDto, UnsignedBlockDto, }, TryFromDto, }, @@ -160,6 +161,23 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM Response::Output(OutputDto::from(&output)) } + ClientMethod::BuildBasicBlock { + issuer_id, + strong_parents, + payload, + } => Response::UnsignedBlock(UnsignedBlockDto::from( + &client + .build_basic_block( + issuer_id, + None, + strong_parents, + Some(Payload::try_from_dto_with_params( + payload, + &client.get_protocol_parameters().await?, + )?), + ) + .await?, + )), #[cfg(feature = "mqtt")] ClientMethod::ClearListeners { topics } => { client.unsubscribe(topics).await?; @@ -179,7 +197,7 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM ClientMethod::GetIssuance => Response::Issuance(client.get_issuance().await?), ClientMethod::PostBlockRaw { block_bytes } => Response::BlockId( client - .post_block_raw(&BlockWrapper::unpack_strict( + .post_block_raw(&SignedBlock::unpack_strict( &block_bytes[..], &client.get_protocol_parameters().await?, )?) @@ -187,14 +205,14 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM ), ClientMethod::PostBlock { block } => Response::BlockId( client - .post_block(&BlockWrapper::try_from_dto_with_params( + .post_block(&SignedBlock::try_from_dto_with_params( block, client.get_protocol_parameters().await?, )?) .await?, ), ClientMethod::GetBlock { block_id } => { - Response::Block(BlockWrapperDto::from(&client.get_block(&block_id).await?)) + Response::SignedBlock(SignedBlockDto::from(&client.get_block(&block_id).await?)) } ClientMethod::GetBlockMetadata { block_id } => { Response::BlockMetadata(client.get_block_metadata(&block_id).await?) @@ -209,9 +227,9 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM ClientMethod::GetOutputMetadata { output_id } => { Response::OutputMetadata(client.get_output_metadata(&output_id).await?) } - ClientMethod::GetIncludedBlock { transaction_id } => Response::Block(BlockWrapperDto::from( - &client.get_included_block(&transaction_id).await?, - )), + ClientMethod::GetIncludedBlock { transaction_id } => { + Response::SignedBlock(SignedBlockDto::from(&client.get_included_block(&transaction_id).await?)) + } ClientMethod::GetIncludedBlockMetadata { transaction_id } => { Response::BlockMetadata(client.get_included_block_metadata(&transaction_id).await?) } @@ -256,7 +274,7 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM .find_blocks(&block_ids) .await? .iter() - .map(BlockWrapperDto::from) + .map(SignedBlockDto::from) .collect(), ), ClientMethod::FindInputs { addresses, amount } => { @@ -297,9 +315,9 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM .await?; Response::CustomJson(data) } - ClientMethod::BlockId { block } => { + ClientMethod::BlockId { signed_block: block } => { let protocol_parameters = client.get_protocol_parameters().await?; - let block = BlockWrapper::try_from_dto_with_params(block, &protocol_parameters)?; + let block = SignedBlock::try_from_dto_with_params(block, &protocol_parameters)?; Response::BlockId(block.id(&protocol_parameters)) } }; diff --git a/bindings/core/src/method_handler/client_secret.rs b/bindings/core/src/method_handler/client_secret.rs deleted file mode 100644 index 25f9e3ec42..0000000000 --- a/bindings/core/src/method_handler/client_secret.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2023 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use iota_sdk::{ - client::{secret::SecretManage, Client}, - types::{ - block::{payload::Payload, BlockWrapperDto}, - TryFromDto, - }, -}; - -use crate::{method::ClientSecretMethod, Response, Result}; - -/// Call a secret manager method. -pub(crate) async fn call_client_secret_method_internal( - client: &Client, - secret_manager: &S, - method: ClientSecretMethod, -) -> Result -where - iota_sdk::client::Error: From, -{ - let response = match method { - ClientSecretMethod::PostBasicBlockPayload { - issuer_id, - strong_parents, - payload, - chain, - } => { - let block = client - .build_basic_block( - issuer_id, - None, - strong_parents, - Some(Payload::try_from_dto_with_params( - payload, - &client.get_protocol_parameters().await?, - )?), - secret_manager, - chain, - ) - .await?; - - let block_id = client.block_id(&block).await?; - - Response::BlockIdWithBlock(block_id, BlockWrapperDto::from(&block)) - } - }; - Ok(response) -} diff --git a/bindings/core/src/method_handler/mod.rs b/bindings/core/src/method_handler/mod.rs index 340ff728ce..49be54cf5e 100644 --- a/bindings/core/src/method_handler/mod.rs +++ b/bindings/core/src/method_handler/mod.rs @@ -4,14 +4,12 @@ mod account; mod call_method; mod client; -mod client_secret; mod secret_manager; mod utils; mod wallet; pub use call_method::{ - call_client_method, call_client_secret_method, call_secret_manager_method, call_utils_method, call_wallet_method, - CallMethod, + call_client_method, call_secret_manager_method, call_utils_method, call_wallet_method, CallMethod, }; #[cfg(feature = "mqtt")] pub use client::listen_mqtt; diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index d6f559684e..f8a693dbe4 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -6,10 +6,11 @@ use iota_sdk::{ api::{GetAddressesOptions, PreparedTransactionData}, secret::{ ledger_nano::LedgerSecretManager, stronghold::StrongholdSecretManager, DowncastSecretManager, SecretManage, + SignBlock, }, }, types::{ - block::{address::ToBech32Ext, unlock::Unlock}, + block::{address::ToBech32Ext, core::UnsignedBlock, unlock::Unlock, SignedBlockDto}, TryFromDto, }, }; @@ -80,6 +81,11 @@ where .map_err(iota_sdk::client::Error::from)?; Response::SignedTransaction(transaction.into()) } + SecretManagerMethod::SignBlock { unsigned_block, chain } => Response::SignedBlock(SignedBlockDto::from( + &UnsignedBlock::try_from_dto(unsigned_block)? + .sign_ed25519(secret_manager, chain) + .await?, + )), SecretManagerMethod::SignatureUnlock { transaction_essence_hash, chain, diff --git a/bindings/core/src/method_handler/utils.rs b/bindings/core/src/method_handler/utils.rs index 17d7011540..6aa4cfbcd0 100644 --- a/bindings/core/src/method_handler/utils.rs +++ b/bindings/core/src/method_handler/utils.rs @@ -10,7 +10,7 @@ use iota_sdk::{ input::UtxoInput, output::{AccountId, FoundryId, InputsCommitment, NftId, Output, OutputId, Rent, TokenId}, payload::{transaction::TransactionEssence, TransactionPayload}, - BlockWrapper, + SignedBlock, }, TryFromDto, }, @@ -41,7 +41,7 @@ pub(crate) fn call_utils_method_internal(method: UtilsMethod) -> Result { - let block = BlockWrapper::try_from_dto_with_params(block, &protocol_parameters)?; + let block = SignedBlock::try_from_dto_with_params(block, &protocol_parameters)?; Response::BlockId(block.id(&protocol_parameters)) } UtilsMethod::TransactionId { payload } => { diff --git a/bindings/core/src/response.rs b/bindings/core/src/response.rs index 693bee2335..8671af75da 100644 --- a/bindings/core/src/response.rs +++ b/bindings/core/src/response.rs @@ -30,7 +30,7 @@ use iota_sdk::{ signature::Ed25519Signature, slot::SlotCommitmentId, unlock::Unlock, - BlockId, BlockWrapperDto, + BlockId, SignedBlockDto, UnsignedBlockDto, }, }, wallet::account::{ @@ -105,12 +105,12 @@ pub enum Response { /// - [`GetIssuance`](crate::method::ClientMethod::GetIssuance) Issuance(IssuanceBlockHeaderResponse), /// Response for: + /// - [`BuildBasicBlock`](crate::method::ClientMethod::BuildBasicBlock) + UnsignedBlock(UnsignedBlockDto), + /// Response for: /// - [`GetBlock`](crate::method::ClientMethod::GetBlock) /// - [`GetIncludedBlock`](crate::method::ClientMethod::GetIncludedBlock) - Block(BlockWrapperDto), - /// Response for: - /// - [`PostBlockPayload`](crate::method::ClientMethod::PostBlockPayload) - BlockIdWithBlock(BlockId, BlockWrapperDto), + SignedBlock(SignedBlockDto), /// Response for: /// - [`GetBlockMetadata`](crate::method::ClientMethod::GetBlockMetadata) BlockMetadata(BlockMetadataResponse), @@ -141,7 +141,7 @@ pub enum Response { OutputIdsResponse(OutputIdsResponse), /// Response for: /// - [`FindBlocks`](crate::method::ClientMethod::FindBlocks) - Blocks(Vec), + Blocks(Vec), /// Response for: /// - [`FindInputs`](crate::method::ClientMethod::FindInputs) Inputs(Vec), diff --git a/bindings/core/tests/combined.rs b/bindings/core/tests/combined.rs index c014a1e3a9..f08965ca9e 100644 --- a/bindings/core/tests/combined.rs +++ b/bindings/core/tests/combined.rs @@ -13,15 +13,15 @@ use iota_sdk::{ types::{ block::{ payload::{dto::PayloadDto, Payload, TaggedDataPayload}, - BlockDto, BlockWrapper, IssuerId, + BlockDto, IssuerId, SignedBlock, }, TryFromDto, }, wallet::account::types::AccountIdentifier, }; use iota_sdk_bindings_core::{ - call_client_secret_method, AccountMethod, CallMethod, ClientSecretMethod, Response, Result, WalletMethod, - WalletOptions, + call_client_method, call_secret_manager_method, AccountMethod, CallMethod, ClientMethod, Response, Result, + SecretManagerMethod, WalletMethod, WalletOptions, }; #[tokio::test] @@ -249,8 +249,8 @@ async fn client_from_wallet() -> Result<()> { } #[tokio::test] -async fn post_block() -> Result<()> { - let storage_path = "test-storage/client_from_wallet"; +async fn build_and_sign_block() -> Result<()> { + let storage_path = "test-storage/build_and_sign_block"; std::fs::remove_dir_all(storage_path).ok(); let secret_manager = MnemonicSecretManager::try_from_mnemonic( @@ -267,33 +267,69 @@ async fn post_block() -> Result<()> { TaggedDataPayload::new("Hello".as_bytes(), "Tangle".as_bytes()).unwrap(), )); - let response = call_client_secret_method( + // Get an unsigned block + let response = call_client_method( &client, - &secret_manager, - ClientSecretMethod::PostBasicBlockPayload { + ClientMethod::BuildBasicBlock { issuer_id: IssuerId::null(), strong_parents: None, payload: payload.clone(), + }, + ) + .await; + + let unsigned_block = match response { + Response::UnsignedBlock(unsigned_block) => { + match &unsigned_block.block { + BlockDto::Basic(b) => assert_eq!(b.payload.as_ref(), Some(&payload)), + BlockDto::Validation(v) => panic!("unexpected block {v:?}"), + } + unsigned_block + } + _ => panic!("unexpected response {response:?}"), + }; + + // Sign the block using the secret manager + let response = call_secret_manager_method( + &secret_manager, + SecretManagerMethod::SignBlock { + unsigned_block, chain: Bip44::new(IOTA_COIN_TYPE), }, ) .await; - match response { - Response::BlockIdWithBlock(block_id, block) => { + let signed_block = match response { + Response::SignedBlock(block) => { match &block.block { - BlockDto::Basic(b) => assert_eq!(b.payload, Some(payload)), + BlockDto::Basic(b) => assert_eq!(b.payload.as_ref(), Some(&payload)), BlockDto::Validation(v) => panic!("unexpected block {v:?}"), } + block + } + _ => panic!("unexpected response {response:?}"), + }; + + // Get the block ID + let response = call_client_method( + &client, + ClientMethod::BlockId { + signed_block: signed_block.clone(), + }, + ) + .await; + + match response { + Response::BlockId(block_id) => { assert_eq!( block_id, - BlockWrapper::try_from_dto(block) + SignedBlock::try_from_dto(signed_block) .unwrap() .id(&client.get_protocol_parameters().await.unwrap()) ); } _ => panic!("unexpected response {response:?}"), - } + }; Ok(()) } diff --git a/bindings/nodejs/examples/client/10-mqtt.ts b/bindings/nodejs/examples/client/10-mqtt.ts index 9b86bea884..72a0da348b 100644 --- a/bindings/nodejs/examples/client/10-mqtt.ts +++ b/bindings/nodejs/examples/client/10-mqtt.ts @@ -1,7 +1,7 @@ // Copyright 2021-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Client, initLogger, parseBlockWrapper } from '@iota/sdk'; +import { Client, initLogger, parseSignedBlock } from '@iota/sdk'; require('dotenv').config({ path: '.env' }); @@ -33,7 +33,7 @@ async function run() { const parsed = JSON.parse(data); if (parsed.topic == 'blocks') { - const block = parseBlockWrapper(JSON.parse(parsed.payload)); + const block = parseSignedBlock(JSON.parse(parsed.payload)); if (block.isBasic()) { const basic = block.asBasic(); diff --git a/bindings/nodejs/lib/client/client.ts b/bindings/nodejs/lib/client/client.ts index ba58c6d234..0bfdd5cb86 100644 --- a/bindings/nodejs/lib/client/client.ts +++ b/bindings/nodejs/lib/client/client.ts @@ -34,8 +34,8 @@ import { UnlockCondition, Payload, TransactionPayload, - parseBlockWrapper, - BlockWrapper, + parseSignedBlock, + SignedBlock, } from '../types/block'; import { HexEncodedString } from '../utils'; import { @@ -187,7 +187,7 @@ export class Client { * @param blockId The corresponding block ID of the requested block. * @returns The requested block. */ - async getBlock(blockId: BlockId): Promise { + async getBlock(blockId: BlockId): Promise { const response = await this.methodHandler.callMethod({ name: 'getBlock', data: { @@ -195,8 +195,8 @@ export class Client { }, }); - const parsed = JSON.parse(response) as Response; - return parseBlockWrapper(parsed.payload); + const parsed = JSON.parse(response) as Response; + return parseSignedBlock(parsed.payload); } /** @@ -290,17 +290,15 @@ export class Client { * @param payload The payload to post. * @returns The block ID followed by the block containing the payload. */ - async postBlockPayload(payload: Payload): Promise<[BlockId, BlockWrapper]> { + async postBlockPayload(payload: Payload): Promise<[BlockId, SignedBlock]> { const response = await this.methodHandler.callMethod({ name: 'postBlockPayload', data: { payload, }, }); - const parsed = JSON.parse(response) as Response< - [BlockId, BlockWrapper] - >; - const block = parseBlockWrapper(parsed.payload[1]); + const parsed = JSON.parse(response) as Response<[BlockId, SignedBlock]>; + const block = parseSignedBlock(parsed.payload[1]); return [parsed.payload[0], block]; } @@ -438,15 +436,15 @@ export class Client { * @param transactionId The ID of the transaction. * @returns The included block that contained the transaction. */ - async getIncludedBlock(transactionId: string): Promise { + async getIncludedBlock(transactionId: string): Promise { const response = await this.methodHandler.callMethod({ name: 'getIncludedBlock', data: { transactionId, }, }); - const parsed = JSON.parse(response) as Response; - return parseBlockWrapper(parsed.payload); + const parsed = JSON.parse(response) as Response; + return parseSignedBlock(parsed.payload); } /** @@ -457,15 +455,15 @@ export class Client { */ async getIncludedBlockMetadata( transactionId: string, - ): Promise { + ): Promise { const response = await this.methodHandler.callMethod({ name: 'getIncludedBlockMetadata', data: { transactionId, }, }); - const parsed = JSON.parse(response) as Response; - return parseBlockWrapper(parsed.payload); + const parsed = JSON.parse(response) as Response; + return parseSignedBlock(parsed.payload); } /** @@ -684,15 +682,15 @@ export class Client { * @param blockIds An array of `BlockId`s. * @returns An array of corresponding blocks. */ - async findBlocks(blockIds: BlockId[]): Promise { + async findBlocks(blockIds: BlockId[]): Promise { const response = await this.methodHandler.callMethod({ name: 'findBlocks', data: { blockIds, }, }); - const parsed = JSON.parse(response) as Response; - return parsed.payload.map((p) => parseBlockWrapper(p)); + const parsed = JSON.parse(response) as Response; + return parsed.payload.map((p) => parseSignedBlock(p)); } /** diff --git a/bindings/nodejs/lib/types/block/core/index.ts b/bindings/nodejs/lib/types/block/core/index.ts index d5bd231ea7..14d027ecfe 100644 --- a/bindings/nodejs/lib/types/block/core/index.ts +++ b/bindings/nodejs/lib/types/block/core/index.ts @@ -8,7 +8,7 @@ import { ValidationBlock } from './validation'; export * from './block'; export * from './basic'; export * from './validation'; -export * from './wrapper'; +export * from './signed-block'; // Here because in block.ts it causes a circular dependency export const BlockDiscriminator = { diff --git a/bindings/nodejs/lib/types/block/core/wrapper.ts b/bindings/nodejs/lib/types/block/core/signed-block.ts similarity index 93% rename from bindings/nodejs/lib/types/block/core/wrapper.ts rename to bindings/nodejs/lib/types/block/core/signed-block.ts index 5445e30041..4788e9e3c0 100644 --- a/bindings/nodejs/lib/types/block/core/wrapper.ts +++ b/bindings/nodejs/lib/types/block/core/signed-block.ts @@ -9,12 +9,12 @@ import { plainToInstance, Type } from 'class-transformer'; import { Block, BlockType } from './block'; import { BasicBlock } from './basic'; import { ValidationBlock } from './validation'; -import { BlockDiscriminator } from './'; +import { BlockDiscriminator } from '.'; /** * Represent the object that nodes gossip around the network. */ -class BlockWrapper { +class SignedBlock { /** * Protocol version of the block. */ @@ -116,8 +116,8 @@ class BlockWrapper { } } -function parseBlockWrapper(data: any): BlockWrapper { - return plainToInstance(BlockWrapper, data) as any as BlockWrapper; +function parseSignedBlock(data: any): SignedBlock { + return plainToInstance(SignedBlock, data) as any as SignedBlock; } -export { BlockWrapper, parseBlockWrapper }; +export { SignedBlock, parseSignedBlock }; diff --git a/bindings/nodejs/lib/types/utils/bridge/utils.ts b/bindings/nodejs/lib/types/utils/bridge/utils.ts index c7e237a5f8..50ac7bda78 100644 --- a/bindings/nodejs/lib/types/utils/bridge/utils.ts +++ b/bindings/nodejs/lib/types/utils/bridge/utils.ts @@ -7,7 +7,7 @@ import { TokenSchemeType, Output, RentStructure, - BlockWrapper, + SignedBlock, ProtocolParameters, } from '../../'; import { AccountId } from '../../block/id'; @@ -89,7 +89,7 @@ export interface __ParseBech32AddressMethod__ { export interface __BlockIdMethod__ { name: 'blockId'; data: { - block: BlockWrapper; + block: SignedBlock; params: ProtocolParameters; }; } diff --git a/bindings/nodejs/lib/utils/utils.ts b/bindings/nodejs/lib/utils/utils.ts index c960546fba..e7785a175f 100644 --- a/bindings/nodejs/lib/utils/utils.ts +++ b/bindings/nodejs/lib/utils/utils.ts @@ -14,7 +14,7 @@ import { RentStructure, OutputId, u64, - BlockWrapper, + SignedBlock, ProtocolParameters, } from '../types'; import { @@ -200,7 +200,7 @@ export class Utils { * @param params The network protocol parameters. * @returns The corresponding block ID. */ - static blockId(block: BlockWrapper, params: ProtocolParameters): BlockId { + static blockId(block: SignedBlock, params: ProtocolParameters): BlockId { return callUtilsMethod({ name: 'blockId', data: { diff --git a/bindings/python/iota_sdk/__init__.py b/bindings/python/iota_sdk/__init__.py index b62c123995..7b244a3be0 100644 --- a/bindings/python/iota_sdk/__init__.py +++ b/bindings/python/iota_sdk/__init__.py @@ -15,7 +15,7 @@ from .types.block.basic import * from .types.block.block import * from .types.block.metadata import * -from .types.block.wrapper import * +from .types.block.signed_block import * from .types.block.validation import * from .types.block_builder_options import * from .types.block_issuer_key import * diff --git a/bindings/python/iota_sdk/client/_high_level_api.py b/bindings/python/iota_sdk/client/_high_level_api.py index f7947d4676..bdb376ae4d 100644 --- a/bindings/python/iota_sdk/client/_high_level_api.py +++ b/bindings/python/iota_sdk/client/_high_level_api.py @@ -4,7 +4,7 @@ from typing import List, Optional from dataclasses import dataclass from abc import ABCMeta, abstractmethod -from iota_sdk.types.block.wrapper import BlockWrapper +from bindings.python.iota_sdk.types.block.signed_block import SignedBlock from iota_sdk.types.common import CoinType, HexStr, json from iota_sdk.types.output_metadata import OutputWithMetadata from iota_sdk.types.output_id import OutputId @@ -94,7 +94,7 @@ def get_outputs_ignore_errors( }) return [OutputWithMetadata.from_dict(o) for o in outputs] - def find_blocks(self, block_ids: List[HexStr]) -> List[BlockWrapper]: + def find_blocks(self, block_ids: List[HexStr]) -> List[SignedBlock]: """Find all blocks by provided block IDs. Args: @@ -106,7 +106,7 @@ def find_blocks(self, block_ids: List[HexStr]) -> List[BlockWrapper]: blocks = self._call_method('findBlocks', { 'blockIds': block_ids }) - return [BlockWrapper.from_dict(block) for block in blocks] + return [SignedBlock.from_dict(block) for block in blocks] def find_inputs(self, addresses: List[str], amount: int): """Function to find inputs from addresses for a provided amount(useful for offline signing). diff --git a/bindings/python/iota_sdk/client/_node_core_api.py b/bindings/python/iota_sdk/client/_node_core_api.py index 43b93216df..50a2649d59 100644 --- a/bindings/python/iota_sdk/client/_node_core_api.py +++ b/bindings/python/iota_sdk/client/_node_core_api.py @@ -5,7 +5,7 @@ from abc import ABCMeta, abstractmethod from dacite import from_dict -from iota_sdk.types.block.wrapper import BlockWrapper +from bindings.python.iota_sdk.types.block.signed_block import SignedBlock from iota_sdk.types.block.metadata import BlockMetadata from iota_sdk.types.common import HexStr from iota_sdk.types.node_info import NodeInfo, NodeInfoWrapper @@ -58,7 +58,7 @@ def get_tips(self) -> List[HexStr]: """ return self._call_method('getTips') - def post_block(self, block: BlockWrapper) -> HexStr: + def post_block(self, block: SignedBlock) -> HexStr: """Post a block. Args: @@ -71,10 +71,10 @@ def post_block(self, block: BlockWrapper) -> HexStr: 'block': block.__dict__ }) - def get_block(self, block_id: HexStr) -> BlockWrapper: + def get_block(self, block_id: HexStr) -> SignedBlock: """Get the block corresponding to the given block id. """ - return BlockWrapper.from_dict(self._call_method('getBlock', { + return SignedBlock.from_dict(self._call_method('getBlock', { 'blockId': block_id })) @@ -128,13 +128,13 @@ def get_output_metadata( 'outputId': output_id_str })) - def get_included_block(self, transaction_id: HexStr) -> BlockWrapper: + def get_included_block(self, transaction_id: HexStr) -> SignedBlock: """Returns the included block of the given transaction. Returns: The included block. """ - return BlockWrapper.from_dict(self._call_method('getIncludedBlock', { + return SignedBlock.from_dict(self._call_method('getIncludedBlock', { 'transactionId': transaction_id })) diff --git a/bindings/python/iota_sdk/client/client.py b/bindings/python/iota_sdk/client/client.py index d7d1fd55c4..0215011b27 100644 --- a/bindings/python/iota_sdk/client/client.py +++ b/bindings/python/iota_sdk/client/client.py @@ -13,7 +13,7 @@ from iota_sdk.client._high_level_api import HighLevelAPI from iota_sdk.client._utils import ClientUtils from iota_sdk.secret_manager.secret_manager import LedgerNanoSecretManager, MnemonicSecretManager, StrongholdSecretManager, SeedSecretManager -from iota_sdk.types.block.wrapper import BlockWrapper +from bindings.python.iota_sdk.types.block.signed_block import SignedBlock from iota_sdk.types.common import HexStr, Node from iota_sdk.types.feature import Feature from iota_sdk.types.native_token import NativeToken @@ -395,7 +395,7 @@ def sign_transaction( })) def submit_payload( - self, payload: Payload) -> List[Union[HexStr, BlockWrapper]]: + self, payload: Payload) -> List[Union[HexStr, SignedBlock]]: """Submit a payload in a block. Args: @@ -407,7 +407,7 @@ def submit_payload( result = self._call_method('postBlockPayload', { 'payload': payload.to_dict() }) - result[1] = BlockWrapper.from_dict(result[1]) + result[1] = SignedBlock.from_dict(result[1]) return result def listen_mqtt(self, topics: List[str], handler): diff --git a/bindings/python/iota_sdk/types/block/wrapper.py b/bindings/python/iota_sdk/types/block/signed_block.py similarity index 89% rename from bindings/python/iota_sdk/types/block/wrapper.py rename to bindings/python/iota_sdk/types/block/signed_block.py index 01798703eb..31b19cd6ef 100644 --- a/bindings/python/iota_sdk/types/block/wrapper.py +++ b/bindings/python/iota_sdk/types/block/signed_block.py @@ -15,9 +15,9 @@ @json @dataclass -class BlockWrapper: - """A block wrapper type that can hold either a `BasicBlock` or a `ValidationBlock`. - Shared data is stored alongside such a block in the `BlockHeader` and `Signature` fields. +class SignedBlock: + """A signed block type that can hold either a `BasicBlock` or a `ValidationBlock`. + Shared data is stored alongside such a block in the header fields. Attributes: protocol_version: Protocol version of the network to which this block belongs. diff --git a/bindings/python/iota_sdk/utils.py b/bindings/python/iota_sdk/utils.py index 85d71ebe6a..f5ed27a012 100644 --- a/bindings/python/iota_sdk/utils.py +++ b/bindings/python/iota_sdk/utils.py @@ -16,7 +16,7 @@ # Required to prevent circular import if TYPE_CHECKING: - from iota_sdk.types.block.wrapper import BlockWrapper + from bindings.python.iota_sdk.types.block.signed_block import SignedBlock class Utils(): @@ -165,7 +165,7 @@ def compute_token_id(account_id: HexStr, serial_number: int, }) @staticmethod - def block_id(block: BlockWrapper, params: ProtocolParameters) -> HexStr: + def block_id(block: SignedBlock, params: ProtocolParameters) -> HexStr: """ Return a block ID (Blake2b256 hash of block bytes) from a block. """ return _call_method('blockId', { diff --git a/bindings/python/tests/test_block.py b/bindings/python/tests/test_block.py index ac4a8c0c99..b4aef4123d 100644 --- a/bindings/python/tests/test_block.py +++ b/bindings/python/tests/test_block.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 from typing import get_args -from iota_sdk import BasicBlock, BlockType, BlockWrapper, Payload, PayloadType +from iota_sdk import BasicBlock, BlockType, SignedBlock, Payload, PayloadType import pytest @@ -30,7 +30,7 @@ def test_basic_block_with_tagged_data_payload(): assert block_to_dict == block_dict -def test_block_wrapper_with_tagged_data_payload(): +def test_signed_block_with_tagged_data_payload(): block_dict = { "protocolVersion": 3, "networkId": "10549460113735494767", @@ -63,14 +63,14 @@ def test_block_wrapper_with_tagged_data_payload(): "signature": "0x7c274e5e771d5d60202d334f06773d3672484b1e4e6f03231b4e69305329267a4834374b0f2e0d5c6c2f7779620f4f534c773b1679400c52303d1f23121a4049" } } - block_wrapper = BlockWrapper.from_dict(block_dict) - assert block_wrapper.to_dict() == block_dict - assert isinstance(block_wrapper.block, BasicBlock) - assert block_wrapper.block.type == BlockType.Basic - assert isinstance(block_wrapper.block.payload, get_args(Payload)) - assert block_wrapper.block.payload.type == PayloadType.TaggedData - # TODO: determine the actual hash of the block wrapper - # assert block_wrapper.id() == "0x7ce5ad074d4162e57f83cfa01cd2303ef5356567027ce0bcee0c9f57bc11656e" + signed_block = SignedBlock.from_dict(block_dict) + assert signed_block.to_dict() == block_dict + assert isinstance(signed_block.block, BasicBlock) + assert signed_block.block.type == BlockType.Basic + assert isinstance(signed_block.block.payload, get_args(Payload)) + assert signed_block.block.payload.type == PayloadType.TaggedData + # TODO: determine the actual hash of the block + # assert signed_block.id() == "0x7ce5ad074d4162e57f83cfa01cd2303ef5356567027ce0bcee0c9f57bc11656e" @pytest.mark.skip(reason="https://github.com/iotaledger/iota-sdk/issues/1387") diff --git a/sdk/examples/client/block/00_block_no_payload.rs b/sdk/examples/client/block/00_block_no_payload.rs index 337fa799d3..5ea4a41aef 100644 --- a/sdk/examples/client/block/00_block_no_payload.rs +++ b/sdk/examples/client/block/00_block_no_payload.rs @@ -10,7 +10,11 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, + client::{ + constants::IOTA_COIN_TYPE, + secret::{SecretManager, SignBlock}, + Client, Result, + }, types::block::IssuerId, }; @@ -29,7 +33,9 @@ async fn main() -> Result<()> { // Create and send the block. let block = client - .build_basic_block(issuer_id, None, None, None, &secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .build_basic_block(issuer_id, None, None, None) + .await? + .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; println!("{block:#?}"); diff --git a/sdk/examples/client/block/01_block_confirmation_time.rs b/sdk/examples/client/block/01_block_confirmation_time.rs index 97e65f7912..d6a7137e65 100644 --- a/sdk/examples/client/block/01_block_confirmation_time.rs +++ b/sdk/examples/client/block/01_block_confirmation_time.rs @@ -10,7 +10,11 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, + client::{ + constants::IOTA_COIN_TYPE, + secret::{SecretManager, SignBlock}, + Client, Result, + }, types::{api::core::response::BlockState, block::IssuerId}, }; @@ -29,7 +33,9 @@ async fn main() -> Result<()> { // Create and send a block. let block = client - .build_basic_block(issuer_id, None, None, None, &secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .build_basic_block(issuer_id, None, None, None) + .await? + .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; let block_id = client.block_id(&block).await?; diff --git a/sdk/examples/client/block/02_block_custom_parents.rs b/sdk/examples/client/block/02_block_custom_parents.rs index 88b607e2d9..5e8eb5325b 100644 --- a/sdk/examples/client/block/02_block_custom_parents.rs +++ b/sdk/examples/client/block/02_block_custom_parents.rs @@ -10,7 +10,11 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, + client::{ + constants::IOTA_COIN_TYPE, + secret::{SecretManager, SignBlock}, + Client, Result, + }, types::block::IssuerId, }; @@ -33,14 +37,9 @@ async fn main() -> Result<()> { // Create and send the block with custom parents. let block = client - .build_basic_block( - issuer_id, - None, - Some(issuance.strong_parents()?), - None, - &secret_manager, - Bip44::new(IOTA_COIN_TYPE), - ) + .build_basic_block(issuer_id, None, Some(issuance.strong_parents()?), None) + .await? + .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; println!("{block:#?}"); diff --git a/sdk/examples/client/block/03_block_custom_payload.rs b/sdk/examples/client/block/03_block_custom_payload.rs index 5bfe3853be..7b48af2fca 100644 --- a/sdk/examples/client/block/03_block_custom_payload.rs +++ b/sdk/examples/client/block/03_block_custom_payload.rs @@ -10,7 +10,11 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, + client::{ + constants::IOTA_COIN_TYPE, + secret::{SecretManager, SignBlock}, + Client, Result, + }, types::block::{ payload::{Payload, TaggedDataPayload}, IssuerId, @@ -35,14 +39,9 @@ async fn main() -> Result<()> { // Create and send the block with the custom payload. let block = client - .build_basic_block( - issuer_id, - None, - None, - Some(Payload::from(tagged_data_payload)), - &secret_manager, - Bip44::new(IOTA_COIN_TYPE), - ) + .build_basic_block(issuer_id, None, None, Some(Payload::from(tagged_data_payload))) + .await? + .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; println!("{block:#?}"); diff --git a/sdk/examples/client/block/04_block_tagged_data.rs b/sdk/examples/client/block/04_block_tagged_data.rs index 736c47fd9d..55cef29bd2 100644 --- a/sdk/examples/client/block/04_block_tagged_data.rs +++ b/sdk/examples/client/block/04_block_tagged_data.rs @@ -10,7 +10,11 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, + client::{ + constants::IOTA_COIN_TYPE, + secret::{SecretManager, SignBlock}, + Client, Result, + }, types::block::{ payload::{Payload, TaggedDataPayload}, IssuerId, @@ -49,9 +53,9 @@ async fn main() -> Result<()> { ) .unwrap(), ))), - &secret_manager, - Bip44::new(IOTA_COIN_TYPE), ) + .await? + .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; println!("{block:#?}\n"); diff --git a/sdk/examples/client/node_api_core/04_post_block.rs b/sdk/examples/client/node_api_core/04_post_block.rs index f29da0eb40..35be7f1038 100644 --- a/sdk/examples/client/node_api_core/04_post_block.rs +++ b/sdk/examples/client/node_api_core/04_post_block.rs @@ -10,7 +10,11 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, + client::{ + constants::IOTA_COIN_TYPE, + secret::{SecretManager, SignBlock}, + Client, Result, + }, types::block::IssuerId, }; @@ -32,7 +36,9 @@ async fn main() -> Result<()> { // Create the block. let block = client - .build_basic_block(issuer_id, None, None, None, &secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .build_basic_block(issuer_id, None, None, None) + .await? + .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; // Post the block. let block_id = client.post_block(&block).await?; diff --git a/sdk/examples/client/node_api_core/05_post_block_raw.rs b/sdk/examples/client/node_api_core/05_post_block_raw.rs index f1f697581f..0d34eece6f 100644 --- a/sdk/examples/client/node_api_core/05_post_block_raw.rs +++ b/sdk/examples/client/node_api_core/05_post_block_raw.rs @@ -10,7 +10,11 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, + client::{ + constants::IOTA_COIN_TYPE, + secret::{SecretManager, SignBlock}, + Client, Result, + }, types::block::IssuerId, }; @@ -32,7 +36,9 @@ async fn main() -> Result<()> { // Create the block. let block = client - .build_basic_block(issuer_id, None, None, None, &secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .build_basic_block(issuer_id, None, None, None) + .await? + .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; // Post the block as raw bytes. let block_id = client.post_block_raw(&block).await?; diff --git a/sdk/src/client/api/block_builder/mod.rs b/sdk/src/client/api/block_builder/mod.rs index 78a1a5d4e8..a00846ad30 100644 --- a/sdk/src/client/api/block_builder/mod.rs +++ b/sdk/src/client/api/block_builder/mod.rs @@ -4,34 +4,24 @@ pub mod input_selection; pub mod transaction; -use crypto::keys::bip44::Bip44; - pub use self::transaction::verify_semantic; use crate::{ - client::{ - secret::{SecretManage, SignBlock}, - ClientInner, Result, - }, + client::{ClientInner, Result}, types::block::{ - core::{basic, BlockHeader, BlockWrapper}, + core::{basic, BlockHeader, UnsignedBlock}, payload::Payload, Block, IssuerId, }, }; impl ClientInner { - pub async fn build_basic_block( + pub async fn build_basic_block( &self, issuer_id: IssuerId, issuing_time: Option, strong_parents: Option, payload: Option, - secret_manager: &S, - chain: Bip44, - ) -> Result - where - crate::client::Error: From, - { + ) -> Result { let issuance = self.get_issuance().await?; let strong_parents = strong_parents.unwrap_or(issuance.strong_parents()?); @@ -50,7 +40,7 @@ impl ClientInner { let protocol_params = self.get_protocol_parameters().await?; - BlockWrapper::build( + Ok(UnsignedBlock::new( BlockHeader::new( protocol_params.version(), protocol_params.network_id(), @@ -64,8 +54,6 @@ impl ClientInner { .with_shallow_like_parents(issuance.shallow_like_parents()?) .with_payload(payload) .finish_block()?, - ) - .sign_ed25519(secret_manager, chain) - .await + )) } } diff --git a/sdk/src/client/api/block_builder/transaction.rs b/sdk/src/client/api/block_builder/transaction.rs index 60c45a77e3..e201774cf6 100644 --- a/sdk/src/client/api/block_builder/transaction.rs +++ b/sdk/src/client/api/block_builder/transaction.rs @@ -12,13 +12,13 @@ use crate::{ payload::transaction::{RegularTransactionEssence, TransactionPayload}, semantic::{semantic_validation, TransactionFailureReason, ValidationContext}, signature::Ed25519Signature, - BlockId, BlockWrapper, + BlockId, SignedBlock, }, }; // TODO this is wrong because of https://github.com/iotaledger/iota-sdk/issues/1208 const MAX_TX_LENGTH_FOR_BLOCK_WITH_8_PARENTS: usize = - BlockWrapper::LENGTH_MAX - BlockWrapper::LENGTH_MIN - (7 * BlockId::LENGTH); + SignedBlock::LENGTH_MAX - SignedBlock::LENGTH_MIN - (7 * BlockId::LENGTH); // Length for unlocks with a single signature unlock (unlocks length + unlock type + signature type + public key + // signature) const SINGLE_UNLOCK_LENGTH: usize = 1 + 1 + Ed25519Signature::PUBLIC_KEY_LENGTH + Ed25519Signature::SIGNATURE_LENGTH; diff --git a/sdk/src/client/api/high_level.rs b/sdk/src/client/api/high_level.rs index c224ebe80b..b0ccea89ed 100644 --- a/sdk/src/client/api/high_level.rs +++ b/sdk/src/client/api/high_level.rs @@ -15,7 +15,7 @@ use crate::{ }, types::block::{ address::Bech32Address, - core::{BasicBlock, Block, BlockWrapper}, + core::{BasicBlock, Block, SignedBlock}, input::{Input, UtxoInput, INPUT_COUNT_MAX}, output::OutputWithMetadata, payload::{transaction::TransactionId, Payload}, @@ -27,9 +27,9 @@ use crate::{ impl Client { /// Get the inputs of a transaction for the given transaction id. pub async fn inputs_from_transaction_id(&self, transaction_id: &TransactionId) -> Result> { - let wrapper = self.get_included_block(transaction_id).await?; + let signed_block = self.get_included_block(transaction_id).await?; - if let Block::Basic(block) = wrapper.block() { + if let Block::Basic(block) = signed_block.block() { let inputs = if let Some(Payload::Transaction(t)) = block.payload() { t.essence().inputs() } else { @@ -47,13 +47,13 @@ impl Client { } else { Err(Error::UnexpectedBlockKind { expected: BasicBlock::KIND, - actual: wrapper.block().kind(), + actual: signed_block.block().kind(), }) } } /// Find all blocks by provided block IDs. - pub async fn find_blocks(&self, block_ids: &[BlockId]) -> Result> { + pub async fn find_blocks(&self, block_ids: &[BlockId]) -> Result> { // Use a `HashSet` to prevent duplicate block_ids. let block_ids = block_ids.iter().copied().collect::>(); futures::future::try_join_all(block_ids.iter().map(|block_id| self.get_block(block_id))).await diff --git a/sdk/src/client/node_api/core/routes.rs b/sdk/src/client/node_api/core/routes.rs index b19da9631f..dbd9eb3228 100644 --- a/sdk/src/client/node_api/core/routes.rs +++ b/sdk/src/client/node_api/core/routes.rs @@ -24,7 +24,7 @@ use crate::{ output::{dto::OutputDto, AccountId, Output, OutputId, OutputMetadata}, payload::transaction::TransactionId, slot::{EpochIndex, SlotCommitment, SlotCommitmentId, SlotIndex}, - BlockId, BlockWrapper, BlockWrapperDto, + BlockId, SignedBlock, SignedBlockDto, }, TryFromDto, }, @@ -160,10 +160,10 @@ impl ClientInner { /// Returns the BlockId of the submitted block. /// POST JSON to /api/core/v3/blocks - pub async fn post_block(&self, block: &BlockWrapper) -> Result { + pub async fn post_block(&self, block: &SignedBlock) -> Result { const PATH: &str = "api/core/v3/blocks"; - let block_dto = BlockWrapperDto::from(block); + let block_dto = SignedBlockDto::from(block); let response = self .post_request::(PATH, serde_json::to_value(block_dto)?) @@ -174,7 +174,7 @@ impl ClientInner { /// Returns the BlockId of the submitted block. /// POST /api/core/v3/blocks - pub async fn post_block_raw(&self, block: &BlockWrapper) -> Result { + pub async fn post_block_raw(&self, block: &SignedBlock) -> Result { const PATH: &str = "api/core/v3/blocks"; let response = self @@ -186,12 +186,12 @@ impl ClientInner { /// Finds a block by its ID and returns it as object. /// GET /api/core/v3/blocks/{blockId} - pub async fn get_block(&self, block_id: &BlockId) -> Result { + pub async fn get_block(&self, block_id: &BlockId) -> Result { let path = &format!("api/core/v3/blocks/{block_id}"); - let dto = self.get_request::(path, None, false, true).await?; + let dto = self.get_request::(path, None, false, true).await?; - Ok(BlockWrapper::try_from_dto_with_params( + Ok(SignedBlock::try_from_dto_with_params( dto, self.get_protocol_parameters().await?, )?) @@ -244,12 +244,12 @@ impl ClientInner { /// Returns the earliest confirmed block containing the transaction with the given ID. /// GET /api/core/v3/transactions/{transactionId}/included-block - pub async fn get_included_block(&self, transaction_id: &TransactionId) -> Result { + pub async fn get_included_block(&self, transaction_id: &TransactionId) -> Result { let path = &format!("api/core/v3/transactions/{transaction_id}/included-block"); - let dto = self.get_request::(path, None, true, true).await?; + let dto = self.get_request::(path, None, true, true).await?; - Ok(BlockWrapper::try_from_dto_with_params( + Ok(SignedBlock::try_from_dto_with_params( dto, self.get_protocol_parameters().await?, )?) diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index 62008273d9..b3092cb311 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -53,12 +53,12 @@ use crate::{ }, types::block::{ address::{Address, Ed25519Address}, - core::BlockWrapperBuilder, + core::UnsignedBlock, output::Output, payload::{transaction::TransactionEssence, TransactionPayload}, signature::{Ed25519Signature, Signature}, unlock::{AccountUnlock, NftUnlock, ReferenceUnlock, SignatureUnlock, Unlock, Unlocks}, - BlockWrapper, + SignedBlock, }, }; @@ -612,18 +612,14 @@ pub trait SignBlock { self, secret_manager: &S, chain: Bip44, - ) -> crate::client::Result + ) -> crate::client::Result where crate::client::Error: From; } #[async_trait] -impl SignBlock for BlockWrapperBuilder { - async fn sign_ed25519( - self, - secret_manager: &S, - chain: Bip44, - ) -> crate::client::Result +impl SignBlock for UnsignedBlock { + async fn sign_ed25519(self, secret_manager: &S, chain: Bip44) -> crate::client::Result where crate::client::Error: From, { diff --git a/sdk/src/client/utils.rs b/sdk/src/client/utils.rs index c864748105..9ed1442ee5 100644 --- a/sdk/src/client/utils.rs +++ b/sdk/src/client/utils.rs @@ -21,7 +21,7 @@ use crate::{ address::{Address, Bech32Address, Ed25519Address, Hrp, ToBech32Ext}, output::{AccountId, NftId}, payload::TaggedDataPayload, - BlockId, BlockWrapper, ConvertTo, + BlockId, ConvertTo, SignedBlock, }, }; @@ -189,7 +189,7 @@ impl Client { Ok((Self::tag_to_utf8(payload)?, Self::data_to_utf8(payload)?)) } - pub async fn block_id(&self, block: &BlockWrapper) -> Result { + pub async fn block_id(&self, block: &SignedBlock) -> Result { Ok(block.id(&self.get_protocol_parameters().await?)) } } diff --git a/sdk/src/types/block/core/mod.rs b/sdk/src/types/block/core/mod.rs index 3b1b9b40bb..21c427f23e 100644 --- a/sdk/src/types/block/core/mod.rs +++ b/sdk/src/types/block/core/mod.rs @@ -3,8 +3,8 @@ pub mod basic; mod parent; +mod signed_block; pub mod validation; -mod wrapper; use alloc::boxed::Box; @@ -20,8 +20,8 @@ use packable::{ pub use self::{ basic::{BasicBlock, BasicBlockBuilder}, parent::Parents, + signed_block::{BlockHeader, SignedBlock, UnsignedBlock}, validation::{ValidationBlock, ValidationBlockBuilder}, - wrapper::{BlockHeader, BlockWrapper, BlockWrapperBuilder}, }; use crate::types::block::{ protocol::{ProtocolParameters, ProtocolParametersHash}, @@ -141,7 +141,7 @@ pub(crate) mod dto { use serde_json::Value; use super::*; - pub use crate::types::block::core::wrapper::dto::BlockWrapperDto; + pub use crate::types::block::core::signed_block::dto::{SignedBlockDto, UnsignedBlockDto}; use crate::types::{ block::core::{basic::dto::BasicBlockDto, validation::dto::ValidationBlockDto}, TryFromDto, ValidationParams, diff --git a/sdk/src/types/block/core/wrapper.rs b/sdk/src/types/block/core/signed_block.rs similarity index 74% rename from sdk/src/types/block/core/wrapper.rs rename to sdk/src/types/block/core/signed_block.rs index d66cf14d71..01c03c3adf 100644 --- a/sdk/src/types/block/core/wrapper.rs +++ b/sdk/src/types/block/core/signed_block.rs @@ -22,16 +22,16 @@ use crate::types::block::{ Block, Error, IssuerId, }; -/// Builder for a [`BlockWrapper`]. +/// Builder for a [`SignedBlock`]. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct BlockWrapperBuilder { +pub struct UnsignedBlock { /// The block header. pub(crate) header: BlockHeader, /// The inner block. pub(crate) block: Block, } -impl BlockWrapperBuilder { +impl UnsignedBlock { pub fn new(header: BlockHeader, block: Block) -> Self { Self { header, block } } @@ -56,8 +56,8 @@ impl BlockWrapperBuilder { [self.header.hash(), self.block.hash()].concat() } - pub fn finish(self, signature: impl Into) -> Result { - Ok(BlockWrapper::new(self.header, self.block, signature)) + pub fn finish(self, signature: impl Into) -> Result { + Ok(SignedBlock::new(self.header, self.block, signature)) } } @@ -167,7 +167,7 @@ impl Packable for BlockHeader { /// Represent the object that nodes gossip around the network. #[derive(Clone, Debug, Eq, PartialEq, Getters, CopyGetters)] -pub struct BlockWrapper { +pub struct SignedBlock { #[getset(skip)] header: BlockHeader, /// The inner block. @@ -178,13 +178,13 @@ pub struct BlockWrapper { signature: Signature, } -impl BlockWrapper { +impl SignedBlock { /// The minimum number of bytes in a block. pub const LENGTH_MIN: usize = 46; /// The maximum number of bytes in a block. pub const LENGTH_MAX: usize = 32768; - /// Creates a new [`BlockWrapper`]. + /// Creates a new [`SignedBlock`]. #[inline(always)] pub fn new(header: BlockHeader, block: Block, signature: impl Into) -> Self { let signature = signature.into(); @@ -196,43 +196,43 @@ impl BlockWrapper { } } - /// Creates a new [`BlockWrapperBuilder`]. + /// Creates a new [`SignedBlockBuilder`]. #[inline(always)] - pub fn build(header: BlockHeader, block: Block) -> BlockWrapperBuilder { - BlockWrapperBuilder::new(header, block) + pub fn build(header: BlockHeader, block: Block) -> UnsignedBlock { + UnsignedBlock::new(header, block) } - /// Returns the protocol version of a [`BlockWrapper`]. + /// Returns the protocol version of a [`SignedBlock`]. #[inline(always)] pub fn protocol_version(&self) -> u8 { self.header.protocol_version() } - /// Returns the network id of a [`BlockWrapper`]. + /// Returns the network id of a [`SignedBlock`]. #[inline(always)] pub fn network_id(&self) -> u64 { self.header.network_id() } - /// Returns the issuing time of a [`BlockWrapper`]. + /// Returns the issuing time of a [`SignedBlock`]. #[inline(always)] pub fn issuing_time(&self) -> u64 { self.header.issuing_time() } - /// Returns the slot commitment ID of a [`BlockWrapper`]. + /// Returns the slot commitment ID of a [`SignedBlock`]. #[inline(always)] pub fn slot_commitment_id(&self) -> SlotCommitmentId { self.header.slot_commitment_id() } - /// Returns the latest finalized slot of a [`BlockWrapper`]. + /// Returns the latest finalized slot of a [`SignedBlock`]. #[inline(always)] pub fn latest_finalized_slot(&self) -> SlotIndex { self.header.latest_finalized_slot() } - /// Returns the issuer ID of a [`BlockWrapper`]. + /// Returns the issuer ID of a [`SignedBlock`]. #[inline(always)] pub fn issuer_id(&self) -> IssuerId { self.header.issuer_id() @@ -250,7 +250,7 @@ impl BlockWrapper { block_hash.with_slot_index(protocol_params.slot_index(self.header.issuing_time() / 1000000000)) } - /// Unpacks a [`BlockWrapper`] from a sequence of bytes doing syntactical checks and verifying that + /// Unpacks a [`SignedBlock`] from a sequence of bytes doing syntactical checks and verifying that /// there are no trailing bytes in the sequence. pub fn unpack_strict>( bytes: T, @@ -290,7 +290,7 @@ impl BlockWrapper { } } -impl Packable for BlockWrapper { +impl Packable for SignedBlock { type UnpackError = Error; type UnpackVisitor = ProtocolParameters; @@ -328,7 +328,7 @@ impl Packable for BlockWrapper { }; if wrapper_len > Self::LENGTH_MAX { - return Err(UnpackError::Packable(Error::InvalidBlockWrapperLength(wrapper_len))); + return Err(UnpackError::Packable(Error::InvalidSignedBlockLength(wrapper_len))); } } @@ -349,7 +349,76 @@ pub(crate) mod dto { /// The block object that nodes gossip around in the network. #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] - pub struct BlockWrapperDto { + pub struct SignedBlockDto { + #[serde(flatten)] + pub inner: UnsignedBlockDto, + pub signature: Signature, + } + + impl core::ops::Deref for SignedBlockDto { + type Target = UnsignedBlockDto; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + + impl From<&SignedBlock> for SignedBlockDto { + fn from(value: &SignedBlock) -> Self { + Self { + inner: UnsignedBlockDto { + protocol_version: value.protocol_version(), + network_id: value.network_id(), + issuing_time: value.issuing_time(), + slot_commitment_id: value.slot_commitment_id(), + latest_finalized_slot: value.latest_finalized_slot(), + issuer_id: value.issuer_id(), + block: BlockDto::from(&value.block), + }, + signature: value.signature, + } + } + } + + impl TryFromDto for SignedBlock { + type Dto = SignedBlockDto; + type Error = Error; + + fn try_from_dto_with_params_inner(dto: Self::Dto, params: ValidationParams<'_>) -> Result { + if let Some(protocol_params) = params.protocol_parameters() { + if dto.inner.protocol_version != protocol_params.version() { + return Err(Error::ProtocolVersionMismatch { + expected: protocol_params.version(), + actual: dto.inner.protocol_version, + }); + } + + if dto.inner.network_id != protocol_params.network_id() { + return Err(Error::NetworkIdMismatch { + expected: protocol_params.network_id(), + actual: dto.inner.network_id, + }); + } + } + + Ok(Self::new( + BlockHeader::new( + dto.inner.protocol_version, + dto.inner.network_id, + dto.inner.issuing_time, + dto.inner.slot_commitment_id, + dto.inner.latest_finalized_slot, + dto.inner.issuer_id, + ), + Block::try_from_dto_with_params_inner(dto.inner.block, params)?, + dto.signature, + )) + } + } + + #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct UnsignedBlockDto { pub protocol_version: u8, #[serde(with = "string")] pub network_id: u64, @@ -359,26 +428,24 @@ pub(crate) mod dto { pub latest_finalized_slot: SlotIndex, pub issuer_id: IssuerId, pub block: BlockDto, - pub signature: Signature, } - impl From<&BlockWrapper> for BlockWrapperDto { - fn from(value: &BlockWrapper) -> Self { + impl From<&UnsignedBlock> for UnsignedBlockDto { + fn from(value: &UnsignedBlock) -> Self { Self { - protocol_version: value.protocol_version(), - network_id: value.network_id(), - issuing_time: value.issuing_time(), - slot_commitment_id: value.slot_commitment_id(), - latest_finalized_slot: value.latest_finalized_slot(), - issuer_id: value.issuer_id(), + protocol_version: value.header.protocol_version(), + network_id: value.header.network_id(), + issuing_time: value.header.issuing_time(), + slot_commitment_id: value.header.slot_commitment_id(), + latest_finalized_slot: value.header.latest_finalized_slot(), + issuer_id: value.header.issuer_id(), block: BlockDto::from(&value.block), - signature: value.signature, } } } - impl TryFromDto for BlockWrapper { - type Dto = BlockWrapperDto; + impl TryFromDto for UnsignedBlock { + type Dto = UnsignedBlockDto; type Error = Error; fn try_from_dto_with_params_inner(dto: Self::Dto, params: ValidationParams<'_>) -> Result { @@ -408,7 +475,6 @@ pub(crate) mod dto { dto.issuer_id, ), Block::try_from_dto_with_params_inner(dto.block, params)?, - dto.signature, )) } } diff --git a/sdk/src/types/block/error.rs b/sdk/src/types/block/error.rs index 5e9ae86b4f..33cfe4d2bd 100644 --- a/sdk/src/types/block/error.rs +++ b/sdk/src/types/block/error.rs @@ -84,7 +84,7 @@ pub enum Error { InvalidInputOutputIndex(>::Error), InvalidBech32Hrp(Bech32HrpError), InvalidCapabilitiesCount(>::Error), - InvalidBlockWrapperLength(usize), + InvalidSignedBlockLength(usize), InvalidStateMetadataLength(>::Error), InvalidManaValue(u64), InvalidMetadataFeatureLength(>::Error), @@ -260,7 +260,7 @@ impl fmt::Display for Error { Self::InvalidInputKind(k) => write!(f, "invalid input kind: {k}"), Self::InvalidInputCount(count) => write!(f, "invalid input count: {count}"), Self::InvalidInputOutputIndex(index) => write!(f, "invalid input or output index: {index}"), - Self::InvalidBlockWrapperLength(length) => write!(f, "invalid block wrapper length {length}"), + Self::InvalidSignedBlockLength(length) => write!(f, "invalid signed block length {length}"), Self::InvalidStateMetadataLength(length) => write!(f, "invalid state metadata length: {length}"), Self::InvalidManaValue(mana) => write!(f, "invalid mana value: {mana}"), Self::InvalidMetadataFeatureLength(length) => { diff --git a/sdk/src/types/block/mod.rs b/sdk/src/types/block/mod.rs index 2954d4c8cd..40eb4675dd 100644 --- a/sdk/src/types/block/mod.rs +++ b/sdk/src/types/block/mod.rs @@ -47,11 +47,11 @@ pub(crate) use r#macro::create_bitflags; pub(crate) use r#macro::{impl_id, string_serde_impl}; #[cfg(feature = "serde")] -pub use self::core::dto::{BlockDto, BlockWrapperDto}; +pub use self::core::dto::{BlockDto, SignedBlockDto, UnsignedBlockDto}; pub use self::{ block_id::{BlockHash, BlockId}, convert::ConvertTo, - core::{Block, BlockWrapper}, + core::{Block, SignedBlock}, error::Error, issuer_id::IssuerId, }; diff --git a/sdk/src/types/block/payload/tagged_data/mod.rs b/sdk/src/types/block/payload/tagged_data/mod.rs index dba8239e9e..80c897099e 100644 --- a/sdk/src/types/block/payload/tagged_data/mod.rs +++ b/sdk/src/types/block/payload/tagged_data/mod.rs @@ -12,7 +12,7 @@ use packable::{ Packable, }; -use crate::types::block::{BlockWrapper, Error}; +use crate::types::block::{Error, SignedBlock}; pub(crate) type TagLength = BoundedU8<{ *TaggedDataPayload::TAG_LENGTH_RANGE.start() }, { *TaggedDataPayload::TAG_LENGTH_RANGE.end() }>; @@ -39,7 +39,7 @@ impl TaggedDataPayload { // lengths. // TODO https://github.com/iotaledger/iota-sdk/issues/1226 pub const DATA_LENGTH_RANGE: RangeInclusive = - 0..=(BlockWrapper::LENGTH_MAX - BlockWrapper::LENGTH_MIN - 9) as u32; + 0..=(SignedBlock::LENGTH_MAX - SignedBlock::LENGTH_MIN - 9) as u32; /// Creates a new [`TaggedDataPayload`]. pub fn new(tag: impl Into>, data: impl Into>) -> Result { diff --git a/sdk/src/types/block/rand/block.rs b/sdk/src/types/block/rand/block.rs index cedfa623ce..8079751708 100644 --- a/sdk/src/types/block/rand/block.rs +++ b/sdk/src/types/block/rand/block.rs @@ -6,7 +6,7 @@ use alloc::vec::Vec; use crate::types::block::{ core::{ basic::{self, BasicBlockBuilder}, - BlockHeader, BlockWrapper, BlockWrapperBuilder, + BlockHeader, SignedBlock, UnsignedBlock, }, protocol::ProtocolParameters, rand::{ @@ -46,9 +46,9 @@ pub fn rand_basic_block_builder_with_strong_parents(strong_parents: basic::Stron Block::build_basic(strong_parents, rand_number()) } -/// Generates a random block wrapper with given block. -pub fn rand_block_wrapper_with_block(protocol_params: ProtocolParameters, block: Block) -> BlockWrapper { - BlockWrapper::build( +/// Generates a random signed block with given block. +pub fn rand_signed_block_with_block(protocol_params: ProtocolParameters, block: Block) -> SignedBlock { + SignedBlock::build( BlockHeader::new( protocol_params.version(), protocol_params.network_id(), @@ -62,25 +62,25 @@ pub fn rand_block_wrapper_with_block(protocol_params: ProtocolParameters, block: .sign_random() } -/// Generates a random block wrapper with given strong parents. -pub fn rand_block_wrapper_with_strong_parents( +/// Generates a random signed block with given strong parents. +pub fn rand_signed_block_with_strong_parents( protocol_params: ProtocolParameters, strong_parents: basic::StrongParents, -) -> BlockWrapper { - rand_block_wrapper_with_block(protocol_params, rand_basic_block_with_strong_parents(strong_parents)) +) -> SignedBlock { + rand_signed_block_with_block(protocol_params, rand_basic_block_with_strong_parents(strong_parents)) } -/// Generates a random block wrapper. -pub fn rand_block_wrapper(protocol_params: ProtocolParameters) -> BlockWrapper { - rand_block_wrapper_with_strong_parents(protocol_params, rand_strong_parents()) +/// Generates a random signed block. +pub fn rand_signed_block(protocol_params: ProtocolParameters) -> SignedBlock { + rand_signed_block_with_strong_parents(protocol_params, rand_strong_parents()) } pub trait SignBlockRandom { - fn sign_random(self) -> BlockWrapper; + fn sign_random(self) -> SignedBlock; } -impl SignBlockRandom for BlockWrapperBuilder { - fn sign_random(self) -> BlockWrapper { +impl SignBlockRandom for UnsignedBlock { + fn sign_random(self) -> SignedBlock { let signing_input = self.signing_input(); self.finish(rand_sign_ed25519(&signing_input)).unwrap() } diff --git a/sdk/src/wallet/account/operations/reissue.rs b/sdk/src/wallet/account/operations/reissue.rs index 54c93a4f42..04575548a3 100644 --- a/sdk/src/wallet/account/operations/reissue.rs +++ b/sdk/src/wallet/account/operations/reissue.rs @@ -4,7 +4,10 @@ use crypto::keys::bip44::Bip44; use crate::{ - client::{secret::SecretManage, Error as ClientError}, + client::{ + secret::{SecretManage, SignBlock}, + Error as ClientError, + }, types::{ api::core::response::{BlockState, TransactionState}, block::{ @@ -63,6 +66,9 @@ where todo!("issuing time"), None, Some(Payload::Transaction(Box::new(transaction.payload.clone()))), + ) + .await? + .sign_ed25519( &*self.get_secret_manager().read().await, Bip44::new(self.wallet.coin_type()), ) @@ -113,6 +119,9 @@ where todo!("issuing time"), None, Some(Payload::Transaction(Box::new(transaction.payload.clone()))), + ) + .await? + .sign_ed25519( &*self.get_secret_manager().read().await, Bip44::new(self.wallet.coin_type()), ) diff --git a/sdk/src/wallet/account/operations/syncing/outputs.rs b/sdk/src/wallet/account/operations/syncing/outputs.rs index 74d7ebca9c..51faddc1d0 100644 --- a/sdk/src/wallet/account/operations/syncing/outputs.rs +++ b/sdk/src/wallet/account/operations/syncing/outputs.rs @@ -141,8 +141,8 @@ where futures::future::try_join_all(transaction_ids.iter().map(|transaction_id| async { let transaction_id = *transaction_id; match client.get_included_block(&transaction_id).await { - Ok(wrapper) => { - if let Block::Basic(block) = wrapper.block() { + Ok(signed_block) => { + if let Block::Basic(block) = signed_block.block() { if let Some(Payload::Transaction(transaction_payload)) = block.payload() { let inputs_with_meta = get_inputs_for_transaction_payload(&client, transaction_payload) @@ -165,7 +165,7 @@ where } else { Err(ClientError::UnexpectedBlockKind { expected: BasicBlock::KIND, - actual: wrapper.block().kind(), + actual: signed_block.block().kind(), } .into()) } diff --git a/sdk/src/wallet/account/operations/transaction/submit_transaction.rs b/sdk/src/wallet/account/operations/transaction/submit_transaction.rs index 3175410e34..eccea2a4c6 100644 --- a/sdk/src/wallet/account/operations/transaction/submit_transaction.rs +++ b/sdk/src/wallet/account/operations/transaction/submit_transaction.rs @@ -6,7 +6,7 @@ use crypto::keys::bip44::Bip44; #[cfg(feature = "events")] use crate::wallet::events::types::{TransactionProgressEvent, WalletEvent}; use crate::{ - client::secret::SecretManage, + client::secret::{SecretManage, SignBlock}, types::block::{payload::Payload, BlockId}, wallet::account::{operations::transaction::TransactionPayload, Account}, }; @@ -32,6 +32,9 @@ where todo!("issuing time"), None, Some(Payload::from(transaction_payload)), + ) + .await? + .sign_ed25519( &*self.get_secret_manager().read().await, Bip44::new(self.wallet.coin_type()), ) diff --git a/sdk/tests/client/node_api/core.rs b/sdk/tests/client/node_api/core.rs index b44bae435a..9b226de9c0 100644 --- a/sdk/tests/client/node_api/core.rs +++ b/sdk/tests/client/node_api/core.rs @@ -9,7 +9,7 @@ use iota_sdk::{ api::core::response::TransactionState, block::{ output::{Output, OutputId}, - BlockWrapper, + SignedBlock, }, }, }; @@ -191,7 +191,7 @@ async fn test_get_included_block_raw() { let (_block_id, transaction_id) = setup_transaction_block(&client).await; let block = client.get_included_block(&transaction_id).await.unwrap(); - let block_raw = BlockWrapper::unpack_verified( + let block_raw = SignedBlock::unpack_verified( client.get_included_block_raw(&transaction_id).await.unwrap(), &client.get_protocol_parameters().await.unwrap(), ) diff --git a/sdk/tests/client/node_api/mod.rs b/sdk/tests/client/node_api/mod.rs index 20cfe27041..0b63e0cf0c 100644 --- a/sdk/tests/client/node_api/mod.rs +++ b/sdk/tests/client/node_api/mod.rs @@ -9,8 +9,12 @@ mod mqtt; use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ - api::GetAddressesOptions, constants::IOTA_COIN_TYPE, node_api::indexer::query_parameters::QueryParameter, - request_funds_from_faucet, secret::SecretManager, Client, + api::GetAddressesOptions, + constants::IOTA_COIN_TYPE, + node_api::indexer::query_parameters::QueryParameter, + request_funds_from_faucet, + secret::{SecretManager, SignBlock}, + Client, }, types::block::{ payload::{tagged_data::TaggedDataPayload, transaction::TransactionId, Payload}, @@ -37,11 +41,12 @@ async fn setup_tagged_data_block(secret_manager: &SecretManager) -> BlockId { Some(Payload::TaggedData(Box::new( TaggedDataPayload::new(b"Hello".to_vec(), b"Tangle".to_vec()).unwrap(), ))), - secret_manager, - Bip44::new(IOTA_COIN_TYPE), ) .await .unwrap() + .sign_ed25519(secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .await + .unwrap() .id(&protocol_params) } diff --git a/sdk/tests/types/block.rs b/sdk/tests/types/block.rs index 7e408dbce9..ab0de8cc63 100644 --- a/sdk/tests/types/block.rs +++ b/sdk/tests/types/block.rs @@ -7,11 +7,11 @@ use iota_sdk::types::{ payload::Payload, protocol::{protocol_parameters, ProtocolParameters}, rand::{ - block::{rand_basic_block_builder_with_strong_parents, rand_block_wrapper, rand_block_wrapper_with_block}, + block::{rand_basic_block_builder_with_strong_parents, rand_signed_block, rand_signed_block_with_block}, parents::rand_strong_parents, payload::rand_tagged_data_payload, }, - BlockWrapper, BlockWrapperDto, + SignedBlock, SignedBlockDto, }, TryFromDto, }; @@ -92,7 +92,7 @@ use packable::PackableExt; #[test] fn pack_unpack_valid() { let protocol_parameters = protocol_parameters(); - let block = rand_block_wrapper(protocol_parameters.clone()); + let block = rand_signed_block(protocol_parameters.clone()); let packed_block = block.pack_to_vec(); assert_eq!(packed_block.len(), block.packed_len()); @@ -112,11 +112,11 @@ fn getters() { .with_payload(payload.clone()) .finish_block() .unwrap(); - let wrapper = rand_block_wrapper_with_block(protocol_parameters.clone(), block); + let signed_block = rand_signed_block_with_block(protocol_parameters.clone(), block); - assert_eq!(wrapper.protocol_version(), protocol_parameters.version()); - assert_eq!(*wrapper.as_basic().strong_parents(), parents); - assert_eq!(*wrapper.as_basic().payload().as_ref().unwrap(), &payload); + assert_eq!(signed_block.protocol_version(), protocol_parameters.version()); + assert_eq!(*signed_block.as_basic().strong_parents(), parents); + assert_eq!(*signed_block.as_basic().payload().as_ref().unwrap(), &payload); } #[test] @@ -149,8 +149,8 @@ fn dto_mismatch_version() { "signature": "0x3e4a492924302b3b093f1e4266757a1d2041480a3861271d4c2e646d4e3d08360a3e765e1a385a784f6753276c233123475867370a184573195d530b41643a1d" } }); - let block_dto = serde_json::from_value::(block_dto_json).unwrap(); - let block_res = BlockWrapper::try_from_dto_with_params(block_dto, &protocol_parameters); + let block_dto = serde_json::from_value::(block_dto_json).unwrap(); + let block_res = SignedBlock::try_from_dto_with_params(block_dto, &protocol_parameters); assert_eq!( block_res, @@ -190,8 +190,8 @@ fn dto_mismatch_network_id() { "signature": "0x3e4a492924302b3b093f1e4266757a1d2041480a3861271d4c2e646d4e3d08360a3e765e1a385a784f6753276c233123475867370a184573195d530b41643a1d" } }); - let block_dto = serde_json::from_value::(block_dto_json).unwrap(); - let block_res = BlockWrapper::try_from_dto_with_params(block_dto, &protocol_parameters); + let block_dto = serde_json::from_value::(block_dto_json).unwrap(); + let block_res = SignedBlock::try_from_dto_with_params(block_dto, &protocol_parameters); assert_eq!( block_res, diff --git a/sdk/tests/types/block_id.rs b/sdk/tests/types/block_id.rs index 437ed7ddab..80b825afd8 100644 --- a/sdk/tests/types/block_id.rs +++ b/sdk/tests/types/block_id.rs @@ -104,8 +104,8 @@ fn memory_layout() { // } // }); -// let block_dto = serde_json::from_value::(block_json).unwrap(); -// let block = BlockWrapper::try_from_dto(block_dto).unwrap(); +// let block_dto = serde_json::from_value::(block_json).unwrap(); +// let block = SignedBlock::try_from_dto(block_dto).unwrap(); // let block_bytes = block.pack_to_vec(); // assert_eq!( @@ -222,8 +222,8 @@ fn memory_layout() { // } // }); -// let block_dto = serde_json::from_value::(block_json).unwrap(); -// let block = BlockWrapper::try_from_dto(block_dto).unwrap(); +// let block_dto = serde_json::from_value::(block_json).unwrap(); +// let block = SignedBlock::try_from_dto(block_dto).unwrap(); // let block_bytes = block.pack_to_vec(); // assert_eq!( @@ -300,8 +300,8 @@ fn memory_layout() { // } // }); -// let block_dto = serde_json::from_value::(block_json).unwrap(); -// let block = BlockWrapper::try_from_dto(block_dto).unwrap(); +// let block_dto = serde_json::from_value::(block_json).unwrap(); +// let block = SignedBlock::try_from_dto(block_dto).unwrap(); // let block_bytes = block.pack_to_vec(); // assert_eq!( diff --git a/sdk/tests/types/tagged_data_payload.rs b/sdk/tests/types/tagged_data_payload.rs index ddf22a0531..446ef341a0 100644 --- a/sdk/tests/types/tagged_data_payload.rs +++ b/sdk/tests/types/tagged_data_payload.rs @@ -4,7 +4,7 @@ use iota_sdk::types::block::{ payload::tagged_data::TaggedDataPayload, rand::bytes::{rand_bytes, rand_bytes_array}, - BlockWrapper, Error, + Error, SignedBlock, }; use packable::{ bounded::{TryIntoBoundedU32Error, TryIntoBoundedU8Error}, @@ -66,8 +66,8 @@ fn new_invalid_tag_length_more_than_max() { fn new_invalid_data_length_more_than_max() { assert!(matches!( // TODO https://github.com/iotaledger/iota-sdk/issues/1226 - TaggedDataPayload::new(rand_bytes(32), [0u8; BlockWrapper::LENGTH_MAX + 42]), - Err(Error::InvalidTaggedDataLength(TryIntoBoundedU32Error::Invalid(l))) if l == BlockWrapper::LENGTH_MAX as u32 + 42 + TaggedDataPayload::new(rand_bytes(32), [0u8; SignedBlock::LENGTH_MAX + 42]), + Err(Error::InvalidTaggedDataLength(TryIntoBoundedU32Error::Invalid(l))) if l == SignedBlock::LENGTH_MAX as u32 + 42 )); } From 9a412293d8dad73f09f9dcae432e63811f519326 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 25 Oct 2023 13:59:49 -0400 Subject: [PATCH 03/20] camelCase --- bindings/core/src/method/secret_manager.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index db617ab044..c538f3aec2 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -63,6 +63,7 @@ pub enum SecretManagerMethod { prepared_transaction_data: PreparedTransactionDataDto, }, // Sign a block. + #[serde(rename_all = "camelCase")] SignBlock { unsigned_block: UnsignedBlockDto, /// Chain to sign the essence hash with From ac9cf33cf5784c0065038cc008aea4e2c671dce3 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 25 Oct 2023 14:17:49 -0400 Subject: [PATCH 04/20] refactor nodejs --- bindings/nodejs/lib/client/client.ts | 22 +++- .../lib/secret_manager/secret-manager.ts | 26 +++++ .../lib/types/block/core/signed-block.ts | 103 +++++++++++++++++- .../nodejs/lib/types/client/bridge/client.ts | 7 +- .../lib/types/secret_manager/bridge/index.ts | 2 + .../secret_manager/bridge/secret-manager.ts | 9 ++ 6 files changed, 159 insertions(+), 10 deletions(-) diff --git a/bindings/nodejs/lib/client/client.ts b/bindings/nodejs/lib/client/client.ts index e634296c76..9ab777d471 100644 --- a/bindings/nodejs/lib/client/client.ts +++ b/bindings/nodejs/lib/client/client.ts @@ -39,6 +39,9 @@ import { AccountId, NftId, FoundryId, + IssuerId, + UnsignedBlock, + parseUnsignedBlock, } from '../types/block'; import { HexEncodedString } from '../utils'; import { @@ -292,21 +295,28 @@ export class Client { } /** - * Submit a payload in a block. + * Build an unsigned block. * + * @param issuerId The identifier of the block issuer account. * @param payload The payload to post. + * @param strongParents Optional strong parents to use for the block. * @returns The block ID followed by the block containing the payload. */ - async postBlockPayload(payload: Payload): Promise<[BlockId, SignedBlock]> { + async buildBasicBlock( + issuerId: IssuerId, + payload: Payload, + strongParents?: [BlockId], + ): Promise { const response = await this.methodHandler.callMethod({ - name: 'postBlockPayload', + name: 'buildBasicBlock', data: { + issuerId, + strongParents, payload, }, }); - const parsed = JSON.parse(response) as Response<[BlockId, SignedBlock]>; - const block = parseSignedBlock(parsed.payload[1]); - return [parsed.payload[0], block]; + const parsed = JSON.parse(response) as Response; + return parseUnsignedBlock(parsed.payload); } /** diff --git a/bindings/nodejs/lib/secret_manager/secret-manager.ts b/bindings/nodejs/lib/secret_manager/secret-manager.ts index acb669b606..83e1db5594 100644 --- a/bindings/nodejs/lib/secret_manager/secret-manager.ts +++ b/bindings/nodejs/lib/secret_manager/secret-manager.ts @@ -18,6 +18,9 @@ import { SignedTransactionPayload, Unlock, Response, + UnsignedBlock, + SignedBlock, + parseSignedBlock, } from '../types'; import { plainToInstance } from 'class-transformer'; @@ -109,6 +112,29 @@ export class SecretManager { return plainToInstance(SignedTransactionPayload, parsed.payload); } + /** + * Sign a block. + * + * @param unsignedBlock An unsigned block. + * @param chain A BIP44 chain. + * @returns The corresponding transaction payload. + */ + async signBlock( + unsignedBlock: UnsignedBlock, + chain: Bip44, + ): Promise { + const response = await this.methodHandler.callMethod({ + name: 'signBlock', + data: { + unsignedBlock, + chain, + }, + }); + + const parsed = JSON.parse(response) as Response; + return parseSignedBlock(parsed.payload); + } + /** * Create a signature unlock using the provided `secretManager`. * diff --git a/bindings/nodejs/lib/types/block/core/signed-block.ts b/bindings/nodejs/lib/types/block/core/signed-block.ts index 4788e9e3c0..44d19bb953 100644 --- a/bindings/nodejs/lib/types/block/core/signed-block.ts +++ b/bindings/nodejs/lib/types/block/core/signed-block.ts @@ -69,8 +69,8 @@ class SignedBlock { this.slotCommitmentId = slotCommitmentId; this.latestFinalizedSlot = latestFinalizedSlot; this.issuerId = issuerId; - this.signature = signature; this.block = block; + this.signature = signature; } /** @@ -120,4 +120,103 @@ function parseSignedBlock(data: any): SignedBlock { return plainToInstance(SignedBlock, data) as any as SignedBlock; } -export { SignedBlock, parseSignedBlock }; +/** + * Represent the object that nodes gossip around the network. + */ +class UnsignedBlock { + /** + * Protocol version of the block. + */ + readonly protocolVersion!: number; + /** + * Network identifier. + */ + readonly networkId!: u64; + /** + * The time at which the block was issued. It is a Unix timestamp in nanoseconds. + */ + readonly issuingTime!: u64; + /** + * The identifier of the slot to which this block commits. + */ + readonly slotCommitmentId!: SlotCommitmentId; + /** + * The slot index of the latest finalized slot. + */ + readonly latestFinalizedSlot!: SlotIndex; + /** + * The identifier of the account that issued this block. + */ + readonly issuerId!: IssuerId; + + @Type(() => Block, { + discriminator: BlockDiscriminator, + }) + readonly block!: Block; + + constructor( + protocolVersion: number, + networkId: u64, + issuingTime: u64, + slotCommitmentId: SlotCommitmentId, + latestFinalizedSlot: SlotIndex, + issuerId: IssuerId, + block: Block, + ) { + this.protocolVersion = protocolVersion; + this.networkId = networkId; + this.issuingTime = issuingTime; + this.slotCommitmentId = slotCommitmentId; + this.latestFinalizedSlot = latestFinalizedSlot; + this.issuerId = issuerId; + this.block = block; + } + + /** + * Checks whether the block is a `BasicBlock`. + * @returns true if it is, otherwise false + */ + isBasic(): boolean { + return this.block.type === BlockType.Basic; + } + + /** + * Gets the block as an actual `BasicBlock`. + * NOTE: Will throw an error if the block is not a `BasicBlock`. + * @returns The block + */ + asBasic(): BasicBlock { + if (this.isBasic()) { + return this.block as unknown as BasicBlock; + } else { + throw new Error('invalid downcast of non-BasicBlock'); + } + } + + /** + * Checks whether the block is a `ValidationBlock`. + * @returns true if it is, otherwise false + */ + isValidation(): boolean { + return this.block.type === BlockType.Validation; + } + + /** + * Gets the block as an actual `ValidationBlock`. + * NOTE: Will throw an error if the block is not a `ValidationBlock`. + * @returns The block + */ + asValidation(): ValidationBlock { + if (this.isValidation()) { + return this.block as unknown as ValidationBlock; + } else { + throw new Error('invalid downcast of non-ValidationBlock'); + } + } +} + +function parseUnsignedBlock(data: any): UnsignedBlock { + return plainToInstance(UnsignedBlock, data) as any as UnsignedBlock; +} + +export { SignedBlock, parseSignedBlock, UnsignedBlock, parseUnsignedBlock }; diff --git a/bindings/nodejs/lib/types/client/bridge/client.ts b/bindings/nodejs/lib/types/client/bridge/client.ts index 70c818bc9a..3dd35997a3 100644 --- a/bindings/nodejs/lib/types/client/bridge/client.ts +++ b/bindings/nodejs/lib/types/client/bridge/client.ts @@ -10,6 +10,7 @@ import type { Block, BlockId, FoundryId, + IssuerId, NftId, Output, OutputId, @@ -117,9 +118,11 @@ export interface __SignatureUnlockMethod__ { }; } -export interface __PostBlockPayloadMethod__ { - name: 'postBlockPayload'; +export interface __BuildBasicBlockMethod__ { + name: 'buildBasicBlock'; data: { + issuerId: IssuerId; + parents?: [BlockId]; payload: Payload; }; } diff --git a/bindings/nodejs/lib/types/secret_manager/bridge/index.ts b/bindings/nodejs/lib/types/secret_manager/bridge/index.ts index fb69675837..c9901c3440 100644 --- a/bindings/nodejs/lib/types/secret_manager/bridge/index.ts +++ b/bindings/nodejs/lib/types/secret_manager/bridge/index.ts @@ -3,6 +3,7 @@ import type { __GenerateEvmAddressesMethod__, __GetLedgerNanoStatusMethod__, __SignTransactionMethod__, + __SignBlockMethod__, __StoreMnemonicMethod__, __SignatureUnlockMethod__, __SignEd25519Method__, @@ -14,6 +15,7 @@ export type __SecretManagerMethods__ = | __GenerateEvmAddressesMethod__ | __GetLedgerNanoStatusMethod__ | __SignTransactionMethod__ + | __SignBlockMethod__ | __SignatureUnlockMethod__ | __StoreMnemonicMethod__ | __SignEd25519Method__ diff --git a/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts b/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts index 7ec44ce96c..31bca06493 100644 --- a/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts +++ b/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts @@ -1,6 +1,7 @@ // Copyright 2021-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +import { UnsignedBlock } from '../../block'; import type { IGenerateAddressesOptions } from '../../client/generate-addresses-options'; import type { PreparedTransactionData } from '../../client/prepared-transaction-data'; import { HexEncodedString } from '../../utils'; @@ -27,6 +28,14 @@ export interface __SignTransactionMethod__ { }; } +export interface __SignBlockMethod__ { + name: 'signBlock'; + data: { + unsignedBlock: UnsignedBlock; + chain: Bip44; + }; +} + export interface __SignatureUnlockMethod__ { name: 'signatureUnlock'; data: { From fae23a4ff1cab891ffa24ce033f2aebe6fca322b Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 25 Oct 2023 14:36:03 -0400 Subject: [PATCH 05/20] Add to python --- .../python/examples/client/06_simple_block.py | 18 ++++++++++-- .../python/examples/client/08_data_block.py | 13 ++++++++- .../python/examples/client/post_raw_block.py | 13 ++++++++- .../examples/client/submit_and_read_block.py | 18 ++++++++---- bindings/python/iota_sdk/client/client.py | 27 +++++++++++------- .../iota_sdk/secret_manager/secret_manager.py | 20 +++++++++++-- .../iota_sdk/types/block/signed_block.py | 28 +++++++++++++++++++ 7 files changed, 114 insertions(+), 23 deletions(-) diff --git a/bindings/python/examples/client/06_simple_block.py b/bindings/python/examples/client/06_simple_block.py index 64147e881e..d0068fe4f0 100644 --- a/bindings/python/examples/client/06_simple_block.py +++ b/bindings/python/examples/client/06_simple_block.py @@ -1,10 +1,18 @@ import os +from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager from dotenv import load_dotenv from iota_sdk import Client, TaggedDataPayload, utf8_to_hex load_dotenv() node_url = os.environ.get('NODE_URL', 'https://api.testnet.shimmer.network') +issuer_id = os.environ.get( + 'ISSUER_ID', '0x0000000000000000000000000000000000000000000000000000000000000000') + +if 'MNEMONIC' not in os.environ: + raise Exception(".env MNEMONIC is undefined, see .env.example") + +secret_manager = SecretManager(MnemonicSecretManager(os.environ['MNEMONIC'])) # Create a Client instance client = Client(nodes=[node_url]) @@ -12,8 +20,12 @@ # Create and post a block without payload # TODO: have a way in the bindings to send an empty block # https://github.com/iotaledger/iota-sdk/issues/647 -block = client.submit_payload( +unsigned_block = client.build_basic_block( + issuer_id, TaggedDataPayload( utf8_to_hex("tag"), - utf8_to_hex("data"))) -print(f'Empty block sent: {os.environ["EXPLORER_URL"]}/block/{block[0]}') + utf8_to_hex("data")))[0] +signed_block = secret_manager.sign_block(unsigned_block) +block_id = client.post_block(signed_block) + +print(f'Empty block sent: {os.environ["EXPLORER_URL"]}/block/{block_id}') diff --git a/bindings/python/examples/client/08_data_block.py b/bindings/python/examples/client/08_data_block.py index fb068471bb..e01676483b 100644 --- a/bindings/python/examples/client/08_data_block.py +++ b/bindings/python/examples/client/08_data_block.py @@ -2,21 +2,32 @@ import json import os from dataclasses import asdict +from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager from dotenv import load_dotenv from iota_sdk import BasicBlock, Client, utf8_to_hex, hex_to_utf8, TaggedDataPayload load_dotenv() node_url = os.environ.get('NODE_URL', 'https://api.testnet.shimmer.network') +issuer_id = os.environ.get( + 'ISSUER_ID', '0x0000000000000000000000000000000000000000000000000000000000000000') + +if 'MNEMONIC' not in os.environ: + raise Exception(".env MNEMONIC is undefined, see .env.example") + +secret_manager = SecretManager(MnemonicSecretManager(os.environ['MNEMONIC'])) # Create a Client instance client = Client(nodes=[node_url]) # Create and post a block with a tagged data payload -block_id = client.submit_payload( +unsigned_block = client.build_basic_block( + issuer_id, TaggedDataPayload( utf8_to_hex("tag"), utf8_to_hex("data")))[0] +signed_block = secret_manager.sign_block(unsigned_block) +block_id = client.post_block(signed_block) print(f'Data block sent: {os.environ["EXPLORER_URL"]}/block/{block_id}') diff --git a/bindings/python/examples/client/post_raw_block.py b/bindings/python/examples/client/post_raw_block.py index 19c66fa539..a8b9723ec4 100644 --- a/bindings/python/examples/client/post_raw_block.py +++ b/bindings/python/examples/client/post_raw_block.py @@ -1,19 +1,30 @@ import os +from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager from dotenv import load_dotenv from iota_sdk import Client, TaggedDataPayload, utf8_to_hex load_dotenv() node_url = os.environ.get('NODE_URL', 'https://api.testnet.shimmer.network') +issuer_id = os.environ.get( + 'ISSUER_ID', '0x0000000000000000000000000000000000000000000000000000000000000000') + +if 'MNEMONIC' not in os.environ: + raise Exception(".env MNEMONIC is undefined, see .env.example") + +secret_manager = SecretManager(MnemonicSecretManager(os.environ['MNEMONIC'])) # Create a Client instance client = Client(nodes=[node_url]) # Create and post a block without payload -block_id = client.submit_payload( +unsigned_block = client.build_basic_block( + issuer_id, TaggedDataPayload( utf8_to_hex("tag"), utf8_to_hex("data")))[0] +signed_block = secret_manager.sign_block(unsigned_block) +block_id = client.post_block(signed_block) blockBytes = client.get_block_raw(block_id) # Post raw block diff --git a/bindings/python/examples/client/submit_and_read_block.py b/bindings/python/examples/client/submit_and_read_block.py index e5211702e7..10bbb97787 100644 --- a/bindings/python/examples/client/submit_and_read_block.py +++ b/bindings/python/examples/client/submit_and_read_block.py @@ -10,12 +10,20 @@ # Import the python iota client # Make sure you have first installed it with `pip install iota_sdk` import os +from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager from dotenv import load_dotenv from iota_sdk import BasicBlock, Client, hex_to_utf8, utf8_to_hex, TaggedDataPayload load_dotenv() node_url = os.environ.get('NODE_URL', 'https://api.testnet.shimmer.network') +issuer_id = os.environ.get( + 'ISSUER_ID', '0x0000000000000000000000000000000000000000000000000000000000000000') + +if 'MNEMONIC' not in os.environ: + raise Exception(".env MNEMONIC is undefined, see .env.example") + +secret_manager = SecretManager(MnemonicSecretManager(os.environ['MNEMONIC'])) # Create a Client instance client = Client(nodes=[node_url]) @@ -56,19 +64,19 @@ # Create and post a block with a tagged data payload # The client returns your block data (blockIdAndBlock) -blockIdAndBlock = client.submit_payload( +unsigned_block = client.build_basic_block( + issuer_id, TaggedDataPayload( utf8_to_hex("tag"), utf8_to_hex("data"))) - -block_id = blockIdAndBlock[0] -block = blockIdAndBlock[1] +signed_block = secret_manager.sign_block(unsigned_block) +block_id = client.post_block(signed_block) print('\nThe block ID for your submitted block is:') print(f' {block_id}') print('\nMetadata for your submitted block is:') -print(f' {block}') +print(f' {signed_block}') ######################################################## # Step 3: Use the block ID to read the payload back diff --git a/bindings/python/iota_sdk/client/client.py b/bindings/python/iota_sdk/client/client.py index 0215011b27..c4c0583047 100644 --- a/bindings/python/iota_sdk/client/client.py +++ b/bindings/python/iota_sdk/client/client.py @@ -13,7 +13,7 @@ from iota_sdk.client._high_level_api import HighLevelAPI from iota_sdk.client._utils import ClientUtils from iota_sdk.secret_manager.secret_manager import LedgerNanoSecretManager, MnemonicSecretManager, StrongholdSecretManager, SeedSecretManager -from bindings.python.iota_sdk.types.block.signed_block import SignedBlock +from bindings.python.iota_sdk.types.block.signed_block import UnsignedBlock from iota_sdk.types.common import HexStr, Node from iota_sdk.types.feature import Feature from iota_sdk.types.native_token import NativeToken @@ -394,21 +394,28 @@ def sign_transaction( 'preparedTransactionData': prepared_transaction_data })) - def submit_payload( - self, payload: Payload) -> List[Union[HexStr, SignedBlock]]: - """Submit a payload in a block. + def build_basic_block( + self, + issuer_id: HexStr, + payload: Payload, + strong_parents: Optional[List[HexStr]] + ) -> UnsignedBlock: + """Build a basic block. Args: - payload : The payload to submit. + issuer_id: The identifier of the block issuer account. + payload: The payload to submit. + strong_parents: Optional strong parents for the block. Returns: - List of HexStr or Block. + An unsigned block. """ - result = self._call_method('postBlockPayload', { - 'payload': payload.to_dict() + result = self._call_method('buildBasicBlock', { + 'issuerId': issuer_id, + 'payload': payload.to_dict(), + 'strongParents': strong_parents }) - result[1] = SignedBlock.from_dict(result[1]) - return result + return UnsignedBlock.from_dict(result) def listen_mqtt(self, topics: List[str], handler): """Listen to MQTT events. diff --git a/bindings/python/iota_sdk/secret_manager/secret_manager.py b/bindings/python/iota_sdk/secret_manager/secret_manager.py index 5612f8c2c4..b559ce1baf 100644 --- a/bindings/python/iota_sdk/secret_manager/secret_manager.py +++ b/bindings/python/iota_sdk/secret_manager/secret_manager.py @@ -3,6 +3,7 @@ from json import dumps, loads from typing import Optional, Union +from bindings.python.iota_sdk.types.block.signed_block import SignedBlock, UnsignedBlock from dacite import from_dict import humps @@ -251,7 +252,7 @@ def sign_ed25519(self, message: HexStr, chain: Bip44) -> Ed25519Signature: """ return Ed25519Signature.from_dict(self._call_method('signEd25519', { 'message': message, - 'chain': chain.__dict__, + 'chain': chain.to_dict(), })) def sign_secp256k1_ecdsa(self, message: HexStr, chain: Bip44): @@ -263,7 +264,7 @@ def sign_secp256k1_ecdsa(self, message: HexStr, chain: Bip44): """ return self._call_method('signSecp256k1Ecdsa', { 'message': message, - 'chain': chain.__dict__, + 'chain': chain.to_dict(), }) def sign_transaction( @@ -277,6 +278,19 @@ def sign_transaction( 'preparedTransactionData': prepared_transaction_data.to_dict() })) + def sign_block( + self, unsigned_block: UnsignedBlock, chain: Bip44) -> SignedBlock: + """Sign a block. + + Args: + unsigned_block: The unsigned block data. + chain: The Bip44 chain to use. + """ + return from_dict(SignedBlock, self._call_method('signBlock', { + 'unsignedBlock': unsigned_block.to_dict(), + 'chain': chain.to_dict() + })) + def signature_unlock(self, transaction_signing_hash: HexStr, chain: Bip44): """Sign a transaction hash. @@ -286,5 +300,5 @@ def signature_unlock(self, transaction_signing_hash: HexStr, chain: Bip44): """ return self._call_method('signatureUnlock', { 'transactionSigningHash': transaction_signing_hash, - 'chain': chain.__dict__, + 'chain': chain.to_dict(), }) diff --git a/bindings/python/iota_sdk/types/block/signed_block.py b/bindings/python/iota_sdk/types/block/signed_block.py index 31b19cd6ef..46439c6a77 100644 --- a/bindings/python/iota_sdk/types/block/signed_block.py +++ b/bindings/python/iota_sdk/types/block/signed_block.py @@ -48,4 +48,32 @@ def id(self, params: ProtocolParameters) -> HexStr: return Utils.block_id(self, params) +@json +@dataclass +class UnsignedBlock: + """An unsigned block type that can hold either a `BasicBlock` or a `ValidationBlock`. + Shared data is stored alongside such a block in the header fields. + + Attributes: + protocol_version: Protocol version of the network to which this block belongs. + network_id: The identifier of the network to which this block belongs. + issuing_time: The time at which the block was issued. It is a Unix timestamp in nanoseconds. + slot_commitment_id: The identifier of the slot to which this block commits. + latest_finalized_slot: The slot index of the latest finalized slot. + issuer_id: The identifier of the account that issued this block. + block: Holds either a `BasicBlock` or a `ValidationBlock`. + """ + protocol_version: int + network_id: int = field(metadata=config( + encoder=str + )) + issuing_time: int = field(metadata=config( + encoder=str + )) + slot_commitment_id: HexStr + latest_finalized_slot: SlotIndex + issuer_id: HexStr + block: Block + + Block: TypeAlias = Union[BasicBlock, ValidationBlock] From 4d4f64d1cdc00baecc3a4f995fc8caab0f924830 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 25 Oct 2023 14:55:58 -0400 Subject: [PATCH 06/20] update nodejs examples --- .../nodejs/examples/client/06-simple-block.ts | 38 +++++++++++++++++-- .../nodejs/examples/client/08-data-block.ts | 33 +++++++++++++--- .../nodejs/lib/types/client/bridge/index.ts | 4 +- bindings/nodejs/tests/client/examples.spec.ts | 34 ++++++++++++----- .../tests/client/messageMethods.spec.ts | 31 +++++++++++++-- 5 files changed, 116 insertions(+), 24 deletions(-) diff --git a/bindings/nodejs/examples/client/06-simple-block.ts b/bindings/nodejs/examples/client/06-simple-block.ts index 4893986e50..5f878f0f65 100644 --- a/bindings/nodejs/examples/client/06-simple-block.ts +++ b/bindings/nodejs/examples/client/06-simple-block.ts @@ -1,7 +1,14 @@ // Copyright 2021-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Client, initLogger, TaggedDataPayload, utf8ToHex } from '@iota/sdk'; +import { + CoinType, + Client, + initLogger, + TaggedDataPayload, + utf8ToHex, + SecretManager, +} from '@iota/sdk'; require('dotenv').config({ path: '.env' }); // Run with command: @@ -14,21 +21,44 @@ async function run() { throw new Error('.env NODE_URL is undefined, see .env.example'); } + if (!process.env.MNEMONIC) { + throw new Error('.env MNEMONIC is undefined, see .env.example'); + } + const mnemonicSecretManager = { + mnemonic: process.env.MNEMONIC, + }; + + const secretManager = new SecretManager(mnemonicSecretManager); + const client = new Client({ // Insert your node URL in the .env. nodes: [process.env.NODE_URL], }); + const issuerId = process.env.ISSUER_ID + ? process.env.ISSUER_ID + : '0x0000000000000000000000000000000000000000000000000000000000000000'; + + const chain = { + coinType: CoinType.Iota, + account: 0, + change: 0, + addressIndex: 0, + }; + try { // Create block with no payload // TODO: have a way in the bindings to send an empty block https://github.com/iotaledger/iota-sdk/issues/647 - const blockIdAndBlock = await client.postBlockPayload( + const unsignedBlock = await client.buildBasicBlock( + issuerId, new TaggedDataPayload(utf8ToHex('Hello'), utf8ToHex('Tangle')), ); - console.log('Block:', blockIdAndBlock, '\n'); + const signedBlock = await secretManager.signBlock(unsignedBlock, chain); + const blockId = await client.postBlock(signedBlock); + console.log('Block:', signedBlock, '\n'); console.log( - `Empty block sent: ${process.env.EXPLORER_URL}/block/${blockIdAndBlock[0]}`, + `Empty block sent: ${process.env.EXPLORER_URL}/block/${blockId}`, ); } catch (error) { console.error('Error: ', error); diff --git a/bindings/nodejs/examples/client/08-data-block.ts b/bindings/nodejs/examples/client/08-data-block.ts index 6ba245b7be..4fcb43bff6 100644 --- a/bindings/nodejs/examples/client/08-data-block.ts +++ b/bindings/nodejs/examples/client/08-data-block.ts @@ -2,11 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 import { + CoinType, Client, hexToUtf8, initLogger, TaggedDataPayload, utf8ToHex, + SecretManager, } from '@iota/sdk'; require('dotenv').config({ path: '.env' }); @@ -20,22 +22,43 @@ async function run() { throw new Error('.env NODE_URL is undefined, see .env.example'); } + if (!process.env.MNEMONIC) { + throw new Error('.env MNEMONIC is undefined, see .env.example'); + } + const mnemonicSecretManager = { + mnemonic: process.env.MNEMONIC, + }; + + const secretManager = new SecretManager(mnemonicSecretManager); + const client = new Client({ // Insert your node URL in the .env. nodes: [process.env.NODE_URL], }); + const issuerId = process.env.ISSUER_ID + ? process.env.ISSUER_ID + : '0x0000000000000000000000000000000000000000000000000000000000000000'; + + const chain = { + coinType: CoinType.Iota, + account: 0, + change: 0, + addressIndex: 0, + }; + try { // Create block with tagged payload - const blockIdAndBlock = await client.postBlockPayload( + const unsignedBlock = await client.buildBasicBlock( + issuerId, new TaggedDataPayload(utf8ToHex('Hello'), utf8ToHex('Tangle')), ); + const signedBlock = await secretManager.signBlock(unsignedBlock, chain); + const blockId = await client.postBlock(signedBlock); - console.log( - `Block sent: ${process.env.EXPLORER_URL}/block/${blockIdAndBlock[0]}`, - ); + console.log(`Block sent: ${process.env.EXPLORER_URL}/block/${blockId}`); - const fetchedBlock = await client.getBlock(blockIdAndBlock[0]); + const fetchedBlock = await client.getBlock(blockId); console.log('Block data: ', fetchedBlock); if (fetchedBlock.isBasic()) { diff --git a/bindings/nodejs/lib/types/client/bridge/index.ts b/bindings/nodejs/lib/types/client/bridge/index.ts index e807215cec..67034eeb92 100644 --- a/bindings/nodejs/lib/types/client/bridge/index.ts +++ b/bindings/nodejs/lib/types/client/bridge/index.ts @@ -14,7 +14,7 @@ import type { __GetBlockMetadataMethod__, __FindInputsMethod__, __SignTransactionMethod__, - __PostBlockPayloadMethod__, + __BuildBasicBlockMethod__, __GetNodeMethod__, __GetNetworkIdMethod__, __GetBech32HrpMethod__, @@ -64,7 +64,7 @@ export type __ClientMethods__ = | __FindInputsMethod__ | __SignTransactionMethod__ | __SignatureUnlockMethod__ - | __PostBlockPayloadMethod__ + | __BuildBasicBlockMethod__ | __GetNodeMethod__ | __GetNetworkIdMethod__ | __GetBech32HrpMethod__ diff --git a/bindings/nodejs/tests/client/examples.spec.ts b/bindings/nodejs/tests/client/examples.spec.ts index 34a6bdf988..a94aff8c28 100644 --- a/bindings/nodejs/tests/client/examples.spec.ts +++ b/bindings/nodejs/tests/client/examples.spec.ts @@ -10,6 +10,7 @@ import { SecretManager, TaggedDataPayload, CommonOutput, + CoinType, } from '../../'; import '../customMatchers'; import 'dotenv/config'; @@ -23,9 +24,19 @@ const client = new Client({ ], }); -const secretManager = { +const secretManager = new SecretManager({ mnemonic: 'endorse answer radar about source reunion marriage tag sausage weekend frost daring base attack because joke dream slender leisure group reason prepare broken river', +}); + +const issuerId = + '0x0000000000000000000000000000000000000000000000000000000000000000'; + +const chain = { + coinType: CoinType.Iota, + account: 0, + change: 0, + addressIndex: 0, }; // Skip for CI @@ -33,7 +44,9 @@ describe.skip('Main examples', () => { it('gets info about the node', async () => { const info = await client.getInfo(); - expect(info.nodeInfo.protocolParameters[0].parameters[0].bech32Hrp).toBe('rms'); + expect( + info.nodeInfo.protocolParameters[0].parameters[0].bech32Hrp, + ).toBe('rms'); }); it('generates a mnemonic', async () => { @@ -94,9 +107,7 @@ describe.skip('Main examples', () => { it('gets the balance of an address', async () => { // Generate the first address - const addresses = await new SecretManager( - secretManager, - ).generateEd25519Addresses({ + const addresses = await secretManager.generateEd25519Addresses({ accountIndex: 0, range: { start: 0, @@ -132,9 +143,9 @@ describe.skip('Main examples', () => { .getNativeTokens() ?.forEach( (token) => - (totalNativeTokens[token.id] = - (totalNativeTokens[token.id] || 0) + - Number(token.amount)), + (totalNativeTokens[token.id] = + (totalNativeTokens[token.id] || 0) + + Number(token.amount)), ); } @@ -169,11 +180,14 @@ describe.skip('Main examples', () => { }); it('sends a block with a tagged data payload', async () => { - const blockIdAndBlock = await client.postBlockPayload( + const unsignedBlock = await client.buildBasicBlock( + issuerId, new TaggedDataPayload(utf8ToHex('Hello'), utf8ToHex('Tangle')), ); + const signedBlock = await secretManager.signBlock(unsignedBlock, chain); + const blockId = await client.postBlock(signedBlock); - const fetchedBlock = await client.getBlock(blockIdAndBlock[0]); + const fetchedBlock = await client.getBlock(blockId); expect(fetchedBlock.payload).toStrictEqual( new TaggedDataPayload(utf8ToHex('Hello'), utf8ToHex('Tangle')), diff --git a/bindings/nodejs/tests/client/messageMethods.spec.ts b/bindings/nodejs/tests/client/messageMethods.spec.ts index 45d276d579..e1c1cf379a 100644 --- a/bindings/nodejs/tests/client/messageMethods.spec.ts +++ b/bindings/nodejs/tests/client/messageMethods.spec.ts @@ -5,7 +5,13 @@ import { describe, it } from '@jest/globals'; import 'reflect-metadata'; import 'dotenv/config'; -import { Client, utf8ToHex, TaggedDataPayload } from '../../'; +import { + CoinType, + Client, + utf8ToHex, + TaggedDataPayload, + SecretManager, +} from '../../'; import '../customMatchers'; const client = new Client({ @@ -16,12 +22,31 @@ const client = new Client({ ], }); +const secretManager = new SecretManager({ + mnemonic: + 'endorse answer radar about source reunion marriage tag sausage weekend frost daring base attack because joke dream slender leisure group reason prepare broken river', +}); + +const issuerId = + '0x0000000000000000000000000000000000000000000000000000000000000000'; + +const chain = { + coinType: CoinType.Iota, + account: 0, + change: 0, + addressIndex: 0, +}; + // Skip for CI describe.skip('Block methods', () => { it('sends a block raw', async () => { - const blockIdAndBlock = await client.postBlockPayload(new TaggedDataPayload(utf8ToHex('Hello'), utf8ToHex('Tangle'))); + const unsignedBlock = await client.buildBasicBlock( + issuerId, + new TaggedDataPayload(utf8ToHex('Hello'), utf8ToHex('Tangle')), + ); + const signedBlock = await secretManager.signBlock(unsignedBlock, chain); - const blockId = await client.postBlockRaw(blockIdAndBlock[1]); + const blockId = await client.postBlockRaw(signedBlock); expect(blockId).toBeValidBlockId(); }); From d7043246c3c10c84492124878b7e22ecb687642f Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 25 Oct 2023 15:00:30 -0400 Subject: [PATCH 07/20] fix python examples --- bindings/core/src/method/client.rs | 2 ++ bindings/python/examples/client/06_simple_block.py | 6 +++++- bindings/python/examples/client/08_data_block.py | 6 +++++- bindings/python/examples/client/post_raw_block.py | 6 +++++- bindings/python/examples/client/submit_and_read_block.py | 6 +++++- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/bindings/core/src/method/client.rs b/bindings/core/src/method/client.rs index 7b318f0c93..c3a4096db2 100644 --- a/bindings/core/src/method/client.rs +++ b/bindings/core/src/method/client.rs @@ -126,6 +126,8 @@ pub enum ClientMethod { BuildBasicBlock { /// The issuer's ID. issuer_id: IssuerId, + /// Optional strong parents for the block. + #[serde(default)] strong_parents: Option, /// The block payload. payload: PayloadDto, diff --git a/bindings/python/examples/client/06_simple_block.py b/bindings/python/examples/client/06_simple_block.py index d0068fe4f0..d4c8b81211 100644 --- a/bindings/python/examples/client/06_simple_block.py +++ b/bindings/python/examples/client/06_simple_block.py @@ -1,5 +1,7 @@ import os from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager +from bindings.python.iota_sdk.types.common import CoinType +from bindings.python.iota_sdk.types.signature import Bip44 from dotenv import load_dotenv from iota_sdk import Client, TaggedDataPayload, utf8_to_hex @@ -17,6 +19,8 @@ # Create a Client instance client = Client(nodes=[node_url]) +chain = Bip44(CoinType.IOTA) + # Create and post a block without payload # TODO: have a way in the bindings to send an empty block # https://github.com/iotaledger/iota-sdk/issues/647 @@ -25,7 +29,7 @@ TaggedDataPayload( utf8_to_hex("tag"), utf8_to_hex("data")))[0] -signed_block = secret_manager.sign_block(unsigned_block) +signed_block = secret_manager.sign_block(unsigned_block, chain) block_id = client.post_block(signed_block) print(f'Empty block sent: {os.environ["EXPLORER_URL"]}/block/{block_id}') diff --git a/bindings/python/examples/client/08_data_block.py b/bindings/python/examples/client/08_data_block.py index e01676483b..ac906bf002 100644 --- a/bindings/python/examples/client/08_data_block.py +++ b/bindings/python/examples/client/08_data_block.py @@ -3,6 +3,8 @@ import os from dataclasses import asdict from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager +from bindings.python.iota_sdk.types.common import CoinType +from bindings.python.iota_sdk.types.signature import Bip44 from dotenv import load_dotenv from iota_sdk import BasicBlock, Client, utf8_to_hex, hex_to_utf8, TaggedDataPayload @@ -20,13 +22,15 @@ # Create a Client instance client = Client(nodes=[node_url]) +chain = Bip44(CoinType.IOTA) + # Create and post a block with a tagged data payload unsigned_block = client.build_basic_block( issuer_id, TaggedDataPayload( utf8_to_hex("tag"), utf8_to_hex("data")))[0] -signed_block = secret_manager.sign_block(unsigned_block) +signed_block = secret_manager.sign_block(unsigned_block, chain) block_id = client.post_block(signed_block) print(f'Data block sent: {os.environ["EXPLORER_URL"]}/block/{block_id}') diff --git a/bindings/python/examples/client/post_raw_block.py b/bindings/python/examples/client/post_raw_block.py index a8b9723ec4..e4eba9f66d 100644 --- a/bindings/python/examples/client/post_raw_block.py +++ b/bindings/python/examples/client/post_raw_block.py @@ -1,5 +1,7 @@ import os from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager +from bindings.python.iota_sdk.types.common import CoinType +from bindings.python.iota_sdk.types.signature import Bip44 from dotenv import load_dotenv from iota_sdk import Client, TaggedDataPayload, utf8_to_hex @@ -17,13 +19,15 @@ # Create a Client instance client = Client(nodes=[node_url]) +chain = Bip44(CoinType.IOTA) + # Create and post a block without payload unsigned_block = client.build_basic_block( issuer_id, TaggedDataPayload( utf8_to_hex("tag"), utf8_to_hex("data")))[0] -signed_block = secret_manager.sign_block(unsigned_block) +signed_block = secret_manager.sign_block(unsigned_block, chain) block_id = client.post_block(signed_block) blockBytes = client.get_block_raw(block_id) diff --git a/bindings/python/examples/client/submit_and_read_block.py b/bindings/python/examples/client/submit_and_read_block.py index 10bbb97787..135c6ac1d0 100644 --- a/bindings/python/examples/client/submit_and_read_block.py +++ b/bindings/python/examples/client/submit_and_read_block.py @@ -11,6 +11,8 @@ # Make sure you have first installed it with `pip install iota_sdk` import os from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager +from bindings.python.iota_sdk.types.common import CoinType +from bindings.python.iota_sdk.types.signature import Bip44 from dotenv import load_dotenv from iota_sdk import BasicBlock, Client, hex_to_utf8, utf8_to_hex, TaggedDataPayload @@ -62,6 +64,8 @@ # A block must be built, to which the payload is attached. # The submit_payload function handles this task. +chain = Bip44(CoinType.IOTA) + # Create and post a block with a tagged data payload # The client returns your block data (blockIdAndBlock) unsigned_block = client.build_basic_block( @@ -69,7 +73,7 @@ TaggedDataPayload( utf8_to_hex("tag"), utf8_to_hex("data"))) -signed_block = secret_manager.sign_block(unsigned_block) +signed_block = secret_manager.sign_block(unsigned_block, chain) block_id = client.post_block(signed_block) print('\nThe block ID for your submitted block is:') From 55ee3a6e8d5022eb7772685f2a911c6430f41bf4 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 25 Oct 2023 15:04:01 -0400 Subject: [PATCH 08/20] review --- sdk/src/types/block/core/signed_block.rs | 12 ++++++------ sdk/src/types/block/macro.rs | 4 ++-- sdk/src/types/block/mod.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sdk/src/types/block/core/signed_block.rs b/sdk/src/types/block/core/signed_block.rs index 997d86b3ae..0c6b13ca2f 100644 --- a/sdk/src/types/block/core/signed_block.rs +++ b/sdk/src/types/block/core/signed_block.rs @@ -314,25 +314,25 @@ impl Packable for SignedBlock { let signature = Signature::unpack::<_, VERIFY>(unpacker, &())?; - let wrapper = Self { + let signed_block = Self { header, block, signature, }; if VERIFY { - let wrapper_len = if let (Some(start), Some(end)) = (start_opt, unpacker.read_bytes()) { + let signed_block_len = if let (Some(start), Some(end)) = (start_opt, unpacker.read_bytes()) { end - start } else { - wrapper.packed_len() + signed_block.packed_len() }; - if wrapper_len > Self::LENGTH_MAX { - return Err(UnpackError::Packable(Error::InvalidSignedBlockLength(wrapper_len))); + if signed_block_len > Self::LENGTH_MAX { + return Err(UnpackError::Packable(Error::InvalidSignedBlockLength(signed_block_len))); } } - Ok(wrapper) + Ok(signed_block) } } diff --git a/sdk/src/types/block/macro.rs b/sdk/src/types/block/macro.rs index b1423707f8..d4783a93cd 100644 --- a/sdk/src/types/block/macro.rs +++ b/sdk/src/types/block/macro.rs @@ -36,13 +36,13 @@ macro_rules! impl_id { $len_vis const LENGTH: usize = $length; #[doc = core::concat!("Creates a new [`", core::stringify!($hash_name), "`].")] - $hash_vis const fn new(bytes: [u8; $hash_name::LENGTH]) -> Self { + $hash_vis const fn new(bytes: [u8; Self::LENGTH]) -> Self { Self(bytes) } #[doc = core::concat!("Creates a null [`", core::stringify!($hash_name), "`].")] $hash_vis const fn null() -> Self { - Self([0u8; $hash_name::LENGTH]) + Self([0u8; Self::LENGTH]) } #[doc = core::concat!("Checks if the [`", core::stringify!($hash_name), "`] is null.")] diff --git a/sdk/src/types/block/mod.rs b/sdk/src/types/block/mod.rs index 5ccab0c4b1..d010281bab 100644 --- a/sdk/src/types/block/mod.rs +++ b/sdk/src/types/block/mod.rs @@ -47,7 +47,7 @@ pub(crate) use self::r#macro::*; pub use self::{ block_id::{BlockHash, BlockId}, convert::ConvertTo, - core::{Block, SignedBlock}, + core::{Block, SignedBlock, UnsignedBlock}, error::Error, issuer_id::IssuerId, }; From 4ef580890f185420c7ca22f5de16f58678792322 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 25 Oct 2023 17:16:42 -0400 Subject: [PATCH 09/20] reviews --- bindings/core/src/method/client.rs | 5 +++- bindings/core/src/method_handler/client.rs | 28 ++++++++++--------- bindings/core/src/response.rs | 1 + bindings/core/tests/combined.rs | 2 +- .../lib/secret_manager/secret-manager.ts | 2 +- .../python/examples/client/06_simple_block.py | 5 +--- .../python/examples/client/08_data_block.py | 5 +--- .../python/examples/client/post_raw_block.py | 5 +--- .../examples/client/submit_and_read_block.py | 5 +--- .../python/iota_sdk/client/_high_level_api.py | 2 +- .../python/iota_sdk/client/_node_core_api.py | 2 +- bindings/python/iota_sdk/client/client.py | 2 +- .../iota_sdk/secret_manager/secret_manager.py | 2 +- sdk/examples/.env.example | 1 + 14 files changed, 31 insertions(+), 36 deletions(-) diff --git a/bindings/core/src/method/client.rs b/bindings/core/src/method/client.rs index c3a4096db2..a9c4128cbe 100644 --- a/bindings/core/src/method/client.rs +++ b/bindings/core/src/method/client.rs @@ -123,6 +123,7 @@ pub enum ClientMethod { query_params: Vec, request_object: Option, }, + #[serde(rename_all = "camelCase")] BuildBasicBlock { /// The issuer's ID. issuer_id: IssuerId, @@ -130,7 +131,8 @@ pub enum ClientMethod { #[serde(default)] strong_parents: Option, /// The block payload. - payload: PayloadDto, + #[serde(default)] + payload: Option, }, ////////////////////////////////////////////////////////////////////// // Node core API @@ -336,6 +338,7 @@ pub enum ClientMethod { address: Bech32Address, }, /// Returns a block ID from a block + #[serde(rename_all = "camelCase")] BlockId { /// Block signed_block: SignedBlockDto, diff --git a/bindings/core/src/method_handler/client.rs b/bindings/core/src/method_handler/client.rs index 0f5a9e5a81..896f000dbb 100644 --- a/bindings/core/src/method_handler/client.rs +++ b/bindings/core/src/method_handler/client.rs @@ -165,19 +165,21 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM issuer_id, strong_parents, payload, - } => Response::UnsignedBlock(UnsignedBlockDto::from( - &client - .build_basic_block( - issuer_id, - None, - strong_parents, - Some(Payload::try_from_dto_with_params( - payload, - &client.get_protocol_parameters().await?, - )?), - ) - .await?, - )), + } => { + let payload = if let Some(payload) = payload { + Some(Payload::try_from_dto_with_params( + payload, + &client.get_protocol_parameters().await?, + )?) + } else { + None + }; + Response::UnsignedBlock(UnsignedBlockDto::from( + &client + .build_basic_block(issuer_id, None, strong_parents, payload) + .await?, + )) + } #[cfg(feature = "mqtt")] ClientMethod::ClearListeners { topics } => { client.unsubscribe(topics).await?; diff --git a/bindings/core/src/response.rs b/bindings/core/src/response.rs index abaf71f4bc..5ba2b88ef8 100644 --- a/bindings/core/src/response.rs +++ b/bindings/core/src/response.rs @@ -110,6 +110,7 @@ pub enum Response { /// Response for: /// - [`GetBlock`](crate::method::ClientMethod::GetBlock) /// - [`GetIncludedBlock`](crate::method::ClientMethod::GetIncludedBlock) + /// - [`SignBlock`](crate::method::SecretManagerMethod::SignBlock) SignedBlock(SignedBlockDto), /// Response for: /// - [`GetBlockMetadata`](crate::method::ClientMethod::GetBlockMetadata) diff --git a/bindings/core/tests/combined.rs b/bindings/core/tests/combined.rs index 7c1e825c77..5e84efbb1a 100644 --- a/bindings/core/tests/combined.rs +++ b/bindings/core/tests/combined.rs @@ -274,7 +274,7 @@ async fn build_and_sign_block() -> Result<()> { ClientMethod::BuildBasicBlock { issuer_id: IssuerId::null(), strong_parents: None, - payload: payload.clone(), + payload: Some(payload.clone()), }, ) .await; diff --git a/bindings/nodejs/lib/secret_manager/secret-manager.ts b/bindings/nodejs/lib/secret_manager/secret-manager.ts index 83e1db5594..7ccaeecd91 100644 --- a/bindings/nodejs/lib/secret_manager/secret-manager.ts +++ b/bindings/nodejs/lib/secret_manager/secret-manager.ts @@ -117,7 +117,7 @@ export class SecretManager { * * @param unsignedBlock An unsigned block. * @param chain A BIP44 chain. - * @returns The corresponding transaction payload. + * @returns The signed block. */ async signBlock( unsignedBlock: UnsignedBlock, diff --git a/bindings/python/examples/client/06_simple_block.py b/bindings/python/examples/client/06_simple_block.py index d4c8b81211..734444a108 100644 --- a/bindings/python/examples/client/06_simple_block.py +++ b/bindings/python/examples/client/06_simple_block.py @@ -1,9 +1,6 @@ import os -from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager -from bindings.python.iota_sdk.types.common import CoinType -from bindings.python.iota_sdk.types.signature import Bip44 from dotenv import load_dotenv -from iota_sdk import Client, TaggedDataPayload, utf8_to_hex +from iota_sdk import MnemonicSecretManager, CoinType, SecretManager, Client, TaggedDataPayload, utf8_to_hex, Bip44 load_dotenv() diff --git a/bindings/python/examples/client/08_data_block.py b/bindings/python/examples/client/08_data_block.py index ac906bf002..900313a537 100644 --- a/bindings/python/examples/client/08_data_block.py +++ b/bindings/python/examples/client/08_data_block.py @@ -2,11 +2,8 @@ import json import os from dataclasses import asdict -from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager -from bindings.python.iota_sdk.types.common import CoinType -from bindings.python.iota_sdk.types.signature import Bip44 from dotenv import load_dotenv -from iota_sdk import BasicBlock, Client, utf8_to_hex, hex_to_utf8, TaggedDataPayload +from iota_sdk import BasicBlock, Bip44, CoinType, Client, utf8_to_hex, hex_to_utf8, TaggedDataPayload, MnemonicSecretManager, SecretManager load_dotenv() diff --git a/bindings/python/examples/client/post_raw_block.py b/bindings/python/examples/client/post_raw_block.py index e4eba9f66d..ea60a51839 100644 --- a/bindings/python/examples/client/post_raw_block.py +++ b/bindings/python/examples/client/post_raw_block.py @@ -1,9 +1,6 @@ import os -from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager -from bindings.python.iota_sdk.types.common import CoinType -from bindings.python.iota_sdk.types.signature import Bip44 from dotenv import load_dotenv -from iota_sdk import Client, TaggedDataPayload, utf8_to_hex +from iota_sdk import Bip44, Client, CoinType, TaggedDataPayload, utf8_to_hex, MnemonicSecretManager, SecretManager load_dotenv() diff --git a/bindings/python/examples/client/submit_and_read_block.py b/bindings/python/examples/client/submit_and_read_block.py index 135c6ac1d0..00002ff09b 100644 --- a/bindings/python/examples/client/submit_and_read_block.py +++ b/bindings/python/examples/client/submit_and_read_block.py @@ -10,11 +10,8 @@ # Import the python iota client # Make sure you have first installed it with `pip install iota_sdk` import os -from bindings.python.iota_sdk.secret_manager.secret_manager import MnemonicSecretManager, SecretManager -from bindings.python.iota_sdk.types.common import CoinType -from bindings.python.iota_sdk.types.signature import Bip44 from dotenv import load_dotenv -from iota_sdk import BasicBlock, Client, hex_to_utf8, utf8_to_hex, TaggedDataPayload +from iota_sdk import BasicBlock, Bip44, Client, CoinType, hex_to_utf8, utf8_to_hex, TaggedDataPayload, MnemonicSecretManager, SecretManager load_dotenv() diff --git a/bindings/python/iota_sdk/client/_high_level_api.py b/bindings/python/iota_sdk/client/_high_level_api.py index bdb376ae4d..cc9bfb0601 100644 --- a/bindings/python/iota_sdk/client/_high_level_api.py +++ b/bindings/python/iota_sdk/client/_high_level_api.py @@ -4,7 +4,7 @@ from typing import List, Optional from dataclasses import dataclass from abc import ABCMeta, abstractmethod -from bindings.python.iota_sdk.types.block.signed_block import SignedBlock +from iota_sdk.types.block.signed_block import SignedBlock from iota_sdk.types.common import CoinType, HexStr, json from iota_sdk.types.output_metadata import OutputWithMetadata from iota_sdk.types.output_id import OutputId diff --git a/bindings/python/iota_sdk/client/_node_core_api.py b/bindings/python/iota_sdk/client/_node_core_api.py index 50a2649d59..84ad26bed2 100644 --- a/bindings/python/iota_sdk/client/_node_core_api.py +++ b/bindings/python/iota_sdk/client/_node_core_api.py @@ -5,7 +5,7 @@ from abc import ABCMeta, abstractmethod from dacite import from_dict -from bindings.python.iota_sdk.types.block.signed_block import SignedBlock +from iota_sdk.types.block.signed_block import SignedBlock from iota_sdk.types.block.metadata import BlockMetadata from iota_sdk.types.common import HexStr from iota_sdk.types.node_info import NodeInfo, NodeInfoWrapper diff --git a/bindings/python/iota_sdk/client/client.py b/bindings/python/iota_sdk/client/client.py index c4c0583047..12742cabee 100644 --- a/bindings/python/iota_sdk/client/client.py +++ b/bindings/python/iota_sdk/client/client.py @@ -13,7 +13,7 @@ from iota_sdk.client._high_level_api import HighLevelAPI from iota_sdk.client._utils import ClientUtils from iota_sdk.secret_manager.secret_manager import LedgerNanoSecretManager, MnemonicSecretManager, StrongholdSecretManager, SeedSecretManager -from bindings.python.iota_sdk.types.block.signed_block import UnsignedBlock +from iota_sdk.types.block.signed_block import UnsignedBlock from iota_sdk.types.common import HexStr, Node from iota_sdk.types.feature import Feature from iota_sdk.types.native_token import NativeToken diff --git a/bindings/python/iota_sdk/secret_manager/secret_manager.py b/bindings/python/iota_sdk/secret_manager/secret_manager.py index b559ce1baf..97c9fec4cc 100644 --- a/bindings/python/iota_sdk/secret_manager/secret_manager.py +++ b/bindings/python/iota_sdk/secret_manager/secret_manager.py @@ -3,11 +3,11 @@ from json import dumps, loads from typing import Optional, Union -from bindings.python.iota_sdk.types.block.signed_block import SignedBlock, UnsignedBlock from dacite import from_dict import humps from iota_sdk.external import create_secret_manager, call_secret_manager_method +from iota_sdk.types.block.signed_block import SignedBlock, UnsignedBlock from iota_sdk.types.common import HexStr from iota_sdk.types.signature import Ed25519Signature, Bip44 from iota_sdk.types.transaction_data import PreparedTransactionData diff --git a/sdk/examples/.env.example b/sdk/examples/.env.example index 7e6c1b0215..54792ec99f 100644 --- a/sdk/examples/.env.example +++ b/sdk/examples/.env.example @@ -18,3 +18,4 @@ NODE_URL="https://api.testnet.shimmer.network" FAUCET_URL="https://faucet.testnet.shimmer.network/api/enqueue" # The explorer URL to look up transactions, blocks, addresses and more EXPLORER_URL="https://explorer.shimmer.network/testnet" +ISSUER_ID="0x0000000000000000000000000000000000000000000000000000000000000000"; From 976403da1eaf683ce668fd40272a7522f2ffb7c1 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Thu, 26 Oct 2023 10:22:22 +0200 Subject: [PATCH 10/20] Remove last bindings.python. --- bindings/python/iota_sdk/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/iota_sdk/utils.py b/bindings/python/iota_sdk/utils.py index d95acda086..e889f74cfb 100644 --- a/bindings/python/iota_sdk/utils.py +++ b/bindings/python/iota_sdk/utils.py @@ -17,7 +17,7 @@ # Required to prevent circular import if TYPE_CHECKING: - from bindings.python.iota_sdk.types.block.signed_block import SignedBlock + from iota_sdk.types.block.signed_block import SignedBlock # pylint: disable=too-many-public-methods From 645c237cc3e42a13ea33e51277f79e19a482318b Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Thu, 26 Oct 2023 10:24:55 +0200 Subject: [PATCH 11/20] Add ISSUER_ID to all .env.examples --- bindings/nodejs/examples/.env.example | 2 ++ bindings/python/examples/.env.example | 2 ++ sdk/examples/.env.example | 1 + 3 files changed, 5 insertions(+) diff --git a/bindings/nodejs/examples/.env.example b/bindings/nodejs/examples/.env.example index 7e6c1b0215..cacb4f080e 100644 --- a/bindings/nodejs/examples/.env.example +++ b/bindings/nodejs/examples/.env.example @@ -18,3 +18,5 @@ NODE_URL="https://api.testnet.shimmer.network" FAUCET_URL="https://faucet.testnet.shimmer.network/api/enqueue" # The explorer URL to look up transactions, blocks, addresses and more EXPLORER_URL="https://explorer.shimmer.network/testnet" +# The issuer ID to use when building blocks +ISSUER_ID="0x0000000000000000000000000000000000000000000000000000000000000000"; \ No newline at end of file diff --git a/bindings/python/examples/.env.example b/bindings/python/examples/.env.example index 7e6c1b0215..cacb4f080e 100644 --- a/bindings/python/examples/.env.example +++ b/bindings/python/examples/.env.example @@ -18,3 +18,5 @@ NODE_URL="https://api.testnet.shimmer.network" FAUCET_URL="https://faucet.testnet.shimmer.network/api/enqueue" # The explorer URL to look up transactions, blocks, addresses and more EXPLORER_URL="https://explorer.shimmer.network/testnet" +# The issuer ID to use when building blocks +ISSUER_ID="0x0000000000000000000000000000000000000000000000000000000000000000"; \ No newline at end of file diff --git a/sdk/examples/.env.example b/sdk/examples/.env.example index 54792ec99f..d51040423a 100644 --- a/sdk/examples/.env.example +++ b/sdk/examples/.env.example @@ -18,4 +18,5 @@ NODE_URL="https://api.testnet.shimmer.network" FAUCET_URL="https://faucet.testnet.shimmer.network/api/enqueue" # The explorer URL to look up transactions, blocks, addresses and more EXPLORER_URL="https://explorer.shimmer.network/testnet" +# The issuer ID to use when building blocks ISSUER_ID="0x0000000000000000000000000000000000000000000000000000000000000000"; From f9908f5e38c486bba935b6a9eaecb5c44a14d7ae Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Thu, 26 Oct 2023 12:16:40 +0200 Subject: [PATCH 12/20] Simpler build_basic_block --- bindings/core/src/method/client.rs | 4 ---- bindings/core/src/method_handler/client.rs | 10 ++-------- bindings/core/tests/combined.rs | 1 - .../client/block/00_block_no_payload.rs | 2 +- .../client/block/01_block_confirmation_time.rs | 2 +- .../client/block/02_block_custom_parents.rs | 3 ++- .../client/block/03_block_custom_payload.rs | 2 +- .../client/block/04_block_tagged_data.rs | 2 -- .../client/node_api_core/04_post_block.rs | 2 +- .../client/node_api_core/05_post_block_raw.rs | 2 +- sdk/src/client/api/block_builder/mod.rs | 18 ++++++------------ sdk/src/wallet/account/operations/reissue.rs | 4 ---- .../transaction/submit_transaction.rs | 7 +------ sdk/tests/client/node_api/mod.rs | 2 -- 14 files changed, 16 insertions(+), 45 deletions(-) diff --git a/bindings/core/src/method/client.rs b/bindings/core/src/method/client.rs index a9c4128cbe..687e37580d 100644 --- a/bindings/core/src/method/client.rs +++ b/bindings/core/src/method/client.rs @@ -8,7 +8,6 @@ use iota_sdk::{ client::{node_api::indexer::query_parameters::QueryParameter, node_manager::node::NodeAuth}, types::block::{ address::{Bech32Address, Hrp}, - core::basic, output::{ dto::OutputDto, feature::Feature, unlock_condition::dto::UnlockConditionDto, AccountId, FoundryId, NativeToken, NftId, OutputId, TokenScheme, @@ -127,9 +126,6 @@ pub enum ClientMethod { BuildBasicBlock { /// The issuer's ID. issuer_id: IssuerId, - /// Optional strong parents for the block. - #[serde(default)] - strong_parents: Option, /// The block payload. #[serde(default)] payload: Option, diff --git a/bindings/core/src/method_handler/client.rs b/bindings/core/src/method_handler/client.rs index 896f000dbb..c59976470f 100644 --- a/bindings/core/src/method_handler/client.rs +++ b/bindings/core/src/method_handler/client.rs @@ -161,11 +161,7 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM Response::Output(OutputDto::from(&output)) } - ClientMethod::BuildBasicBlock { - issuer_id, - strong_parents, - payload, - } => { + ClientMethod::BuildBasicBlock { issuer_id, payload } => { let payload = if let Some(payload) = payload { Some(Payload::try_from_dto_with_params( payload, @@ -175,9 +171,7 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM None }; Response::UnsignedBlock(UnsignedBlockDto::from( - &client - .build_basic_block(issuer_id, None, strong_parents, payload) - .await?, + &client.build_basic_block(issuer_id, payload).await?, )) } #[cfg(feature = "mqtt")] diff --git a/bindings/core/tests/combined.rs b/bindings/core/tests/combined.rs index 5e84efbb1a..0e2608a535 100644 --- a/bindings/core/tests/combined.rs +++ b/bindings/core/tests/combined.rs @@ -273,7 +273,6 @@ async fn build_and_sign_block() -> Result<()> { &client, ClientMethod::BuildBasicBlock { issuer_id: IssuerId::null(), - strong_parents: None, payload: Some(payload.clone()), }, ) diff --git a/sdk/examples/client/block/00_block_no_payload.rs b/sdk/examples/client/block/00_block_no_payload.rs index 5ea4a41aef..77b86733ac 100644 --- a/sdk/examples/client/block/00_block_no_payload.rs +++ b/sdk/examples/client/block/00_block_no_payload.rs @@ -33,7 +33,7 @@ async fn main() -> Result<()> { // Create and send the block. let block = client - .build_basic_block(issuer_id, None, None, None) + .build_basic_block(issuer_id, None) .await? .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; diff --git a/sdk/examples/client/block/01_block_confirmation_time.rs b/sdk/examples/client/block/01_block_confirmation_time.rs index 66bb168bbf..927376169d 100644 --- a/sdk/examples/client/block/01_block_confirmation_time.rs +++ b/sdk/examples/client/block/01_block_confirmation_time.rs @@ -33,7 +33,7 @@ async fn main() -> Result<()> { // Create and send a block. let block = client - .build_basic_block(issuer_id, None, None, None) + .build_basic_block(issuer_id, None) .await? .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; diff --git a/sdk/examples/client/block/02_block_custom_parents.rs b/sdk/examples/client/block/02_block_custom_parents.rs index 5e8eb5325b..3085a5a12a 100644 --- a/sdk/examples/client/block/02_block_custom_parents.rs +++ b/sdk/examples/client/block/02_block_custom_parents.rs @@ -36,8 +36,9 @@ async fn main() -> Result<()> { println!("Issuance:\n{issuance:#?}"); // Create and send the block with custom parents. + // TODO set Some(issuance.strong_parents()? let block = client - .build_basic_block(issuer_id, None, Some(issuance.strong_parents()?), None) + .build_basic_block(issuer_id, None) .await? .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; diff --git a/sdk/examples/client/block/03_block_custom_payload.rs b/sdk/examples/client/block/03_block_custom_payload.rs index 7b48af2fca..db67b48390 100644 --- a/sdk/examples/client/block/03_block_custom_payload.rs +++ b/sdk/examples/client/block/03_block_custom_payload.rs @@ -39,7 +39,7 @@ async fn main() -> Result<()> { // Create and send the block with the custom payload. let block = client - .build_basic_block(issuer_id, None, None, Some(Payload::from(tagged_data_payload))) + .build_basic_block(issuer_id, Some(Payload::from(tagged_data_payload))) .await? .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; diff --git a/sdk/examples/client/block/04_block_tagged_data.rs b/sdk/examples/client/block/04_block_tagged_data.rs index 55cef29bd2..7799a80bf9 100644 --- a/sdk/examples/client/block/04_block_tagged_data.rs +++ b/sdk/examples/client/block/04_block_tagged_data.rs @@ -38,8 +38,6 @@ async fn main() -> Result<()> { let block = client .build_basic_block( issuer_id, - None, - None, Some(Payload::TaggedData(Box::new( TaggedDataPayload::new( std::env::args() diff --git a/sdk/examples/client/node_api_core/04_post_block.rs b/sdk/examples/client/node_api_core/04_post_block.rs index 35be7f1038..c11d780ae4 100644 --- a/sdk/examples/client/node_api_core/04_post_block.rs +++ b/sdk/examples/client/node_api_core/04_post_block.rs @@ -36,7 +36,7 @@ async fn main() -> Result<()> { // Create the block. let block = client - .build_basic_block(issuer_id, None, None, None) + .build_basic_block(issuer_id, None) .await? .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; diff --git a/sdk/examples/client/node_api_core/05_post_block_raw.rs b/sdk/examples/client/node_api_core/05_post_block_raw.rs index 0d34eece6f..d62d366a5c 100644 --- a/sdk/examples/client/node_api_core/05_post_block_raw.rs +++ b/sdk/examples/client/node_api_core/05_post_block_raw.rs @@ -36,7 +36,7 @@ async fn main() -> Result<()> { // Create the block. let block = client - .build_basic_block(issuer_id, None, None, None) + .build_basic_block(issuer_id, None) .await? .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) .await?; diff --git a/sdk/src/client/api/block_builder/mod.rs b/sdk/src/client/api/block_builder/mod.rs index a00846ad30..ca2e99a72e 100644 --- a/sdk/src/client/api/block_builder/mod.rs +++ b/sdk/src/client/api/block_builder/mod.rs @@ -8,24 +8,17 @@ pub use self::transaction::verify_semantic; use crate::{ client::{ClientInner, Result}, types::block::{ - core::{basic, BlockHeader, UnsignedBlock}, + core::{BlockHeader, UnsignedBlock}, payload::Payload, Block, IssuerId, }, }; impl ClientInner { - pub async fn build_basic_block( - &self, - issuer_id: IssuerId, - issuing_time: Option, - strong_parents: Option, - payload: Option, - ) -> Result { + pub async fn build_basic_block(&self, issuer_id: IssuerId, payload: Option) -> Result { let issuance = self.get_issuance().await?; - let strong_parents = strong_parents.unwrap_or(issuance.strong_parents()?); - let issuing_time = issuing_time.unwrap_or_else(|| { + let issuing_time = { #[cfg(feature = "std")] let issuing_time = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -36,7 +29,7 @@ impl ClientInner { #[cfg(not(feature = "std"))] let issuing_time = 0; issuing_time - }); + }; let protocol_params = self.get_protocol_parameters().await?; @@ -49,7 +42,8 @@ impl ClientInner { issuance.latest_finalized_slot, issuer_id, ), - Block::build_basic(strong_parents, 0) // TODO: burned mana calculation + // TODO: burned mana calculation + Block::build_basic(issuance.strong_parents()?, 0) .with_weak_parents(issuance.weak_parents()?) .with_shallow_like_parents(issuance.shallow_like_parents()?) .with_payload(payload) diff --git a/sdk/src/wallet/account/operations/reissue.rs b/sdk/src/wallet/account/operations/reissue.rs index 0fa8d596b2..2eff243a9f 100644 --- a/sdk/src/wallet/account/operations/reissue.rs +++ b/sdk/src/wallet/account/operations/reissue.rs @@ -63,8 +63,6 @@ where .client() .build_basic_block( todo!("issuer id"), - todo!("issuing time"), - None, Some(Payload::SignedTransaction(Box::new(transaction.payload.clone()))), ) .await? @@ -113,8 +111,6 @@ where .client() .build_basic_block( todo!("issuer id"), - todo!("issuing time"), - None, Some(Payload::SignedTransaction(Box::new(transaction.payload.clone()))), ) .await? diff --git a/sdk/src/wallet/account/operations/transaction/submit_transaction.rs b/sdk/src/wallet/account/operations/transaction/submit_transaction.rs index 724cc7353e..28b4bc015b 100644 --- a/sdk/src/wallet/account/operations/transaction/submit_transaction.rs +++ b/sdk/src/wallet/account/operations/transaction/submit_transaction.rs @@ -27,12 +27,7 @@ where let block = self .client() - .build_basic_block( - todo!("issuer id"), - todo!("issuing time"), - None, - Some(Payload::from(transaction_payload)), - ) + .build_basic_block(todo!("issuer id"), Some(Payload::from(transaction_payload))) .await? .sign_ed25519( &*self.get_secret_manager().read().await, diff --git a/sdk/tests/client/node_api/mod.rs b/sdk/tests/client/node_api/mod.rs index c4c675bfca..967a07af8c 100644 --- a/sdk/tests/client/node_api/mod.rs +++ b/sdk/tests/client/node_api/mod.rs @@ -36,8 +36,6 @@ async fn setup_tagged_data_block(secret_manager: &SecretManager) -> BlockId { client .build_basic_block( IssuerId::null(), - None, - None, Some(Payload::TaggedData(Box::new( TaggedDataPayload::new(b"Hello".to_vec(), b"Tangle".to_vec()).unwrap(), ))), From f80bb21523ca6cad147bef30d930d0690155b4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thoralf=20M=C3=BCller?= Date: Thu, 26 Oct 2023 14:53:29 +0200 Subject: [PATCH 13/20] Update bindings --- bindings/nodejs/lib/client/client.ts | 5 +---- bindings/nodejs/lib/types/client/bridge/client.ts | 3 +-- bindings/python/iota_sdk/client/client.py | 9 ++++----- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/bindings/nodejs/lib/client/client.ts b/bindings/nodejs/lib/client/client.ts index 9ab777d471..b974c95066 100644 --- a/bindings/nodejs/lib/client/client.ts +++ b/bindings/nodejs/lib/client/client.ts @@ -299,19 +299,16 @@ export class Client { * * @param issuerId The identifier of the block issuer account. * @param payload The payload to post. - * @param strongParents Optional strong parents to use for the block. * @returns The block ID followed by the block containing the payload. */ async buildBasicBlock( issuerId: IssuerId, - payload: Payload, - strongParents?: [BlockId], + payload?: Payload, ): Promise { const response = await this.methodHandler.callMethod({ name: 'buildBasicBlock', data: { issuerId, - strongParents, payload, }, }); diff --git a/bindings/nodejs/lib/types/client/bridge/client.ts b/bindings/nodejs/lib/types/client/bridge/client.ts index 3dd35997a3..8d3221c425 100644 --- a/bindings/nodejs/lib/types/client/bridge/client.ts +++ b/bindings/nodejs/lib/types/client/bridge/client.ts @@ -122,8 +122,7 @@ export interface __BuildBasicBlockMethod__ { name: 'buildBasicBlock'; data: { issuerId: IssuerId; - parents?: [BlockId]; - payload: Payload; + payload?: Payload; }; } diff --git a/bindings/python/iota_sdk/client/client.py b/bindings/python/iota_sdk/client/client.py index 12742cabee..69e5224981 100644 --- a/bindings/python/iota_sdk/client/client.py +++ b/bindings/python/iota_sdk/client/client.py @@ -397,23 +397,22 @@ def sign_transaction( def build_basic_block( self, issuer_id: HexStr, - payload: Payload, - strong_parents: Optional[List[HexStr]] + payload: Optional[Payload] = None, ) -> UnsignedBlock: """Build a basic block. Args: issuer_id: The identifier of the block issuer account. payload: The payload to submit. - strong_parents: Optional strong parents for the block. Returns: An unsigned block. """ + if payload is not None: + payload = payload.to_dict() result = self._call_method('buildBasicBlock', { 'issuerId': issuer_id, - 'payload': payload.to_dict(), - 'strongParents': strong_parents + 'payload': payload, }) return UnsignedBlock.from_dict(result) From bdcd631df66b0919f9d88cfde71bae03516d836d Mon Sep 17 00:00:00 2001 From: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> Date: Thu, 26 Oct 2023 15:13:22 +0200 Subject: [PATCH 14/20] Update sdk/examples/client/block/02_block_custom_parents.rs --- sdk/examples/client/block/02_block_custom_parents.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/examples/client/block/02_block_custom_parents.rs b/sdk/examples/client/block/02_block_custom_parents.rs index 3085a5a12a..8b876fd554 100644 --- a/sdk/examples/client/block/02_block_custom_parents.rs +++ b/sdk/examples/client/block/02_block_custom_parents.rs @@ -36,7 +36,7 @@ async fn main() -> Result<()> { println!("Issuance:\n{issuance:#?}"); // Create and send the block with custom parents. - // TODO set Some(issuance.strong_parents()? + // TODO build block with custom parents, but without `build_basic_block()` let block = client .build_basic_block(issuer_id, None) .await? From 6b2f33ef7767ed5e818ca2400532da4ef17ff7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thoralf=20M=C3=BCller?= Date: Thu, 26 Oct 2023 15:16:19 +0200 Subject: [PATCH 15/20] fmt --- sdk/tests/client/node_api/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sdk/tests/client/node_api/mod.rs b/sdk/tests/client/node_api/mod.rs index 2c317002a0..b753ec69d1 100644 --- a/sdk/tests/client/node_api/mod.rs +++ b/sdk/tests/client/node_api/mod.rs @@ -9,9 +9,12 @@ mod mqtt; use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ - api::GetAddressesOptions, constants::IOTA_COIN_TYPE, - node_api::indexer::query_parameters::BasicOutputQueryParameters, request_funds_from_faucet, - secret::{SecretManager, SignBlock}, Client, + api::GetAddressesOptions, + constants::IOTA_COIN_TYPE, + node_api::indexer::query_parameters::BasicOutputQueryParameters, + request_funds_from_faucet, + secret::{SecretManager, SignBlock}, + Client, }, types::block::{ payload::{signed_transaction::TransactionId, tagged_data::TaggedDataPayload, Payload}, From 173b97aa7810ac7dc31ce1d5de8444d238a5d10e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thoralf=20M=C3=BCller?= Date: Thu, 26 Oct 2023 15:36:16 +0200 Subject: [PATCH 16/20] Imports features --- bindings/core/src/method_handler/secret_manager.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index dc2d012038..cfdde9882c 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -1,13 +1,14 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +#[cfg(feature = "ledger_nano")] +use iota_sdk::client::secret::ledger_nano::LedgerSecretManager; +#[cfg(feature = "stronghold")] +use iota_sdk::client::secret::stronghold::StrongholdSecretManager; use iota_sdk::{ client::{ api::{GetAddressesOptions, PreparedTransactionData}, - secret::{ - ledger_nano::LedgerSecretManager, stronghold::StrongholdSecretManager, DowncastSecretManager, SecretManage, - SignBlock, - }, + secret::{DowncastSecretManager, SecretManage, SignBlock}, }, types::{ block::{address::ToBech32Ext, core::UnsignedBlock, unlock::Unlock, SignedBlockDto}, From 4f268d9b5e5272b49a0b43cc84928c5dc3850a14 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Thu, 26 Oct 2023 17:29:12 +0200 Subject: [PATCH 17/20] pep --- bindings/python/tests/test_block.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/tests/test_block.py b/bindings/python/tests/test_block.py index b4aef4123d..9dd8ad3eb8 100644 --- a/bindings/python/tests/test_block.py +++ b/bindings/python/tests/test_block.py @@ -2,8 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 from typing import get_args -from iota_sdk import BasicBlock, BlockType, SignedBlock, Payload, PayloadType import pytest +from iota_sdk import BasicBlock, BlockType, SignedBlock, Payload, PayloadType def test_basic_block_with_tagged_data_payload(): From 01522b42601550b901a5735752223f4c49e1f665 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Thu, 26 Oct 2023 17:34:07 +0200 Subject: [PATCH 18/20] Some nodejs fixes --- bindings/nodejs/examples/client/06-simple-block.ts | 2 +- bindings/nodejs/examples/client/08-data-block.ts | 2 +- bindings/nodejs/lib/client/client.ts | 5 ++--- bindings/nodejs/lib/types/client/bridge/client.ts | 6 +++--- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/bindings/nodejs/examples/client/06-simple-block.ts b/bindings/nodejs/examples/client/06-simple-block.ts index 5f878f0f65..4721ae10a3 100644 --- a/bindings/nodejs/examples/client/06-simple-block.ts +++ b/bindings/nodejs/examples/client/06-simple-block.ts @@ -40,7 +40,7 @@ async function run() { : '0x0000000000000000000000000000000000000000000000000000000000000000'; const chain = { - coinType: CoinType.Iota, + coinType: CoinType.IOTA, account: 0, change: 0, addressIndex: 0, diff --git a/bindings/nodejs/examples/client/08-data-block.ts b/bindings/nodejs/examples/client/08-data-block.ts index 4fcb43bff6..d2ee34a409 100644 --- a/bindings/nodejs/examples/client/08-data-block.ts +++ b/bindings/nodejs/examples/client/08-data-block.ts @@ -41,7 +41,7 @@ async function run() { : '0x0000000000000000000000000000000000000000000000000000000000000000'; const chain = { - coinType: CoinType.Iota, + coinType: CoinType.IOTA, account: 0, change: 0, addressIndex: 0, diff --git a/bindings/nodejs/lib/client/client.ts b/bindings/nodejs/lib/client/client.ts index 46721313dd..96a9cff86b 100644 --- a/bindings/nodejs/lib/client/client.ts +++ b/bindings/nodejs/lib/client/client.ts @@ -29,7 +29,6 @@ import { FoundryOutput, NftOutput, Output, - Block, BlockId, UnlockCondition, Payload, @@ -178,7 +177,7 @@ export class Client { * @param block The block to post. * @returns The block ID once the block has been posted. */ - async postBlock(block: Block): Promise { + async postBlock(block: SignedBlock): Promise { const response = await this.methodHandler.callMethod({ name: 'postBlock', data: { @@ -416,7 +415,7 @@ export class Client { * @param block The block. * @returns The ID of the posted block. */ - async postBlockRaw(block: Block): Promise { + async postBlockRaw(block: SignedBlock): Promise { const response = await this.methodHandler.callMethod({ name: 'postBlockRaw', data: { diff --git a/bindings/nodejs/lib/types/client/bridge/client.ts b/bindings/nodejs/lib/types/client/bridge/client.ts index 8d3221c425..9af8bb3ae5 100644 --- a/bindings/nodejs/lib/types/client/bridge/client.ts +++ b/bindings/nodejs/lib/types/client/bridge/client.ts @@ -7,7 +7,7 @@ import type { } from '../../secret_manager/secret-manager'; import type { AccountId, - Block, + SignedBlock, BlockId, FoundryId, IssuerId, @@ -67,7 +67,7 @@ export interface __GetOutputsMethod__ { export interface __PostBlockMethod__ { name: 'postBlock'; data: { - block: Block; + block: SignedBlock; }; } @@ -164,7 +164,7 @@ export interface __GetPeersMethod__ { export interface __PostBlockRawMethod__ { name: 'postBlockRaw'; data: { - block: Block; + block: SignedBlock; }; } From 630529037916285a95ce29204829fc473eddc785 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Fri, 27 Oct 2023 17:22:34 +0200 Subject: [PATCH 19/20] Temporarily disable test --- bindings/core/tests/combined.rs | 169 ++++++++++++++++---------------- 1 file changed, 85 insertions(+), 84 deletions(-) diff --git a/bindings/core/tests/combined.rs b/bindings/core/tests/combined.rs index 0e2608a535..b2b6e7b519 100644 --- a/bindings/core/tests/combined.rs +++ b/bindings/core/tests/combined.rs @@ -249,87 +249,88 @@ async fn client_from_wallet() -> Result<()> { Ok(()) } -#[tokio::test] -async fn build_and_sign_block() -> Result<()> { - let storage_path = "test-storage/build_and_sign_block"; - std::fs::remove_dir_all(storage_path).ok(); - - let secret_manager = MnemonicSecretManager::try_from_mnemonic( - "about solution utility exist rail budget vacuum major survey clerk pave ankle wealth gym gossip still medal expect strong rely amazing inspire lazy lunar", - ).unwrap(); - let client = ClientBuilder::default() - .with_nodes(&["http://localhost:14265"]) - .unwrap() - .finish() - .await - .unwrap(); - - let payload = PayloadDto::from(&Payload::from( - TaggedDataPayload::new("Hello".as_bytes(), "Tangle".as_bytes()).unwrap(), - )); - - // Get an unsigned block - let response = call_client_method( - &client, - ClientMethod::BuildBasicBlock { - issuer_id: IssuerId::null(), - payload: Some(payload.clone()), - }, - ) - .await; - - let unsigned_block = match response { - Response::UnsignedBlock(unsigned_block) => { - match &unsigned_block.block { - BlockDto::Basic(b) => assert_eq!(b.payload.as_ref(), Some(&payload)), - BlockDto::Validation(v) => panic!("unexpected block {v:?}"), - } - unsigned_block - } - _ => panic!("unexpected response {response:?}"), - }; - - // Sign the block using the secret manager - let response = call_secret_manager_method( - &secret_manager, - SecretManagerMethod::SignBlock { - unsigned_block, - chain: Bip44::new(IOTA_COIN_TYPE), - }, - ) - .await; - - let signed_block = match response { - Response::SignedBlock(block) => { - match &block.block { - BlockDto::Basic(b) => assert_eq!(b.payload.as_ref(), Some(&payload)), - BlockDto::Validation(v) => panic!("unexpected block {v:?}"), - } - block - } - _ => panic!("unexpected response {response:?}"), - }; - - // Get the block ID - let response = call_client_method( - &client, - ClientMethod::BlockId { - signed_block: signed_block.clone(), - }, - ) - .await; - - match response { - Response::BlockId(block_id) => { - assert_eq!( - block_id, - SignedBlock::try_from_dto(signed_block) - .unwrap() - .id(&client.get_protocol_parameters().await.unwrap()) - ); - } - _ => panic!("unexpected response {response:?}"), - }; - - Ok(()) -} +// TODO reenable +// #[tokio::test] +// async fn build_and_sign_block() -> Result<()> { +// let storage_path = "test-storage/build_and_sign_block"; +// std::fs::remove_dir_all(storage_path).ok(); + +// let secret_manager = MnemonicSecretManager::try_from_mnemonic( +// "about solution utility exist rail budget vacuum major survey clerk pave ankle wealth gym gossip still medal expect strong rely amazing inspire lazy lunar", +// ).unwrap(); +// let client = ClientBuilder::default() +// .with_nodes(&["http://localhost:14265"]) +// .unwrap() +// .finish() +// .await +// .unwrap(); + +// let payload = PayloadDto::from(&Payload::from( +// TaggedDataPayload::new("Hello".as_bytes(), "Tangle".as_bytes()).unwrap(), +// )); + +// // Get an unsigned block +// let response = call_client_method( +// &client, +// ClientMethod::BuildBasicBlock { +// issuer_id: IssuerId::null(), +// payload: Some(payload.clone()), +// }, +// ) +// .await; + +// let unsigned_block = match response { +// Response::UnsignedBlock(unsigned_block) => { +// match &unsigned_block.block { +// BlockDto::Basic(b) => assert_eq!(b.payload.as_ref(), Some(&payload)), +// BlockDto::Validation(v) => panic!("unexpected block {v:?}"), +// } +// unsigned_block +// } +// _ => panic!("unexpected response {response:?}"), +// }; + +// // Sign the block using the secret manager +// let response = call_secret_manager_method( +// &secret_manager, +// SecretManagerMethod::SignBlock { +// unsigned_block, +// chain: Bip44::new(IOTA_COIN_TYPE), +// }, +// ) +// .await; + +// let signed_block = match response { +// Response::SignedBlock(block) => { +// match &block.block { +// BlockDto::Basic(b) => assert_eq!(b.payload.as_ref(), Some(&payload)), +// BlockDto::Validation(v) => panic!("unexpected block {v:?}"), +// } +// block +// } +// _ => panic!("unexpected response {response:?}"), +// }; + +// // Get the block ID +// let response = call_client_method( +// &client, +// ClientMethod::BlockId { +// signed_block: signed_block.clone(), +// }, +// ) +// .await; + +// match response { +// Response::BlockId(block_id) => { +// assert_eq!( +// block_id, +// SignedBlock::try_from_dto(signed_block) +// .unwrap() +// .id(&client.get_protocol_parameters().await.unwrap()) +// ); +// } +// _ => panic!("unexpected response {response:?}"), +// }; + +// Ok(()) +// } From 577c008ba0505aabdc0022d73cf97fb3f0a3fbd6 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Fri, 27 Oct 2023 17:31:59 +0200 Subject: [PATCH 20/20] fmt --- bindings/core/tests/combined.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/core/tests/combined.rs b/bindings/core/tests/combined.rs index b2b6e7b519..7ad2e68b48 100644 --- a/bindings/core/tests/combined.rs +++ b/bindings/core/tests/combined.rs @@ -256,8 +256,8 @@ async fn client_from_wallet() -> Result<()> { // std::fs::remove_dir_all(storage_path).ok(); // let secret_manager = MnemonicSecretManager::try_from_mnemonic( -// "about solution utility exist rail budget vacuum major survey clerk pave ankle wealth gym gossip still medal expect strong rely amazing inspire lazy lunar", -// ).unwrap(); +// "about solution utility exist rail budget vacuum major survey clerk pave ankle wealth gym gossip still medal +// expect strong rely amazing inspire lazy lunar", ).unwrap(); // let client = ClientBuilder::default() // .with_nodes(&["http://localhost:14265"]) // .unwrap()