diff --git a/bindings/core/src/method/client.rs b/bindings/core/src/method/client.rs index b82114b11a..ab998873fb 100644 --- a/bindings/core/src/method/client.rs +++ b/bindings/core/src/method/client.rs @@ -19,7 +19,7 @@ use iota_sdk::{ NativeToken, NftId, OutputId, TokenScheme, }, payload::{dto::PayloadDto, signed_transaction::TransactionId}, - BlockId, BlockWrapperDto, + BlockId, IssuerId, SignedBlockDto, }, utils::serde::{option_string, string}, }; @@ -128,10 +128,13 @@ 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, + #[serde(rename_all = "camelCase")] + BuildBasicBlock { + /// The issuer's ID. + issuer_id: IssuerId, + /// The block payload. + #[serde(default)] + payload: Option, }, ////////////////////////////////////////////////////////////////////// // Node core API @@ -157,7 +160,7 @@ pub enum ClientMethod { /// Post block (JSON) PostBlock { /// Block - block: BlockWrapperDto, + block: SignedBlockDto, }, /// Post block (raw) #[serde(rename_all = "camelCase")] @@ -337,8 +340,9 @@ pub enum ClientMethod { address: Bech32Address, }, /// Returns a block ID from a block + #[serde(rename_all = "camelCase")] BlockId { /// Block - block: BlockWrapperDto, + signed_block: SignedBlockDto, }, } diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index 2a4ae98cdf..c538f3aec2 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,14 @@ pub enum SecretManagerMethod { /// Prepared transaction data prepared_transaction_data: PreparedTransactionDataDto, }, + // Sign a block. + #[serde(rename_all = "camelCase")] + 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 470636f4ac..71047d504d 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 b0202468a1..44e3574d40 100644 --- a/bindings/core/src/method_handler/call_method.rs +++ b/bindings/core/src/method_handler/call_method.rs @@ -5,10 +5,12 @@ 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}, @@ -78,10 +80,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; diff --git a/bindings/core/src/method_handler/client.rs b/bindings/core/src/method_handler/client.rs index 89fab444d6..c59976470f 100644 --- a/bindings/core/src/method_handler/client.rs +++ b/bindings/core/src/method_handler/client.rs @@ -4,7 +4,7 @@ #[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::OutputWithMetadataResponse, block::{ @@ -12,7 +12,7 @@ use iota_sdk::{ dto::OutputDto, AccountOutput, BasicOutput, FoundryOutput, NftOutput, Output, OutputBuilderAmount, Rent, }, payload::Payload, - BlockWrapper, BlockWrapperDto, + SignedBlock, SignedBlockDto, UnsignedBlockDto, }, TryFromDto, }, @@ -161,6 +161,19 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM Response::Output(OutputDto::from(&output)) } + ClientMethod::BuildBasicBlock { issuer_id, payload } => { + 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, payload).await?, + )) + } #[cfg(feature = "mqtt")] ClientMethod::ClearListeners { topics } => { client.unsubscribe(topics).await?; @@ -171,25 +184,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?), @@ -199,7 +193,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?, )?) @@ -207,14 +201,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?) @@ -229,9 +223,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?) } @@ -276,7 +270,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 } => { @@ -317,9 +311,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/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index 26559703bf..cfdde9882c 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -1,35 +1,73 @@ // 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::PreparedTransactionData, - secret::{SecretManage, SecretManager}, + api::{GetAddressesOptions, PreparedTransactionData}, + secret::{DowncastSecretManager, SecretManage, SignBlock}, + }, + types::{ + block::{address::ToBech32Ext, core::UnsignedBlock, unlock::Unlock, SignedBlockDto}, + 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,9 +78,15 @@ 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::SignBlock { unsigned_block, chain } => Response::SignedBlock(SignedBlockDto::from( + &UnsignedBlock::try_from_dto(unsigned_block)? + .sign_ed25519(secret_manager, chain) + .await?, + )), SecretManagerMethod::SignatureUnlock { transaction_signing_hash, chain, @@ -50,18 +94,25 @@ pub(crate) async fn call_secret_manager_method_internal( let transaction_signing_hash: [u8; 32] = prefix_hex::decode(transaction_signing_hash)?; let unlock: Unlock = secret_manager .signature_unlock(&transaction_signing_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 +121,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/src/method_handler/utils.rs b/bindings/core/src/method_handler/utils.rs index dfe78271de..4a0432cfec 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, NftId, Output, OutputId, Rent, TokenId}, payload::{signed_transaction::Transaction, SignedTransactionPayload}, - BlockWrapper, + SignedBlock, }, TryFromDto, }, @@ -42,7 +42,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 1f1e7267e0..5ba2b88ef8 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,13 @@ 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), + /// - [`SignBlock`](crate::method::SecretManagerMethod::SignBlock) + SignedBlock(SignedBlockDto), /// Response for: /// - [`GetBlockMetadata`](crate::method::ClientMethod::GetBlockMetadata) BlockMetadata(BlockMetadataResponse), @@ -141,7 +142,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 a0e7a1456f..7ad2e68b48 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, IssuerId, SignedBlock, + }, + TryFromDto, + }, wallet::account::types::AccountIdentifier, }; -use iota_sdk_bindings_core::{AccountMethod, CallMethod, ClientMethod, Response, Result, WalletMethod, WalletOptions}; +use iota_sdk_bindings_core::{ + call_client_method, call_secret_manager_method, AccountMethod, CallMethod, ClientMethod, Response, Result, + SecretManagerMethod, WalletMethod, WalletOptions, +}; use pretty_assertions::assert_eq; #[tokio::test] @@ -233,3 +248,89 @@ async fn client_from_wallet() -> Result<()> { std::fs::remove_dir_all(storage_path).ok(); 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(()) +// } diff --git a/bindings/core/tests/secrets_debug.rs b/bindings/core/tests/secrets_debug.rs index 8ca8a69917..79e35d6052 100644 --- a/bindings/core/tests/secrets_debug.rs +++ b/bindings/core/tests/secrets_debug.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::client::secret::SecretManagerDto; -use iota_sdk_bindings_core::{ClientMethod, Response, UtilsMethod, WalletOptions}; +use iota_sdk_bindings_core::{Response, UtilsMethod, WalletOptions}; use pretty_assertions::assert_eq; #[test] diff --git a/bindings/core/tests/secrets_manager.rs b/bindings/core/tests/secrets_manager.rs index 018292e7c8..2192cbae09 100644 --- a/bindings/core/tests/secrets_manager.rs +++ b/bindings/core/tests/secrets_manager.rs @@ -1,18 +1,15 @@ // 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 pretty_assertions::assert_eq; -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), @@ -32,9 +29,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/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/nodejs/examples/client/06-simple-block.ts b/bindings/nodejs/examples/client/06-simple-block.ts index 4893986e50..4721ae10a3 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..d2ee34a409 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/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 81bd7aafe4..96a9cff86b 100644 --- a/bindings/nodejs/lib/client/client.ts +++ b/bindings/nodejs/lib/client/client.ts @@ -29,16 +29,18 @@ import { FoundryOutput, NftOutput, Output, - Block, BlockId, UnlockCondition, Payload, SignedTransactionPayload, - parseBlockWrapper, - BlockWrapper, + parseSignedBlock, + SignedBlock, AccountId, NftId, FoundryId, + IssuerId, + UnsignedBlock, + parseUnsignedBlock, } from '../types/block'; import { HexEncodedString } from '../utils'; import { @@ -175,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: { @@ -192,7 +194,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: { @@ -200,8 +202,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); } /** @@ -292,23 +294,25 @@ 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. * @returns The block ID followed by the block containing the payload. */ - async postBlockPayload(payload: Payload): Promise<[BlockId, BlockWrapper]> { + async buildBasicBlock( + issuerId: IssuerId, + payload?: Payload, + ): Promise { const response = await this.methodHandler.callMethod({ - name: 'postBlockPayload', + name: 'buildBasicBlock', data: { + issuerId, payload, }, }); - const parsed = JSON.parse(response) as Response< - [BlockId, BlockWrapper] - >; - const block = parseBlockWrapper(parsed.payload[1]); - return [parsed.payload[0], block]; + const parsed = JSON.parse(response) as Response; + return parseUnsignedBlock(parsed.payload); } /** @@ -411,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: { @@ -445,17 +449,15 @@ export class Client { * @param transactionId The ID of the transaction. * @returns The included block that contained the transaction. */ - async getIncludedBlock( - transactionId: TransactionId, - ): Promise { + async getIncludedBlock(transactionId: TransactionId): 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); } /** @@ -466,15 +468,15 @@ export class Client { */ async getIncludedBlockMetadata( transactionId: TransactionId, - ): 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); } /** @@ -699,15 +701,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/secret_manager/secret-manager.ts b/bindings/nodejs/lib/secret_manager/secret-manager.ts index acb669b606..7ccaeecd91 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 signed block. + */ + 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/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 52% rename from bindings/nodejs/lib/types/block/core/wrapper.ts rename to bindings/nodejs/lib/types/block/core/signed-block.ts index 5445e30041..44d19bb953 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. */ @@ -69,7 +69,106 @@ class BlockWrapper { this.slotCommitmentId = slotCommitmentId; this.latestFinalizedSlot = latestFinalizedSlot; this.issuerId = issuerId; + this.block = block; this.signature = signature; + } + + /** + * 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 parseSignedBlock(data: any): SignedBlock { + return plainToInstance(SignedBlock, data) as any as SignedBlock; +} + +/** + * 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; } @@ -116,8 +215,8 @@ class BlockWrapper { } } -function parseBlockWrapper(data: any): BlockWrapper { - return plainToInstance(BlockWrapper, data) as any as BlockWrapper; +function parseUnsignedBlock(data: any): UnsignedBlock { + return plainToInstance(UnsignedBlock, data) as any as UnsignedBlock; } -export { BlockWrapper, parseBlockWrapper }; +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..9af8bb3ae5 100644 --- a/bindings/nodejs/lib/types/client/bridge/client.ts +++ b/bindings/nodejs/lib/types/client/bridge/client.ts @@ -7,9 +7,10 @@ import type { } from '../../secret_manager/secret-manager'; import type { AccountId, - Block, + SignedBlock, BlockId, FoundryId, + IssuerId, NftId, Output, OutputId, @@ -66,7 +67,7 @@ export interface __GetOutputsMethod__ { export interface __PostBlockMethod__ { name: 'postBlock'; data: { - block: Block; + block: SignedBlock; }; } @@ -117,10 +118,11 @@ export interface __SignatureUnlockMethod__ { }; } -export interface __PostBlockPayloadMethod__ { - name: 'postBlockPayload'; +export interface __BuildBasicBlockMethod__ { + name: 'buildBasicBlock'; data: { - payload: Payload; + issuerId: IssuerId; + payload?: Payload; }; } @@ -162,7 +164,7 @@ export interface __GetPeersMethod__ { export interface __PostBlockRawMethod__ { name: 'postBlockRaw'; data: { - block: Block; + block: SignedBlock; }; } 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/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: { diff --git a/bindings/nodejs/lib/types/utils/bridge/utils.ts b/bindings/nodejs/lib/types/utils/bridge/utils.ts index be7ed42267..79c1931f74 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, OutputId, NftId, @@ -85,7 +85,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 28f8aeb782..7824171c58 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, Bech32Address, } from '../types'; @@ -186,7 +186,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/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/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(); }); 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/bindings/python/examples/client/06_simple_block.py b/bindings/python/examples/client/06_simple_block.py index 64147e881e..734444a108 100644 --- a/bindings/python/examples/client/06_simple_block.py +++ b/bindings/python/examples/client/06_simple_block.py @@ -1,19 +1,32 @@ import os 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() 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]) +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 -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, 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 fb068471bb..900313a537 100644 --- a/bindings/python/examples/client/08_data_block.py +++ b/bindings/python/examples/client/08_data_block.py @@ -3,20 +3,32 @@ import os from dataclasses import asdict 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() 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]) +chain = Bip44(CoinType.IOTA) + # 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, 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 19c66fa539..ea60a51839 100644 --- a/bindings/python/examples/client/post_raw_block.py +++ b/bindings/python/examples/client/post_raw_block.py @@ -1,19 +1,31 @@ import os 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() 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]) +chain = Bip44(CoinType.IOTA) + # 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, chain) +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..00002ff09b 100644 --- a/bindings/python/examples/client/submit_and_read_block.py +++ b/bindings/python/examples/client/submit_and_read_block.py @@ -11,11 +11,18 @@ # Make sure you have first installed it with `pip install iota_sdk` import os 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() 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]) @@ -54,21 +61,23 @@ # 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) -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, chain) +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/__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..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 iota_sdk.types.block.wrapper import BlockWrapper +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 @@ -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..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 iota_sdk.types.block.wrapper import BlockWrapper +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 @@ -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..69e5224981 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 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,27 @@ def sign_transaction( 'preparedTransactionData': prepared_transaction_data })) - def submit_payload( - self, payload: Payload) -> List[Union[HexStr, BlockWrapper]]: - """Submit a payload in a block. + def build_basic_block( + self, + issuer_id: HexStr, + payload: Optional[Payload] = None, + ) -> 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. Returns: - List of HexStr or Block. + An unsigned block. """ - result = self._call_method('postBlockPayload', { - 'payload': payload.to_dict() + if payload is not None: + payload = payload.to_dict() + result = self._call_method('buildBasicBlock', { + 'issuerId': issuer_id, + 'payload': payload, }) - result[1] = BlockWrapper.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..97c9fec4cc 100644 --- a/bindings/python/iota_sdk/secret_manager/secret_manager.py +++ b/bindings/python/iota_sdk/secret_manager/secret_manager.py @@ -7,6 +7,7 @@ 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 @@ -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/wrapper.py b/bindings/python/iota_sdk/types/block/signed_block.py similarity index 57% rename from bindings/python/iota_sdk/types/block/wrapper.py rename to bindings/python/iota_sdk/types/block/signed_block.py index 01798703eb..46439c6a77 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. @@ -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] diff --git a/bindings/python/iota_sdk/utils.py b/bindings/python/iota_sdk/utils.py index 676479be9a..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 iota_sdk.types.block.wrapper import BlockWrapper + from iota_sdk.types.block.signed_block import SignedBlock # pylint: disable=too-many-public-methods @@ -168,7 +168,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/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/python/tests/test_block.py b/bindings/python/tests/test_block.py index 194c3133e2..9dd8ad3eb8 100644 --- a/bindings/python/tests/test_block.py +++ b/bindings/python/tests/test_block.py @@ -3,7 +3,7 @@ from typing import get_args import pytest -from iota_sdk import BasicBlock, BlockType, BlockWrapper, Payload, PayloadType +from iota_sdk import BasicBlock, BlockType, SignedBlock, Payload, PayloadType def test_basic_block_with_tagged_data_payload(): @@ -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/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/.env.example b/sdk/examples/.env.example index 7e6c1b0215..d51040423a 100644 --- a/sdk/examples/.env.example +++ b/sdk/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"; diff --git a/sdk/examples/client/block/00_block_no_payload.rs b/sdk/examples/client/block/00_block_no_payload.rs index ce029516bc..77b86733ac 100644 --- a/sdk/examples/client/block/00_block_no_payload.rs +++ b/sdk/examples/client/block/00_block_no_payload.rs @@ -9,7 +9,14 @@ //! ``` 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, SignBlock}, + Client, Result, + }, + types::block::IssuerId, +}; #[tokio::main] async fn main() -> Result<()> { @@ -17,6 +24,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 +33,9 @@ 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) + .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 81f0c9c993..927376169d 100644 --- a/sdk/examples/client/block/01_block_confirmation_time.rs +++ b/sdk/examples/client/block/01_block_confirmation_time.rs @@ -10,8 +10,12 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, - types::api::core::BlockState, + client::{ + constants::IOTA_COIN_TYPE, + secret::{SecretManager, SignBlock}, + Client, Result, + }, + types::{api::core::BlockState, block::IssuerId}, }; #[tokio::main] @@ -20,6 +24,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 +33,9 @@ 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) + .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 2a01e8f95b..8b876fd554 100644 --- a/sdk/examples/client/block/02_block_custom_parents.rs +++ b/sdk/examples/client/block/02_block_custom_parents.rs @@ -9,7 +9,14 @@ //! ``` 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, SignBlock}, + Client, Result, + }, + types::block::IssuerId, +}; #[tokio::main] async fn main() -> Result<()> { @@ -17,6 +24,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,15 +36,11 @@ async fn main() -> Result<()> { println!("Issuance:\n{issuance:#?}"); // Create and send the block with custom parents. + // TODO build block with custom parents, but without `build_basic_block()` let block = client - .build_basic_block( - todo!("issuer id"), - todo!("issuing time"), - Some(issuance.strong_parents()?), - None, - &secret_manager, - Bip44::new(IOTA_COIN_TYPE), - ) + .build_basic_block(issuer_id, 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 b27c5a289c..db67b48390 100644 --- a/sdk/examples/client/block/03_block_custom_payload.rs +++ b/sdk/examples/client/block/03_block_custom_payload.rs @@ -10,8 +10,15 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, - types::block::payload::{Payload, TaggedDataPayload}, + client::{ + constants::IOTA_COIN_TYPE, + secret::{SecretManager, SignBlock}, + Client, Result, + }, + types::block::{ + payload::{Payload, TaggedDataPayload}, + IssuerId, + }, }; #[tokio::main] @@ -20,6 +27,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?; @@ -31,14 +39,9 @@ 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"), - None, - Some(Payload::from(tagged_data_payload)), - &secret_manager, - Bip44::new(IOTA_COIN_TYPE), - ) + .build_basic_block(issuer_id, 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 2fc25aa84f..7799a80bf9 100644 --- a/sdk/examples/client/block/04_block_tagged_data.rs +++ b/sdk/examples/client/block/04_block_tagged_data.rs @@ -10,8 +10,15 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, - types::block::payload::{Payload, TaggedDataPayload}, + client::{ + constants::IOTA_COIN_TYPE, + secret::{SecretManager, SignBlock}, + Client, Result, + }, + types::block::{ + payload::{Payload, TaggedDataPayload}, + IssuerId, + }, }; #[tokio::main] @@ -20,6 +27,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,9 +37,7 @@ 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"), - None, + issuer_id, Some(Payload::TaggedData(Box::new( TaggedDataPayload::new( std::env::args() @@ -45,9 +51,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 414e3ca7cf..c11d780ae4 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,14 @@ //! ``` 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, SignBlock}, + Client, Result, + }, + types::block::IssuerId, +}; #[tokio::main] async fn main() -> Result<()> { @@ -20,6 +27,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 +36,9 @@ 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) + .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 a20a0ad257..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 @@ -9,7 +9,14 @@ //! ``` 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, SignBlock}, + Client, Result, + }, + types::block::IssuerId, +}; #[tokio::main] async fn main() -> Result<()> { @@ -20,6 +27,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 +36,9 @@ 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) + .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..ca2e99a72e 100644 --- a/sdk/src/client/api/block_builder/mod.rs +++ b/sdk/src/client/api/block_builder/mod.rs @@ -4,38 +4,21 @@ 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::{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, - secret_manager: &S, - chain: Bip44, - ) -> Result - where - crate::client::Error: From, - { + 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) @@ -46,11 +29,11 @@ impl ClientInner { #[cfg(not(feature = "std"))] let issuing_time = 0; issuing_time - }); + }; let protocol_params = self.get_protocol_parameters().await?; - BlockWrapper::build( + Ok(UnsignedBlock::new( BlockHeader::new( protocol_params.version(), protocol_params.network_id(), @@ -59,13 +42,12 @@ 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) .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 307e0ce910..be2141f4cc 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::signed_transaction::{SignedTransactionPayload, Transaction}, semantic::{SemanticValidationContext, TransactionFailureReason}, 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 352005c372..1d2fcaee52 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::{signed_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::SignedTransaction(t)) = block.payload() { t.transaction().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 22f0830cef..462338bdd9 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::signed_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 6718e1d853..36ba209fe3 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::SignedTransactionPayload, signature::{Ed25519Signature, Signature}, unlock::{AccountUnlock, NftUnlock, ReferenceUnlock, SignatureUnlock, Unlock, Unlocks}, - BlockWrapper, + SignedBlock, }, }; @@ -611,18 +611,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 f71a5370f9..a6f8b6cd9d 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 73% rename from sdk/src/types/block/core/wrapper.rs rename to sdk/src/types/block/core/signed_block.rs index e13cd7a8c1..0c6b13ca2f 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.into_block_id(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; @@ -314,25 +314,25 @@ impl Packable for BlockWrapper { 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::InvalidBlockWrapperLength(wrapper_len))); + if signed_block_len > Self::LENGTH_MAX { + return Err(UnpackError::Packable(Error::InvalidSignedBlockLength(signed_block_len))); } } - Ok(wrapper) + Ok(signed_block) } } @@ -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 129382eca0..7e7026da62 100644 --- a/sdk/src/types/block/error.rs +++ b/sdk/src/types/block/error.rs @@ -83,7 +83,7 @@ pub enum Error { InvalidInputOutputIndex(>::Error), InvalidBech32Hrp(Bech32HrpError), InvalidCapabilitiesCount(>::Error), - InvalidBlockWrapperLength(usize), + InvalidSignedBlockLength(usize), InvalidStateMetadataLength(>::Error), InvalidManaValue(u64), InvalidMetadataFeatureLength(>::Error), @@ -257,7 +257,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/macro.rs b/sdk/src/types/block/macro.rs index 3af7efdfc9..d4783a93cd 100644 --- a/sdk/src/types/block/macro.rs +++ b/sdk/src/types/block/macro.rs @@ -36,17 +36,17 @@ macro_rules! impl_id { $len_vis const LENGTH: usize = $length; #[doc = core::concat!("Creates a new [`", core::stringify!($hash_name), "`].")] - $hash_vis fn new(bytes: [u8; Self::LENGTH]) -> Self { - Self::from(bytes) + $hash_vis const fn new(bytes: [u8; Self::LENGTH]) -> Self { + Self(bytes) } #[doc = core::concat!("Creates a null [`", core::stringify!($hash_name), "`].")] - pub fn null() -> Self { - Self::from([0u8; Self::LENGTH]) + $hash_vis const fn null() -> Self { + Self([0u8; Self::LENGTH]) } #[doc = core::concat!("Checks if the [`", core::stringify!($hash_name), "`] is null.")] - pub fn is_null(&self) -> bool { + $hash_vis fn is_null(&self) -> bool { self.0.iter().all(|&b| b == 0) } } diff --git a/sdk/src/types/block/mod.rs b/sdk/src/types/block/mod.rs index 30bbcb474d..d010281bab 100644 --- a/sdk/src/types/block/mod.rs +++ b/sdk/src/types/block/mod.rs @@ -42,12 +42,12 @@ pub mod slot; pub mod unlock; #[cfg(feature = "serde")] -pub use self::core::dto::{BlockDto, BlockWrapperDto}; +pub use self::core::dto::{BlockDto, SignedBlockDto, UnsignedBlockDto}; pub(crate) use self::r#macro::*; pub use self::{ block_id::{BlockHash, BlockId}, convert::ConvertTo, - core::{Block, BlockWrapper}, + core::{Block, SignedBlock, UnsignedBlock}, 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 13be595f53..aba08669b3 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 b99d537916..2eff243a9f 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::{BlockState, TransactionState}, block::{ @@ -60,9 +63,10 @@ where .client() .build_basic_block( todo!("issuer id"), - todo!("issuing time"), - None, Some(Payload::SignedTransaction(Box::new(transaction.payload.clone()))), + ) + .await? + .sign_ed25519( &*self.get_secret_manager().read().await, Bip44::new(self.wallet.coin_type()), ) @@ -107,9 +111,10 @@ where .client() .build_basic_block( todo!("issuer id"), - todo!("issuing time"), - None, Some(Payload::SignedTransaction(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 b019265c2c..a0de9f0462 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::SignedTransaction(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 199873b435..28b4bc015b 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::SignedTransactionPayload, Account}, }; @@ -27,11 +27,9 @@ 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, 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 40acaa351d..b24ca5b13d 100644 --- a/sdk/tests/client/node_api/core.rs +++ b/sdk/tests/client/node_api/core.rs @@ -12,7 +12,7 @@ use iota_sdk::{ api::core::TransactionState, block::{ output::{Output, OutputId}, - BlockWrapper, + SignedBlock, }, }, }; @@ -195,7 +195,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 8b50f9d377..b753ec69d1 100644 --- a/sdk/tests/client/node_api/mod.rs +++ b/sdk/tests/client/node_api/mod.rs @@ -9,13 +9,16 @@ 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, 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}, - BlockId, + BlockId, IssuerId, }, }; @@ -32,17 +35,16 @@ async fn setup_tagged_data_block(secret_manager: &SecretManager) -> BlockId { client .build_basic_block( - todo!("issuer id"), - todo!("issuing time"), - None, + IssuerId::null(), 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 7b206e8c56..ad04349932 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, }; @@ -93,7 +93,7 @@ use pretty_assertions::assert_eq; #[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()); @@ -113,11 +113,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] @@ -150,8 +150,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, @@ -191,8 +191,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 28c59faf59..87152765ca 100644 --- a/sdk/tests/types/block_id.rs +++ b/sdk/tests/types/block_id.rs @@ -103,8 +103,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!( @@ -221,8 +221,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!( @@ -299,8 +299,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 76b3997aba..1073321b7f 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}, @@ -67,8 +67,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 )); }