From d480f57c02de99c98b4055fbb25e7aa3c12a4e6d Mon Sep 17 00:00:00 2001 From: DaughterOfMars Date: Wed, 4 Oct 2023 15:44:28 -0400 Subject: [PATCH 1/2] Rename python union types (#1392) * based * Use unions everywhere * remove base classes * remove unused imports * another unused import * hopefully fix circular dep * imports order :triumph: --- bindings/python/iota_sdk/types/address.py | 20 +++------ bindings/python/iota_sdk/types/block/basic.py | 8 ++-- bindings/python/iota_sdk/types/block/block.py | 10 ----- .../python/iota_sdk/types/block/validation.py | 4 +- .../python/iota_sdk/types/block/wrapper.py | 17 ++++---- .../python/iota_sdk/types/context_input.py | 22 ++++------ bindings/python/iota_sdk/types/essence.py | 23 ++++------ bindings/python/iota_sdk/types/feature.py | 34 ++++++--------- bindings/python/iota_sdk/types/output.py | 26 ++++-------- bindings/python/iota_sdk/types/output_data.py | 8 ++-- bindings/python/iota_sdk/types/payload.py | 22 ++++------ bindings/python/iota_sdk/types/signature.py | 14 ++----- .../python/iota_sdk/types/token_scheme.py | 14 +++---- .../python/iota_sdk/types/transaction_data.py | 14 +++---- .../python/iota_sdk/types/unlock_condition.py | 42 ++++++++----------- bindings/python/iota_sdk/utils.py | 13 +----- bindings/python/tests/test_block.py | 11 ++--- 17 files changed, 110 insertions(+), 192 deletions(-) diff --git a/bindings/python/iota_sdk/types/address.py b/bindings/python/iota_sdk/types/address.py index 05c9e5a299..c70ec342af 100644 --- a/bindings/python/iota_sdk/types/address.py +++ b/bindings/python/iota_sdk/types/address.py @@ -22,15 +22,7 @@ class AddressType(IntEnum): @json @dataclass -class Address(): - """Base class for addresses. - """ - type: int - - -@json -@dataclass -class Ed25519Address(Address): +class Ed25519Address: """Represents an Ed25519 address. Attributes: pub_key_hash: The hex encoded Ed25519 public key hash. @@ -44,7 +36,7 @@ class Ed25519Address(Address): @json @dataclass -class AccountAddress(Address): +class AccountAddress: """Represents an Account address. Attributes: account_id: The hex encoded account id. @@ -58,7 +50,7 @@ class AccountAddress(Address): @json @dataclass -class NFTAddress(Address): +class NFTAddress: """Represents an NFT address. Attributes: nft_id: The hex encoded NFT id. @@ -78,10 +70,10 @@ class AddressWithUnspentOutputs(): output_ids: bool -AddressUnion: TypeAlias = Union[Ed25519Address, AccountAddress, NFTAddress] +Address: TypeAlias = Union[Ed25519Address, AccountAddress, NFTAddress] -def deserialize_address(d: Dict[str, Any]) -> AddressUnion: +def deserialize_address(d: Dict[str, Any]) -> Address: """ Takes a dictionary as input and returns an instance of a specific class based on the value of the 'type' key in the dictionary. @@ -99,7 +91,7 @@ def deserialize_address(d: Dict[str, Any]) -> AddressUnion: def deserialize_addresses( - dicts: List[Dict[str, Any]]) -> List[AddressUnion]: + dicts: List[Dict[str, Any]]) -> List[Address]: """ Takes a list of dictionaries as input and returns a list with specific instances of a classes based on the value of the 'type' key in the dictionary. diff --git a/bindings/python/iota_sdk/types/block/basic.py b/bindings/python/iota_sdk/types/block/basic.py index ee4b56b9f7..3d27b18fe8 100644 --- a/bindings/python/iota_sdk/types/block/basic.py +++ b/bindings/python/iota_sdk/types/block/basic.py @@ -4,14 +4,14 @@ from __future__ import annotations from dataclasses import dataclass, field from typing import List, Optional -from iota_sdk.types.block.block import Block, BlockType +from iota_sdk.types.block.block import BlockType from iota_sdk.types.common import HexStr, json -from iota_sdk.types.payload import PayloadUnion +from iota_sdk.types.payload import Payload @json @dataclass -class BasicBlock(Block): +class BasicBlock: """A `BasicBlock` is the most common type of block used to issue various kinds of payloads such as transactions at the cost of burning Mana. @@ -26,7 +26,7 @@ class BasicBlock(Block): weak_parents: List[HexStr] shallow_like_parents: List[HexStr] max_burned_mana: str - payload: Optional[PayloadUnion] = None + payload: Optional[Payload] = None type: int = field( default_factory=lambda: BlockType.Basic, init=False) diff --git a/bindings/python/iota_sdk/types/block/block.py b/bindings/python/iota_sdk/types/block/block.py index 026f8d4b5e..9fc0d54747 100644 --- a/bindings/python/iota_sdk/types/block/block.py +++ b/bindings/python/iota_sdk/types/block/block.py @@ -3,8 +3,6 @@ from __future__ import annotations from enum import IntEnum -from dataclasses import dataclass -from iota_sdk.types.common import json class BlockType(IntEnum): @@ -16,11 +14,3 @@ class BlockType(IntEnum): """ Basic = 0 Validation = 1 - - -@json -@dataclass -class Block: - """Base class for blocks. - """ - type: int diff --git a/bindings/python/iota_sdk/types/block/validation.py b/bindings/python/iota_sdk/types/block/validation.py index 2bcaaf2232..bd99ea61e1 100644 --- a/bindings/python/iota_sdk/types/block/validation.py +++ b/bindings/python/iota_sdk/types/block/validation.py @@ -4,13 +4,13 @@ from __future__ import annotations from dataclasses import dataclass, field from typing import List -from iota_sdk.types.block.block import Block, BlockType +from iota_sdk.types.block.block import BlockType from iota_sdk.types.common import HexStr, json @json @dataclass -class ValidationBlock(Block): +class ValidationBlock: """A Validation Block is a special type of block used by validators to secure the network. It is recognized by the Congestion Control of the IOTA 2.0 protocol and can be issued without burning Mana within the constraints of the allowed validator throughput. It is allowed to reference more parent blocks than a normal Basic Block. diff --git a/bindings/python/iota_sdk/types/block/wrapper.py b/bindings/python/iota_sdk/types/block/wrapper.py index c1ebf2db80..cfed6e2681 100644 --- a/bindings/python/iota_sdk/types/block/wrapper.py +++ b/bindings/python/iota_sdk/types/block/wrapper.py @@ -4,14 +4,12 @@ from __future__ import annotations from dataclasses import dataclass from typing import TypeAlias, Union -from iota_sdk.types.block.basic import BasicBlock -from iota_sdk.types.block.validation import ValidationBlock +from iota_sdk.utils import Utils from iota_sdk.types.common import HexStr, json, SlotIndex from iota_sdk.types.node_info import ProtocolParameters -from iota_sdk.types.signature import SignatureUnion -from iota_sdk.utils import Utils - -BlockUnion: TypeAlias = Union[BasicBlock, ValidationBlock] +from iota_sdk.types.signature import Signature +from iota_sdk.types.block.basic import BasicBlock +from iota_sdk.types.block.validation import ValidationBlock @json @@ -36,10 +34,13 @@ class BlockWrapper: slot_commitment_id: HexStr latest_finalized_slot: SlotIndex issuer_id: HexStr - block: BlockUnion - signature: SignatureUnion + block: Block + signature: Signature def id(self, params: ProtocolParameters) -> HexStr: """Returns the block ID as a hexadecimal string. """ return Utils.block_id(self, params) + + +Block: TypeAlias = Union[BasicBlock, ValidationBlock] diff --git a/bindings/python/iota_sdk/types/context_input.py b/bindings/python/iota_sdk/types/context_input.py index f8e85ef0c0..fcdd6a3f35 100644 --- a/bindings/python/iota_sdk/types/context_input.py +++ b/bindings/python/iota_sdk/types/context_input.py @@ -18,15 +18,7 @@ class ContextInputType(IntEnum): @json @dataclass -class ContextInput(): - """Base class for context inputs. - """ - type: int - - -@json -@dataclass -class CommitmentContextInput(ContextInput): +class CommitmentContextInput: """A Commitment Context Input allows referencing a commitment to a certain slot. Attributes: @@ -42,7 +34,7 @@ class CommitmentContextInput(ContextInput): @json @dataclass -class BlockIssuanceCreditContextInput(ContextInput): +class BlockIssuanceCreditContextInput: """A Block Issuance Credit (BIC) Context Input provides the VM with context for the value of the BIC vector of a specific slot. @@ -59,7 +51,7 @@ class BlockIssuanceCreditContextInput(ContextInput): @json @dataclass -class RewardContextInput(ContextInput): +class RewardContextInput: """A Reward Context Input indicates which transaction Input is claiming Mana rewards. Attributes: @@ -73,11 +65,11 @@ class RewardContextInput(ContextInput): init=False) -ContextInputUnion: TypeAlias = Union[CommitmentContextInput, - BlockIssuanceCreditContextInput, RewardContextInput] +ContextInput: TypeAlias = Union[CommitmentContextInput, + BlockIssuanceCreditContextInput, RewardContextInput] -def deserialize_context_input(d: Dict[str, Any]) -> ContextInputUnion: +def deserialize_context_input(d: Dict[str, Any]) -> ContextInput: """ Takes a dictionary as input and returns an instance of a specific class based on the value of the 'type' key in the dictionary. @@ -95,7 +87,7 @@ def deserialize_context_input(d: Dict[str, Any]) -> ContextInputUnion: def deserialize_context_inputs( - dicts: List[Dict[str, Any]]) -> List[ContextInputUnion]: + dicts: List[Dict[str, Any]]) -> List[ContextInput]: """ Takes a list of dictionaries as input and returns a list with specific instances of a classes based on the value of the 'type' key in the dictionary. diff --git a/bindings/python/iota_sdk/types/essence.py b/bindings/python/iota_sdk/types/essence.py index 16a3c0e34c..cd9ae1bdc6 100644 --- a/bindings/python/iota_sdk/types/essence.py +++ b/bindings/python/iota_sdk/types/essence.py @@ -3,15 +3,15 @@ from __future__ import annotations from enum import IntEnum -from typing import TYPE_CHECKING, Optional, List +from typing import TYPE_CHECKING, Optional, List, TypeAlias from dataclasses import dataclass, field from iota_sdk.types.common import HexStr, json, SlotIndex from iota_sdk.types.mana import ManaAllotment from iota_sdk.types.input import UtxoInput -from iota_sdk.types.context_input import ContextInputUnion -from iota_sdk.types.output import OutputUnion +from iota_sdk.types.context_input import ContextInput +from iota_sdk.types.output import Output # Required to prevent circular import if TYPE_CHECKING: @@ -29,15 +29,7 @@ class EssenceType(IntEnum): @json @dataclass -class TransactionEssence: - """Base class of Transaction essence - """ - type: int - - -@json -@dataclass -class RegularTransactionEssence(TransactionEssence): +class RegularTransactionEssence: """Describes the essence data making up a transaction by defining its inputs, outputs, and an optional payload. Attributes: @@ -55,10 +47,13 @@ class RegularTransactionEssence(TransactionEssence): creation_slot: SlotIndex inputs: List[UtxoInput] inputs_commitment: HexStr - outputs: List[OutputUnion] - context_inputs: Optional[List[ContextInputUnion]] = None + outputs: List[Output] + context_inputs: Optional[List[ContextInput]] = None allotments: Optional[List[ManaAllotment]] = None payload: Optional[Payload] = None type: int = field( default_factory=lambda: EssenceType.RegularTransactionEssence, init=False) + + +TransactionEssence: TypeAlias = RegularTransactionEssence diff --git a/bindings/python/iota_sdk/types/feature.py b/bindings/python/iota_sdk/types/feature.py index ab1cb11398..5968932f18 100644 --- a/bindings/python/iota_sdk/types/feature.py +++ b/bindings/python/iota_sdk/types/feature.py @@ -5,7 +5,7 @@ from typing import Dict, List, TypeAlias, Union, Any from dataclasses import dataclass, field from dataclasses_json import config -from iota_sdk.types.address import AddressUnion, deserialize_address +from iota_sdk.types.address import Address, deserialize_address from iota_sdk.types.common import EpochIndex, HexStr, json, SlotIndex @@ -30,20 +30,12 @@ class FeatureType(IntEnum): @json @dataclass -class Feature(): - """Base class of a feature. - """ - type: int - - -@json -@dataclass -class SenderFeature(Feature): +class SenderFeature: """Identifies the validated sender of an output. Attributes: address: A given sender address. """ - address: AddressUnion = field( + address: Address = field( metadata=config( decoder=deserialize_address )) @@ -55,12 +47,12 @@ class SenderFeature(Feature): @json @dataclass -class IssuerFeature(Feature): +class IssuerFeature: """Identifies the validated issuer of the UTXO state machine. Attributes: address: A given issuer address. """ - address: AddressUnion = field( + address: Address = field( metadata=config( decoder=deserialize_address )) @@ -72,7 +64,7 @@ class IssuerFeature(Feature): @json @dataclass -class MetadataFeature(Feature): +class MetadataFeature: """Defines metadata, arbitrary binary data, that will be stored in the output. Attributes: data: Some hex encoded metadata. @@ -86,7 +78,7 @@ class MetadataFeature(Feature): @json @dataclass -class TagFeature(Feature): +class TagFeature: """Makes it possible to tag outputs with an index, so they can be retrieved through an indexer API. Attributes: tag: A hex encoded tag used to index the output. @@ -97,7 +89,7 @@ class TagFeature(Feature): @json @dataclass -class BlockIssuerFeature(Feature): +class BlockIssuerFeature: """Contains the public keys to verify block signatures and allows for unbonding the issuer deposit. Attributes: expiry_slot: The slot index at which the Block Issuer Feature expires and can be removed. @@ -114,7 +106,7 @@ class BlockIssuerFeature(Feature): @json @dataclass -class StakingFeature(Feature): +class StakingFeature: """Stakes IOTA coins to become eligible for committee selection, validate the network and receive Mana rewards. Attributes: staked_amount: The amount of IOTA coins that are locked and staked in the containing account. @@ -132,11 +124,11 @@ class StakingFeature(Feature): init=False) -FeatureUnion: TypeAlias = Union[SenderFeature, IssuerFeature, - MetadataFeature, TagFeature, BlockIssuerFeature, StakingFeature] +Feature: TypeAlias = Union[SenderFeature, IssuerFeature, + MetadataFeature, TagFeature, BlockIssuerFeature, StakingFeature] -def deserialize_feature(d: Dict[str, Any]) -> FeatureUnion: +def deserialize_feature(d: Dict[str, Any]) -> Feature: """ Takes a dictionary as input and returns an instance of a specific class based on the value of the 'type' key in the dictionary. @@ -159,7 +151,7 @@ def deserialize_feature(d: Dict[str, Any]) -> FeatureUnion: raise Exception(f'invalid feature type: {feature_type}') -def deserialize_features(dicts: List[Dict[str, Any]]) -> List[FeatureUnion]: +def deserialize_features(dicts: List[Dict[str, Any]]) -> List[Feature]: """ Takes a list of dictionaries as input and returns a list with specific instances of a classes based on the value of the 'type' key in the dictionary. diff --git a/bindings/python/iota_sdk/types/output.py b/bindings/python/iota_sdk/types/output.py index a42923d6fb..956527a79c 100644 --- a/bindings/python/iota_sdk/types/output.py +++ b/bindings/python/iota_sdk/types/output.py @@ -31,15 +31,7 @@ class OutputType(IntEnum): @json @dataclass -class Output(): - """An output in a UTXO ledger. - """ - type: int - - -@json -@dataclass -class BasicOutput(Output): +class BasicOutput: """Describes a basic output. Attributes: amount : @@ -75,7 +67,7 @@ class BasicOutput(Output): @json @dataclass -class AccountOutput(Output): +class AccountOutput: """Describes an account output. Attributes: amount : @@ -131,7 +123,7 @@ class AccountOutput(Output): @json @dataclass -class FoundryOutput(Output): +class FoundryOutput: """Describes a foundry output. Attributes: amount : @@ -172,7 +164,7 @@ class FoundryOutput(Output): @json @dataclass -class NftOutput(Output): +class NftOutput: """Describes an NFT output. Attributes: amount : @@ -216,7 +208,7 @@ class NftOutput(Output): @json @dataclass -class DelegationOutput(Output): +class DelegationOutput: """Describes a delegation output. Attributes: type : @@ -227,11 +219,11 @@ class DelegationOutput(Output): OutputType.Delegation), init=False) -OutputUnion: TypeAlias = Union[BasicOutput, AccountOutput, - FoundryOutput, NftOutput, DelegationOutput] +Output: TypeAlias = Union[BasicOutput, AccountOutput, + FoundryOutput, NftOutput, DelegationOutput] -def deserialize_output(d: Dict[str, Any]) -> OutputUnion: +def deserialize_output(d: Dict[str, Any]) -> Output: """ Takes a dictionary as input and returns an instance of a specific class based on the value of the 'type' key in the dictionary. @@ -252,7 +244,7 @@ def deserialize_output(d: Dict[str, Any]) -> OutputUnion: raise Exception(f'invalid output type: {output_type}') -def deserialize_outputs(dicts: List[Dict[str, Any]]) -> List[OutputUnion]: +def deserialize_outputs(dicts: List[Dict[str, Any]]) -> List[Output]: """ Takes a list of dictionaries as input and returns a list with specific instances of a classes based on the value of the 'type' key in the dictionary. diff --git a/bindings/python/iota_sdk/types/output_data.py b/bindings/python/iota_sdk/types/output_data.py index 2c5fdeb428..61c07cd532 100644 --- a/bindings/python/iota_sdk/types/output_data.py +++ b/bindings/python/iota_sdk/types/output_data.py @@ -4,9 +4,9 @@ from __future__ import annotations from dataclasses import dataclass from typing import Optional -from iota_sdk.types.address import AddressUnion +from iota_sdk.types.address import Address from iota_sdk.types.common import HexStr, json -from iota_sdk.types.output import OutputUnion +from iota_sdk.types.output import Output from iota_sdk.types.output_metadata import OutputMetadata from iota_sdk.types.signature import Bip44 @@ -28,9 +28,9 @@ class OutputData(): """ output_id: HexStr metadata: OutputMetadata - output: OutputUnion + output: Output is_spent: bool - address: AddressUnion + address: Address network_id: str remainder: bool chain: Optional[Bip44] = None diff --git a/bindings/python/iota_sdk/types/payload.py b/bindings/python/iota_sdk/types/payload.py index 06eaa0c31c..9e14206a7d 100644 --- a/bindings/python/iota_sdk/types/payload.py +++ b/bindings/python/iota_sdk/types/payload.py @@ -6,7 +6,7 @@ from typing import Any, Dict, List, TypeAlias, Union from dataclasses import dataclass, field from iota_sdk.types.common import HexStr, json -from iota_sdk.types.essence import RegularTransactionEssence +from iota_sdk.types.essence import TransactionEssence from iota_sdk.types.unlock import SignatureUnlock, ReferenceUnlock @@ -23,15 +23,7 @@ class PayloadType(IntEnum): @json @dataclass -class Payload(): - """Initialize a Payload. - """ - type: int - - -@json -@dataclass -class TaggedDataPayload(Payload): +class TaggedDataPayload: """A tagged data payload. Attributes: @@ -48,14 +40,14 @@ class TaggedDataPayload(Payload): @json @dataclass -class TransactionPayload(Payload): +class TransactionPayload: """A transaction payload. Attributes: essence: The transaction essence. unlocks: The unlocks of the transaction. """ - essence: RegularTransactionEssence + essence: TransactionEssence unlocks: List[Union[SignatureUnlock, ReferenceUnlock]] type: int = field( default_factory=lambda: int( @@ -63,10 +55,10 @@ class TransactionPayload(Payload): init=False) -PayloadUnion: TypeAlias = Union[TaggedDataPayload, TransactionPayload] +Payload: TypeAlias = Union[TaggedDataPayload, TransactionPayload] -def deserialize_payload(d: Dict[str, Any]) -> PayloadUnion: +def deserialize_payload(d: Dict[str, Any]) -> Payload: """ Takes a dictionary as input and returns an instance of a specific class based on the value of the 'type' key in the dictionary. @@ -82,7 +74,7 @@ def deserialize_payload(d: Dict[str, Any]) -> PayloadUnion: def deserialize_payloads( - dicts: List[Dict[str, Any]]) -> List[PayloadUnion]: + dicts: List[Dict[str, Any]]) -> List[Payload]: """ Takes a list of dictionaries as input and returns a list with specific instances of a classes based on the value of the 'type' key in the dictionary. diff --git a/bindings/python/iota_sdk/types/signature.py b/bindings/python/iota_sdk/types/signature.py index 9dbc96e2fe..0112b9a3f5 100644 --- a/bindings/python/iota_sdk/types/signature.py +++ b/bindings/python/iota_sdk/types/signature.py @@ -1,22 +1,14 @@ # Copyright 2023 IOTA Stiftung # SPDX-License-Identifier: Apache-2.0 -from typing import TypeAlias, Union +from typing import TypeAlias from dataclasses import dataclass, field from iota_sdk.types.common import HexStr, CoinType, json @json @dataclass -class Signature(): - """Base class of a signature. - """ - type: int - - -@json -@dataclass -class Ed25519Signature(Signature): +class Ed25519Signature: """An Ed25519 signature. Attributes: @@ -29,7 +21,7 @@ class Ed25519Signature(Signature): type: int = field(default_factory=lambda: 0, init=False) -SignatureUnion: TypeAlias = Union[Ed25519Signature] +Signature: TypeAlias = Ed25519Signature @json diff --git a/bindings/python/iota_sdk/types/token_scheme.py b/bindings/python/iota_sdk/types/token_scheme.py index 962f3bec67..95d671ce2b 100644 --- a/bindings/python/iota_sdk/types/token_scheme.py +++ b/bindings/python/iota_sdk/types/token_scheme.py @@ -2,20 +2,13 @@ # SPDX-License-Identifier: Apache-2.0 from dataclasses import dataclass, field +from typing import TypeAlias from iota_sdk.types.common import HexStr, json @json @dataclass -class TokenScheme(): - """Base class of a token scheme. - """ - type: int - - -@json -@dataclass -class SimpleTokenScheme(TokenScheme): +class SimpleTokenScheme: """A simple token scheme. Attributes: @@ -43,3 +36,6 @@ def to_dict_custom(config): config['maximumSupply'] = str(hex(config['maximumSupply'])) return config + + +TokenScheme: TypeAlias = SimpleTokenScheme diff --git a/bindings/python/iota_sdk/types/transaction_data.py b/bindings/python/iota_sdk/types/transaction_data.py index 4d59d3b539..e7ab0f5092 100644 --- a/bindings/python/iota_sdk/types/transaction_data.py +++ b/bindings/python/iota_sdk/types/transaction_data.py @@ -4,10 +4,10 @@ from __future__ import annotations from dataclasses import dataclass from typing import Optional, List -from iota_sdk.types.address import AddressUnion -from iota_sdk.types.output import OutputUnion +from iota_sdk.types.address import Address +from iota_sdk.types.output import Output from iota_sdk.types.output_metadata import OutputMetadata -from iota_sdk.types.essence import RegularTransactionEssence +from iota_sdk.types.essence import TransactionEssence from iota_sdk.types.payload import TransactionPayload from iota_sdk.types.signature import Bip44 from iota_sdk.types.common import json @@ -23,7 +23,7 @@ class InputSigningData: output_metadata: The output metadata. chain: The BIP44 chain for the address to unlock the output. """ - output: OutputUnion + output: Output output_metadata: OutputMetadata chain: Optional[Bip44] = None @@ -38,8 +38,8 @@ class RemainderData: address: The remainder address. chain: The BIP44 chain for the remainder address. """ - output: OutputUnion - address: AddressUnion + output: Output + address: Address chain: Optional[Bip44] = None @@ -53,7 +53,7 @@ class PreparedTransactionData: inputs_data: Data about the inputs which is required for signing. remainder: Data about a remainder. """ - essence: RegularTransactionEssence + essence: TransactionEssence inputs_data: List[InputSigningData] remainder: Optional[RemainderData] = None diff --git a/bindings/python/iota_sdk/types/unlock_condition.py b/bindings/python/iota_sdk/types/unlock_condition.py index 6676f9681b..c7c573c1da 100644 --- a/bindings/python/iota_sdk/types/unlock_condition.py +++ b/bindings/python/iota_sdk/types/unlock_condition.py @@ -5,7 +5,7 @@ from dataclasses import dataclass, field from typing import Dict, List, TypeAlias, Union, Any from dataclasses_json import config -from iota_sdk.types.address import AddressUnion, AccountAddress +from iota_sdk.types.address import Address, AccountAddress from iota_sdk.types.common import json from iota_sdk.types.address import deserialize_address @@ -33,21 +33,13 @@ class UnlockConditionType(IntEnum): @json @dataclass -class UnlockCondition(): - """Base class for unlock conditions. - """ - type: int - - -@json -@dataclass -class AddressUnlockCondition(UnlockCondition): +class AddressUnlockCondition: """An address unlock condition. Args: address: An address unlocked with a private key. """ - address: AddressUnion = field( + address: Address = field( metadata=config( decoder=deserialize_address )) @@ -59,14 +51,14 @@ class AddressUnlockCondition(UnlockCondition): @json @dataclass -class StorageDepositReturnUnlockCondition(UnlockCondition): +class StorageDepositReturnUnlockCondition: """A storage-deposit-return unlock condition. Args: amount: The amount of base coins the consuming transaction must deposit to `return_address`. return_address: The address to return the amount to. """ amount: str - return_address: AddressUnion = field( + return_address: Address = field( metadata=config( decoder=deserialize_address )) @@ -76,7 +68,7 @@ class StorageDepositReturnUnlockCondition(UnlockCondition): @json @dataclass -class TimelockUnlockCondition(UnlockCondition): +class TimelockUnlockCondition: """A timelock unlock condition. Args: unix_time: The Unix timestamp marking the end of the timelock. @@ -90,14 +82,14 @@ class TimelockUnlockCondition(UnlockCondition): @json @dataclass -class ExpirationUnlockCondition(UnlockCondition): +class ExpirationUnlockCondition: """An expiration unlock condition. Args: unix_time: Unix timestamp marking the expiration of the claim. return_address: The return address if the output was not claimed in time. """ unix_time: int - return_address: AddressUnion = field( + return_address: Address = field( metadata=config( decoder=deserialize_address )) @@ -109,12 +101,12 @@ class ExpirationUnlockCondition(UnlockCondition): @json @dataclass -class StateControllerAddressUnlockCondition(UnlockCondition): +class StateControllerAddressUnlockCondition: """A state controller address unlock condition. Args: address: The state controller address that owns the output. """ - address: AddressUnion = field( + address: Address = field( metadata=config( decoder=deserialize_address )) @@ -124,12 +116,12 @@ class StateControllerAddressUnlockCondition(UnlockCondition): @json @dataclass -class GovernorAddressUnlockCondition(UnlockCondition): +class GovernorAddressUnlockCondition: """A governor address unlock condition. Args: address: The governor address that owns the output. """ - address: AddressUnion = field( + address: Address = field( metadata=config( decoder=deserialize_address )) @@ -139,7 +131,7 @@ class GovernorAddressUnlockCondition(UnlockCondition): @json @dataclass -class ImmutableAccountAddressUnlockCondition(UnlockCondition): +class ImmutableAccountAddressUnlockCondition: """An immutable account address unlock condition. Args: address: The permanent account address that owns this output. @@ -149,11 +141,11 @@ class ImmutableAccountAddressUnlockCondition(UnlockCondition): UnlockConditionType.ImmutableAccountAddress), init=False) -UnlockConditionUnion: TypeAlias = Union[AddressUnlockCondition, StorageDepositReturnUnlockCondition, TimelockUnlockCondition, - ExpirationUnlockCondition, StateControllerAddressUnlockCondition, GovernorAddressUnlockCondition, ImmutableAccountAddressUnlockCondition] +UnlockCondition: TypeAlias = Union[AddressUnlockCondition, StorageDepositReturnUnlockCondition, TimelockUnlockCondition, + ExpirationUnlockCondition, StateControllerAddressUnlockCondition, GovernorAddressUnlockCondition, ImmutableAccountAddressUnlockCondition] -def deserialize_unlock_condition(d: Dict[str, Any]) -> UnlockConditionUnion: +def deserialize_unlock_condition(d: Dict[str, Any]) -> UnlockCondition: """ Takes a dictionary as input and returns an instance of a specific class based on the value of the 'type' key in the dictionary. @@ -180,7 +172,7 @@ def deserialize_unlock_condition(d: Dict[str, Any]) -> UnlockConditionUnion: def deserialize_unlock_conditions( - dicts: List[Dict[str, Any]]) -> List[UnlockConditionUnion]: + dicts: List[Dict[str, Any]]) -> List[UnlockCondition]: """ Takes a list of dictionaries as input and returns a list with specific instances of a classes based on the value of the 'type' key in the dictionary. diff --git a/bindings/python/iota_sdk/utils.py b/bindings/python/iota_sdk/utils.py index 86929441fd..85d71ebe6a 100644 --- a/bindings/python/iota_sdk/utils.py +++ b/bindings/python/iota_sdk/utils.py @@ -5,9 +5,8 @@ from json import dumps, loads from typing import TYPE_CHECKING, List -from dacite import from_dict from iota_sdk.types.signature import Ed25519Signature -from iota_sdk.types.address import Address, AddressType, Ed25519Address, AccountAddress, NFTAddress +from iota_sdk.types.address import Address, deserialize_address from iota_sdk.types.common import HexStr from iota_sdk.types.essence import TransactionEssence from iota_sdk.types.node_info import ProtocolParameters @@ -77,15 +76,7 @@ def parse_bech32_address(address: str) -> Address: 'address': address }) - address_type = AddressType(response['type']) - - if address_type == AddressType.ED25519: - return from_dict(Ed25519Address, response) - if address_type == AddressType.ACCOUNT: - return from_dict(AccountAddress, response) - if address_type == AddressType.NFT: - return from_dict(NFTAddress, response) - return from_dict(Address, response) + deserialize_address(response) @staticmethod def is_address_valid(address: str) -> bool: diff --git a/bindings/python/tests/test_block.py b/bindings/python/tests/test_block.py index ad9f651e5f..120284f349 100644 --- a/bindings/python/tests/test_block.py +++ b/bindings/python/tests/test_block.py @@ -1,6 +1,7 @@ # Copyright 2023 IOTA Stiftung # SPDX-License-Identifier: Apache-2.0 +from typing import get_args from iota_sdk import BasicBlock, BlockType, BlockWrapper, Payload, PayloadType import pytest @@ -20,7 +21,7 @@ def test_basic_block_with_tagged_data_payload(): "data": "0x57652061726520616c6c206d616465206f662073746172647573742e0a436f756e743a20353436333730330a54696d657374616d703a20323032332d30372d31395430373a32323a32385a0a54697073656c656374696f6e3a20343732c2b573"}} block = BasicBlock.from_dict(block_dict) assert block.to_dict() == block_dict - assert isinstance(block.payload, Payload) + assert isinstance(block.payload, get_args(Payload)) assert block.payload.type == PayloadType.TaggedData @@ -61,7 +62,7 @@ def test_block_wrapper_with_tagged_data_payload(): 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, Payload) + 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" @@ -101,7 +102,7 @@ def test_basic_block_with_tx_payload(): "signature": "0x6bbe2eed95300a3d707af1bb17e04f83087fe31261256020fd00c24a54543c084079bed29c6d1479ee5acfd1e2fa32316e88c4c1577b4fbea3fe247f71114500"}}]}} block = BasicBlock.from_dict(block_dict) assert block.to_dict() == block_dict - assert isinstance(block.payload, Payload) + assert isinstance(block.payload, get_args(Payload)) assert block.payload.type == PayloadType.Transaction @@ -242,7 +243,7 @@ def test_basic_block_with_tx_payload_all_output_types(): "type": 1, "reference": 0}]}} block = BasicBlock.from_dict(block_dict) assert block.to_dict() == block_dict - assert isinstance(block.payload, Payload) + assert isinstance(block.payload, get_args(Payload)) assert block.payload.type == PayloadType.Transaction @@ -288,5 +289,5 @@ def test_basic_block_with_tx_payload_with_tagged_data_payload(): "reference": 0}]}} block = BasicBlock.from_dict(block_dict) assert block.to_dict() == block_dict - assert isinstance(block.payload, Payload) + assert isinstance(block.payload, get_args(Payload)) assert block.payload.type == PayloadType.Transaction From 60efd78b2877de41afe46998833f5e09999c2918 Mon Sep 17 00:00:00 2001 From: DaughterOfMars Date: Thu, 5 Oct 2023 05:16:20 -0400 Subject: [PATCH 2/2] Refactor block signature (#995) * Add parents to block * Add burned mana to rust block (#926) * merge imports * Split block into basic and validation types * udep * Comment out more tests that will change * oop * no_std * impl more of BlockWrapper * fix client block builder * Update sdk/src/types/block/protocol.rs Co-authored-by: Thibault Martinez * PR suggestion * no_std * Update sdk/src/types/block/validation.rs Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> * invalid block kind * Refactor types so that `Block` is the highest level enum * small improvements * Pr suggestions * Allow warnings and stub in missing values * clippy * properly pack kind and disable clippy CI for now * Implement new block ID * Rework BlockId into struct * serde with string * align dto to spec * PR suggestions * PR suggs * remove pub(crate) protocol params fields * cleanup * comments * fix tests * Use Signature for serialized layouts * more signature fixes * Refactor block signature * Fix block id computation, fix return type, reexport BlockHash, clippy (#998) * no_std * fix block ID slot index on big endian systems and clippy * fix with_slot_index too * PR suggestion * oof Co-authored-by: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com> * add memory layout test * no_std * Merge branch 2.0 * Add ext trait to help block builder signing * Update sdk/src/types/block/core.rs * Fix merge breakage and clippy * fix nostd * fix tests * remove generics * Nits * simplify name * rename trait * use header more * move it move it * PR suggestions * no_std * Nit --------- Co-authored-by: Thibault Martinez Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> Co-authored-by: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com> --- bindings/core/src/method_handler/client.rs | 7 +- .../client/block/00_block_no_payload.rs | 10 +- .../block/01_block_confirmation_time.rs | 10 +- .../client/block/02_block_custom_parents.rs | 10 +- .../client/block/03_block_custom_payload.rs | 10 +- .../client/block/04_block_tagged_data.rs | 10 +- .../client/node_api_core/04_post_block.rs | 10 +- .../client/node_api_core/05_post_block_raw.rs | 10 +- sdk/src/client/api/block_builder/mod.rs | 48 +++++---- sdk/src/client/secret/mod.rs | 28 ++++++ sdk/src/types/block/core/basic.rs | 12 +++ sdk/src/types/block/core/mod.rs | 26 ++++- sdk/src/types/block/core/validation.rs | 12 +++ sdk/src/types/block/core/wrapper.rs | 98 ++++++++++++++----- sdk/src/types/block/rand/block.rs | 69 +++++++++---- sdk/src/types/block/rand/signature.rs | 6 +- sdk/src/wallet/account/operations/balance.rs | 1 + .../account/operations/output_claiming.rs | 1 + .../operations/output_consolidation.rs | 1 + .../account/operations/output_finder.rs | 1 + .../operations/participation/voting.rs | 1 + .../operations/participation/voting_power.rs | 1 + sdk/src/wallet/account/operations/reissue.rs | 13 ++- .../wallet/account/operations/syncing/mod.rs | 1 + .../operations/syncing/transactions.rs | 1 + .../burning_melting/melt_native_token.rs | 1 + .../transaction/high_level/create_account.rs | 1 + .../high_level/minting/create_native_token.rs | 1 + .../high_level/minting/mint_native_token.rs | 1 + .../high_level/minting/mint_nfts.rs | 1 + .../operations/transaction/high_level/send.rs | 1 + .../high_level/send_native_tokens.rs | 1 + .../transaction/high_level/send_nft.rs | 1 + .../account/operations/transaction/mod.rs | 1 + .../operations/transaction/prepare_output.rs | 1 + .../transaction/prepare_transaction.rs | 1 + .../transaction/sign_transaction.rs | 1 + .../transaction/submit_transaction.rs | 8 +- sdk/src/wallet/core/mod.rs | 6 ++ .../core/operations/account_recovery.rs | 1 + .../core/operations/address_generation.rs | 1 + .../core/operations/background_syncing.rs | 1 + sdk/tests/client/node_api/core.rs | 12 ++- sdk/tests/client/node_api/mod.rs | 22 +++-- sdk/tests/types/block.rs | 20 ++-- 45 files changed, 359 insertions(+), 121 deletions(-) diff --git a/bindings/core/src/method_handler/client.rs b/bindings/core/src/method_handler/client.rs index bfae35f84b..5c1845d46d 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, Client}, + client::{request_funds_from_faucet, secret::SecretManager, Client}, types::{ api::core::response::OutputWithMetadataResponse, block::{ @@ -173,15 +173,16 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM ClientMethod::GetProtocolParameters => Response::ProtocolParameters(client.get_protocol_parameters().await?), ClientMethod::PostBlockPayload { payload } => { let block = client - .finish_basic_block_builder( + .build_basic_block::( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), None, Some(Payload::try_from_dto_with_params( payload, &client.get_protocol_parameters().await?, )?), + todo!("secret manager"), + todo!("chain"), ) .await?; diff --git a/sdk/examples/client/block/00_block_no_payload.rs b/sdk/examples/client/block/00_block_no_payload.rs index 015634be92..ce029516bc 100644 --- a/sdk/examples/client/block/00_block_no_payload.rs +++ b/sdk/examples/client/block/00_block_no_payload.rs @@ -8,7 +8,8 @@ //! cargo run --release --example block_no_payload //! ``` -use iota_sdk::client::{Client, Result}; +use crypto::keys::bip44::Bip44; +use iota_sdk::client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}; #[tokio::main] async fn main() -> Result<()> { @@ -20,14 +21,17 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; + let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + // Create and send the block. let block = client - .finish_basic_block_builder( + .build_basic_block( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), None, None, + &secret_manager, + Bip44::new(IOTA_COIN_TYPE), ) .await?; diff --git a/sdk/examples/client/block/01_block_confirmation_time.rs b/sdk/examples/client/block/01_block_confirmation_time.rs index 267562f40f..6b6b961dc8 100644 --- a/sdk/examples/client/block/01_block_confirmation_time.rs +++ b/sdk/examples/client/block/01_block_confirmation_time.rs @@ -8,8 +8,9 @@ //! cargo run --release --example block_confirmation_time //! ``` +use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{Client, Result}, + client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, types::api::core::response::BlockState, }; @@ -23,14 +24,17 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; + let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + // Create and send a block. let block = client - .finish_basic_block_builder( + .build_basic_block( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), None, None, + &secret_manager, + Bip44::new(IOTA_COIN_TYPE), ) .await?; let block_id = client.block_id(&block).await?; diff --git a/sdk/examples/client/block/02_block_custom_parents.rs b/sdk/examples/client/block/02_block_custom_parents.rs index 823da8d391..2a01e8f95b 100644 --- a/sdk/examples/client/block/02_block_custom_parents.rs +++ b/sdk/examples/client/block/02_block_custom_parents.rs @@ -8,7 +8,8 @@ //! cargo run --release --example block_custom_parents //! ``` -use iota_sdk::client::{Client, Result}; +use crypto::keys::bip44::Bip44; +use iota_sdk::client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}; #[tokio::main] async fn main() -> Result<()> { @@ -20,18 +21,21 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; + let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + // Use issuance as custom parents. let issuance = client.get_issuance().await?; println!("Issuance:\n{issuance:#?}"); // Create and send the block with custom parents. let block = client - .finish_basic_block_builder( + .build_basic_block( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), Some(issuance.strong_parents()?), None, + &secret_manager, + Bip44::new(IOTA_COIN_TYPE), ) .await?; diff --git a/sdk/examples/client/block/03_block_custom_payload.rs b/sdk/examples/client/block/03_block_custom_payload.rs index 90a621723a..b27c5a289c 100644 --- a/sdk/examples/client/block/03_block_custom_payload.rs +++ b/sdk/examples/client/block/03_block_custom_payload.rs @@ -8,8 +8,9 @@ //! cargo run --release --example block_custom_payload //! ``` +use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{Client, Result}, + client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, types::block::payload::{Payload, TaggedDataPayload}, }; @@ -23,17 +24,20 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; + let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + // Create a custom payload. let tagged_data_payload = TaggedDataPayload::new(*b"Your tag", *b"Your data")?; // Create and send the block with the custom payload. let block = client - .finish_basic_block_builder( + .build_basic_block( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), None, Some(Payload::from(tagged_data_payload)), + &secret_manager, + Bip44::new(IOTA_COIN_TYPE), ) .await?; diff --git a/sdk/examples/client/block/04_block_tagged_data.rs b/sdk/examples/client/block/04_block_tagged_data.rs index 16fee70d0f..2fc25aa84f 100644 --- a/sdk/examples/client/block/04_block_tagged_data.rs +++ b/sdk/examples/client/block/04_block_tagged_data.rs @@ -8,8 +8,9 @@ //! cargo run --release --example block_tagged_data [TAG] [DATA] //! ``` +use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{Client, Result}, + client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}, types::block::payload::{Payload, TaggedDataPayload}, }; @@ -23,11 +24,12 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; + let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + // Create and send the block with tag and data. let block = client - .finish_basic_block_builder( + .build_basic_block( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), None, Some(Payload::TaggedData(Box::new( @@ -43,6 +45,8 @@ async fn main() -> Result<()> { ) .unwrap(), ))), + &secret_manager, + Bip44::new(IOTA_COIN_TYPE), ) .await?; 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 17b277fe9f..414e3ca7cf 100644 --- a/sdk/examples/client/node_api_core/04_post_block.rs +++ b/sdk/examples/client/node_api_core/04_post_block.rs @@ -8,7 +8,8 @@ //! cargo run --release --example node_api_core_post_block [NODE URL] //! ``` -use iota_sdk::client::{Client, Result}; +use crypto::keys::bip44::Bip44; +use iota_sdk::client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}; #[tokio::main] async fn main() -> Result<()> { @@ -23,14 +24,17 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; + let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + // Create the block. let block = client - .finish_basic_block_builder( + .build_basic_block( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), None, None, + &secret_manager, + Bip44::new(IOTA_COIN_TYPE), ) .await?; // Post the block. 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 c93f8129c8..a20a0ad257 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 @@ -8,7 +8,8 @@ //! cargo run --release --example node_api_core_post_block_raw [NODE URL] //! ``` -use iota_sdk::client::{Client, Result}; +use crypto::keys::bip44::Bip44; +use iota_sdk::client::{constants::IOTA_COIN_TYPE, secret::SecretManager, Client, Result}; #[tokio::main] async fn main() -> Result<()> { @@ -23,14 +24,17 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; + let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + // Create the block. let block = client - .finish_basic_block_builder( + .build_basic_block( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), None, None, + &secret_manager, + Bip44::new(IOTA_COIN_TYPE), ) .await?; // Post the block as raw bytes. diff --git a/sdk/src/client/api/block_builder/mod.rs b/sdk/src/client/api/block_builder/mod.rs index a1d38def3f..80b5b78280 100644 --- a/sdk/src/client/api/block_builder/mod.rs +++ b/sdk/src/client/api/block_builder/mod.rs @@ -4,26 +4,34 @@ pub mod input_selection; pub mod transaction; +use crypto::keys::bip44::Bip44; + pub use self::transaction::verify_semantic; use crate::{ - client::{ClientInner, Result}, + client::{ + secret::{SecretManage, SignBlock}, + ClientInner, Result, + }, types::block::{ - core::{basic, Block, BlockWrapper}, + core::{basic, BlockHeader, BlockWrapper}, payload::Payload, - signature::Ed25519Signature, - IssuerId, + Block, IssuerId, }, }; impl ClientInner { - pub async fn finish_basic_block_builder( + pub async fn build_basic_block( &self, issuer_id: IssuerId, - signature: Ed25519Signature, issuing_time: Option, strong_parents: Option, payload: Option, - ) -> Result { + secret_manager: &S, + chain: Bip44, + ) -> Result + where + crate::client::Error: From, + { let issuance = self.get_issuance().await?; let strong_parents = strong_parents.unwrap_or(issuance.strong_parents()?); @@ -40,22 +48,24 @@ impl ClientInner { issuing_time }); - let protocol_parameters = self.get_protocol_parameters().await?; + let protocol_params = self.get_protocol_parameters().await?; - Ok(BlockWrapper::new( - protocol_parameters.version(), - protocol_parameters.network_id(), - issuing_time, - issuance.commitment.id(), - issuance.latest_finalized_slot, - issuer_id, - // TODO correct value for max_burned_mana - Block::build_basic(strong_parents, 0) + Ok(BlockWrapper::build( + BlockHeader::new( + protocol_params.version(), + protocol_params.network_id(), + issuing_time, + issuance.commitment.id(), + issuance.latest_finalized_slot, + issuer_id, + ), + Block::build_basic(strong_parents, 0) // TODO: burned mana calculation .with_weak_parents(issuance.weak_parents()?) .with_shallow_like_parents(issuance.shallow_like_parents()?) .with_payload(payload) .finish_block()?, - signature, - )) + ) + .sign_ed25519(secret_manager, chain) + .await?) } } diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index 67c58865e8..1815419905 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -53,10 +53,12 @@ use crate::{ }, types::block::{ address::{Address, Ed25519Address}, + core::BlockWrapperBuilder, output::Output, payload::{transaction::TransactionEssence, TransactionPayload}, signature::{Ed25519Signature, Signature}, unlock::{AccountUnlock, NftUnlock, ReferenceUnlock, SignatureUnlock, Unlock, Unlocks}, + BlockWrapper, }, }; @@ -602,3 +604,29 @@ where Ok(tx_payload) } + +#[async_trait] +pub trait SignBlock { + async fn sign_ed25519( + self, + secret_manager: &S, + chain: Bip44, + ) -> 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 + where + crate::client::Error: From, + { + let msg = self.signing_input(); + Ok(self.finish(secret_manager.sign_ed25519(&msg, chain).await?)?) + } +} diff --git a/sdk/src/types/block/core/basic.rs b/sdk/src/types/block/core/basic.rs index 7c19d46f28..5535c70075 100644 --- a/sdk/src/types/block/core/basic.rs +++ b/sdk/src/types/block/core/basic.rs @@ -95,6 +95,18 @@ impl BasicBlockBuilder { } } +impl From for BasicBlockBuilder { + fn from(value: BasicBlock) -> Self { + Self { + strong_parents: value.strong_parents, + weak_parents: value.weak_parents, + shallow_like_parents: value.shallow_like_parents, + payload: value.payload, + max_burned_mana: value.max_burned_mana, + } + } +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct BasicBlock { /// Blocks that are strongly directly approved. diff --git a/sdk/src/types/block/core/mod.rs b/sdk/src/types/block/core/mod.rs index 416f644b66..bd3c3fcd38 100644 --- a/sdk/src/types/block/core/mod.rs +++ b/sdk/src/types/block/core/mod.rs @@ -21,7 +21,7 @@ pub use self::{ basic::{BasicBlock, BasicBlockBuilder}, parent::Parents, validation::{ValidationBlock, ValidationBlockBuilder}, - wrapper::{BlockHeader, BlockWrapper}, + wrapper::{BlockHeader, BlockWrapper, BlockWrapperBuilder}, }; use crate::types::block::{ protocol::{ProtocolParameters, ProtocolParametersHash}, @@ -46,6 +46,30 @@ impl From for Block { } } +impl TryFrom for BasicBlockBuilder { + type Error = Error; + + fn try_from(value: Block) -> Result { + if let Block::Basic(block) = value { + Ok((*block).into()) + } else { + Err(Error::InvalidBlockKind(value.kind())) + } + } +} + +impl TryFrom for ValidationBlockBuilder { + type Error = Error; + + fn try_from(value: Block) -> Result { + if let Block::Validation(block) = value { + Ok((*block).into()) + } else { + Err(Error::InvalidBlockKind(value.kind())) + } + } +} + impl Block { /// Return the block kind of a [`Block`]. pub fn kind(&self) -> u8 { diff --git a/sdk/src/types/block/core/validation.rs b/sdk/src/types/block/core/validation.rs index 4e37a68bab..f93970c41b 100644 --- a/sdk/src/types/block/core/validation.rs +++ b/sdk/src/types/block/core/validation.rs @@ -98,6 +98,18 @@ impl ValidationBlockBuilder { } } +impl From for ValidationBlockBuilder { + fn from(value: ValidationBlock) -> Self { + Self { + strong_parents: value.strong_parents, + weak_parents: value.weak_parents, + shallow_like_parents: value.shallow_like_parents, + highest_supported_version: value.highest_supported_version, + protocol_parameters_hash: value.protocol_parameters_hash, + } + } +} + /// A Validation Block is a special type of block used by validators to secure the network. It is recognized by the /// Congestion Control of the IOTA 2.0 protocol and can be issued without burning Mana within the constraints of the /// allowed validator throughput. It is allowed to reference more parent blocks than a normal Basic Block. diff --git a/sdk/src/types/block/core/wrapper.rs b/sdk/src/types/block/core/wrapper.rs index ecf61b5f38..d66cf14d71 100644 --- a/sdk/src/types/block/core/wrapper.rs +++ b/sdk/src/types/block/core/wrapper.rs @@ -1,6 +1,7 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use alloc::vec::Vec; use core::mem::size_of; use crypto::hashes::{blake2b::Blake2b256, Digest}; @@ -21,6 +22,45 @@ use crate::types::block::{ Block, Error, IssuerId, }; +/// Builder for a [`BlockWrapper`]. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct BlockWrapperBuilder { + /// The block header. + pub(crate) header: BlockHeader, + /// The inner block. + pub(crate) block: Block, +} + +impl BlockWrapperBuilder { + pub fn new(header: BlockHeader, block: Block) -> Self { + Self { header, block } + } + + /// Updates the block header. + #[inline(always)] + pub fn with_block_header(mut self, header: BlockHeader) -> Self { + self.header = header; + self + } + + /// Updates the block. + #[inline(always)] + pub fn with_block(mut self, block: Block) -> Self { + self.block = block; + self + } + + /// Get the signing input that can be used to generate a [`Signature`](crate::types::block::signature::Signature) + /// for the resulting block. + pub fn signing_input(&self) -> Vec { + [self.header.hash(), self.block.hash()].concat() + } + + pub fn finish(self, signature: impl Into) -> Result { + Ok(BlockWrapper::new(self.header, self.block, signature)) + } +} + #[derive(Clone, Debug, Eq, PartialEq, CopyGetters)] #[getset(get_copy = "pub")] pub struct BlockHeader { @@ -43,6 +83,24 @@ impl BlockHeader { pub const LENGTH: usize = size_of::() + 2 * size_of::() + SlotCommitmentId::LENGTH + size_of::() + IssuerId::LENGTH; + pub fn new( + protocol_version: u8, + network_id: u64, + issuing_time: u64, + slot_commitment_id: SlotCommitmentId, + latest_finalized_slot: SlotIndex, + issuer_id: IssuerId, + ) -> Self { + Self { + protocol_version, + network_id, + issuing_time, + slot_commitment_id, + latest_finalized_slot, + issuer_id, + } + } + pub(crate) fn hash(&self) -> [u8; 32] { let mut bytes = [0u8; Self::LENGTH]; @@ -128,25 +186,7 @@ impl BlockWrapper { /// Creates a new [`BlockWrapper`]. #[inline(always)] - pub fn new( - protocol_version: u8, - network_id: u64, - issuing_time: u64, - slot_commitment_id: SlotCommitmentId, - latest_finalized_slot: SlotIndex, - issuer_id: IssuerId, - block: impl Into, - signature: impl Into, - ) -> Self { - let header = BlockHeader { - protocol_version, - network_id, - issuing_time, - slot_commitment_id, - latest_finalized_slot, - issuer_id, - }; - let block = block.into(); + pub fn new(header: BlockHeader, block: Block, signature: impl Into) -> Self { let signature = signature.into(); Self { @@ -156,6 +196,12 @@ impl BlockWrapper { } } + /// Creates a new [`BlockWrapperBuilder`]. + #[inline(always)] + pub fn build(header: BlockHeader, block: Block) -> BlockWrapperBuilder { + BlockWrapperBuilder::new(header, block) + } + /// Returns the protocol version of a [`BlockWrapper`]. #[inline(always)] pub fn protocol_version(&self) -> u8 { @@ -353,12 +399,14 @@ pub(crate) mod dto { } Ok(Self::new( - dto.protocol_version, - dto.network_id, - dto.issuing_time, - dto.slot_commitment_id, - dto.latest_finalized_slot, - dto.issuer_id, + BlockHeader::new( + dto.protocol_version, + dto.network_id, + dto.issuing_time, + dto.slot_commitment_id, + dto.latest_finalized_slot, + dto.issuer_id, + ), Block::try_from_dto_with_params_inner(dto.block, params)?, dto.signature, )) diff --git a/sdk/src/types/block/rand/block.rs b/sdk/src/types/block/rand/block.rs index c1de20b13d..cedfa623ce 100644 --- a/sdk/src/types/block/rand/block.rs +++ b/sdk/src/types/block/rand/block.rs @@ -4,7 +4,10 @@ use alloc::vec::Vec; use crate::types::block::{ - core::{basic, BasicBlockBuilder, Block, BlockWrapper}, + core::{ + basic::{self, BasicBlockBuilder}, + BlockHeader, BlockWrapper, BlockWrapperBuilder, + }, protocol::ProtocolParameters, rand::{ bytes::rand_bytes_array, @@ -12,10 +15,10 @@ use crate::types::block::{ number::rand_number, parents::rand_strong_parents, payload::rand_payload_for_block, - signature::rand_signature, + signature::rand_sign_ed25519, slot::{rand_slot_commitment_id, rand_slot_index}, }, - BlockId, + Block, BlockId, }; /// Generates a random block id. @@ -31,30 +34,54 @@ pub fn rand_block_ids(len: usize) -> Vec { } /// Generates a random basic block with given strong parents. +pub fn rand_basic_block_with_strong_parents(strong_parents: basic::StrongParents) -> Block { + rand_basic_block_builder_with_strong_parents(strong_parents) + .with_payload(rand_payload_for_block()) + .finish_block() + .unwrap() +} + +/// Generates a random basic block builder with given strong parents. pub fn rand_basic_block_builder_with_strong_parents(strong_parents: basic::StrongParents) -> BasicBlockBuilder { - Block::build_basic(strong_parents, rand_number()).with_payload(rand_payload_for_block()) + Block::build_basic(strong_parents, rand_number()) } -/// Generates a random block wrapper. -pub fn rand_block_wrapper_with_block(protocol_params: &ProtocolParameters, block: impl Into) -> BlockWrapper { - BlockWrapper::new( - protocol_params.version(), - protocol_params.network_id(), - rand_number(), - rand_slot_commitment_id(), - rand_slot_index(), - rand_issuer_id(), +/// Generates a random block wrapper with given block. +pub fn rand_block_wrapper_with_block(protocol_params: ProtocolParameters, block: Block) -> BlockWrapper { + BlockWrapper::build( + BlockHeader::new( + protocol_params.version(), + protocol_params.network_id(), + rand_number(), + rand_slot_commitment_id(), + rand_slot_index(), + rand_issuer_id(), + ), block, - rand_signature(), ) + .sign_random() +} + +/// Generates a random block wrapper with given strong parents. +pub fn rand_block_wrapper_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)) } /// Generates a random block wrapper. -pub fn rand_block_wrapper(protocol_params: &ProtocolParameters) -> BlockWrapper { - rand_block_wrapper_with_block( - protocol_params, - rand_basic_block_builder_with_strong_parents(rand_strong_parents()) - .finish_block() - .unwrap(), - ) +pub fn rand_block_wrapper(protocol_params: ProtocolParameters) -> BlockWrapper { + rand_block_wrapper_with_strong_parents(protocol_params, rand_strong_parents()) +} + +pub trait SignBlockRandom { + fn sign_random(self) -> BlockWrapper; +} + +impl SignBlockRandom for BlockWrapperBuilder { + fn sign_random(self) -> BlockWrapper { + let signing_input = self.signing_input(); + self.finish(rand_sign_ed25519(&signing_input)).unwrap() + } } diff --git a/sdk/src/types/block/rand/signature.rs b/sdk/src/types/block/rand/signature.rs index 7ffd5d5508..d9a7680ce3 100644 --- a/sdk/src/types/block/rand/signature.rs +++ b/sdk/src/types/block/rand/signature.rs @@ -13,6 +13,10 @@ use super::bytes::{rand_bytes, rand_bytes_array}; use crate::types::block::signature::{Ed25519Signature, Signature}; pub fn rand_ed25519_signature() -> Ed25519Signature { + rand_sign_ed25519(&rand_bytes(64)) +} + +pub fn rand_sign_ed25519(msg: &[u8]) -> Ed25519Signature { let mnemonic = wordlist::encode(&rand_bytes_array::<32>(), &wordlist::ENGLISH).unwrap(); let seed = Seed::from(mnemonic_to_seed(&mnemonic, &Passphrase::default())); let chain = [0; 5]; @@ -20,7 +24,7 @@ pub fn rand_ed25519_signature() -> Ed25519Signature { .derive::(chain.into_iter().map(Segment::harden)) .secret_key(); let public_key = private_key.public_key(); - let signature = private_key.sign(&rand_bytes(64)); + let signature = private_key.sign(msg); Ed25519Signature::new(public_key, signature) } diff --git a/sdk/src/wallet/account/operations/balance.rs b/sdk/src/wallet/account/operations/balance.rs index 0a6d8fb026..2d71126820 100644 --- a/sdk/src/wallet/account/operations/balance.rs +++ b/sdk/src/wallet/account/operations/balance.rs @@ -23,6 +23,7 @@ use crate::{ impl Account where Error: From, + crate::client::Error: From, { /// Get the balance of the account. pub async fn balance(&self) -> Result { diff --git a/sdk/src/wallet/account/operations/output_claiming.rs b/sdk/src/wallet/account/operations/output_claiming.rs index 66192f018a..000b26513f 100644 --- a/sdk/src/wallet/account/operations/output_claiming.rs +++ b/sdk/src/wallet/account/operations/output_claiming.rs @@ -36,6 +36,7 @@ pub enum OutputsToClaim { impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Get basic and nft outputs that have /// [`ExpirationUnlockCondition`](crate::types::block::output::unlock_condition::ExpirationUnlockCondition), diff --git a/sdk/src/wallet/account/operations/output_consolidation.rs b/sdk/src/wallet/account/operations/output_consolidation.rs index d27feae1ce..acf4577198 100644 --- a/sdk/src/wallet/account/operations/output_consolidation.rs +++ b/sdk/src/wallet/account/operations/output_consolidation.rs @@ -73,6 +73,7 @@ impl ConsolidationParams { impl Account where crate::wallet::Error: From, + crate::client::Error: From, { fn should_consolidate_output( &self, diff --git a/sdk/src/wallet/account/operations/output_finder.rs b/sdk/src/wallet/account/operations/output_finder.rs index eab49bdb0d..e15c6cf683 100644 --- a/sdk/src/wallet/account/operations/output_finder.rs +++ b/sdk/src/wallet/account/operations/output_finder.rs @@ -11,6 +11,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Search addresses with unspent outputs /// `address_gap_limit`: The number of addresses to search for, after the last address with unspent outputs diff --git a/sdk/src/wallet/account/operations/participation/voting.rs b/sdk/src/wallet/account/operations/participation/voting.rs index 26b1c541dd..dda76cbf49 100644 --- a/sdk/src/wallet/account/operations/participation/voting.rs +++ b/sdk/src/wallet/account/operations/participation/voting.rs @@ -22,6 +22,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Casts a given number of votes for a given (voting) event. /// diff --git a/sdk/src/wallet/account/operations/participation/voting_power.rs b/sdk/src/wallet/account/operations/participation/voting_power.rs index 7abe682f60..bc14c01f80 100644 --- a/sdk/src/wallet/account/operations/participation/voting_power.rs +++ b/sdk/src/wallet/account/operations/participation/voting_power.rs @@ -23,6 +23,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Returns an account's total voting power (voting or NOT voting). pub async fn get_voting_power(&self) -> Result { diff --git a/sdk/src/wallet/account/operations/reissue.rs b/sdk/src/wallet/account/operations/reissue.rs index 9124ceabcd..54c93a4f42 100644 --- a/sdk/src/wallet/account/operations/reissue.rs +++ b/sdk/src/wallet/account/operations/reissue.rs @@ -1,6 +1,8 @@ // Copyright 2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use crypto::keys::bip44::Bip44; + use crate::{ client::{secret::SecretManage, Error as ClientError}, types::{ @@ -22,6 +24,7 @@ const DEFAULT_REISSUE_UNTIL_INCLUDED_MAX_AMOUNT: u64 = 40; impl Account where Error: From, + crate::client::Error: From, { /// Reissues a transaction sent from the account for a provided transaction id until it's /// included (referenced by a milestone). Returns the included block id. @@ -55,12 +58,13 @@ where Some(block_id) => block_id, None => self .client() - .finish_basic_block_builder( + .build_basic_block( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), None, Some(Payload::Transaction(Box::new(transaction.payload.clone()))), + &*self.get_secret_manager().read().await, + Bip44::new(self.wallet.coin_type()), ) .await? .id(&protocol_parameters), @@ -104,12 +108,13 @@ where if index == block_ids_len - 1 && should_reissue { let reissued_block = self .client() - .finish_basic_block_builder( + .build_basic_block( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), None, Some(Payload::Transaction(Box::new(transaction.payload.clone()))), + &*self.get_secret_manager().read().await, + Bip44::new(self.wallet.coin_type()), ) .await?; block_ids.push(reissued_block.id(&protocol_parameters)); diff --git a/sdk/src/wallet/account/operations/syncing/mod.rs b/sdk/src/wallet/account/operations/syncing/mod.rs index 250a3beb45..84019b4641 100644 --- a/sdk/src/wallet/account/operations/syncing/mod.rs +++ b/sdk/src/wallet/account/operations/syncing/mod.rs @@ -26,6 +26,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Set the fallback SyncOptions for account syncing. /// If storage is enabled, will persist during restarts. diff --git a/sdk/src/wallet/account/operations/syncing/transactions.rs b/sdk/src/wallet/account/operations/syncing/transactions.rs index d0dbeff01b..028ab8ecf4 100644 --- a/sdk/src/wallet/account/operations/syncing/transactions.rs +++ b/sdk/src/wallet/account/operations/syncing/transactions.rs @@ -21,6 +21,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Sync transactions and reissue them if unconfirmed. Returns the transaction with updated metadata and spent /// output ids that don't need to be locked anymore diff --git a/sdk/src/wallet/account/operations/transaction/high_level/burning_melting/melt_native_token.rs b/sdk/src/wallet/account/operations/transaction/high_level/burning_melting/melt_native_token.rs index 242e329164..759879ce96 100644 --- a/sdk/src/wallet/account/operations/transaction/high_level/burning_melting/melt_native_token.rs +++ b/sdk/src/wallet/account/operations/transaction/high_level/burning_melting/melt_native_token.rs @@ -18,6 +18,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Melts native tokens. /// diff --git a/sdk/src/wallet/account/operations/transaction/high_level/create_account.rs b/sdk/src/wallet/account/operations/transaction/high_level/create_account.rs index 6a5a4b2310..4259eb6b63 100644 --- a/sdk/src/wallet/account/operations/transaction/high_level/create_account.rs +++ b/sdk/src/wallet/account/operations/transaction/high_level/create_account.rs @@ -38,6 +38,7 @@ pub struct CreateAccountParams { impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Creates an account output. /// ```ignore diff --git a/sdk/src/wallet/account/operations/transaction/high_level/minting/create_native_token.rs b/sdk/src/wallet/account/operations/transaction/high_level/minting/create_native_token.rs index 8e7c71997e..4d07f59381 100644 --- a/sdk/src/wallet/account/operations/transaction/high_level/minting/create_native_token.rs +++ b/sdk/src/wallet/account/operations/transaction/high_level/minting/create_native_token.rs @@ -88,6 +88,7 @@ impl From<&PreparedCreateNativeTokenTransaction> for PreparedCreateNativeTokenTr impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Creates a new foundry output with minted native tokens. /// diff --git a/sdk/src/wallet/account/operations/transaction/high_level/minting/mint_native_token.rs b/sdk/src/wallet/account/operations/transaction/high_level/minting/mint_native_token.rs index 6fa5103052..219ad5867f 100644 --- a/sdk/src/wallet/account/operations/transaction/high_level/minting/mint_native_token.rs +++ b/sdk/src/wallet/account/operations/transaction/high_level/minting/mint_native_token.rs @@ -17,6 +17,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Mints additional native tokens. /// diff --git a/sdk/src/wallet/account/operations/transaction/high_level/minting/mint_nfts.rs b/sdk/src/wallet/account/operations/transaction/high_level/minting/mint_nfts.rs index 18996d33ee..7bbdd202d5 100644 --- a/sdk/src/wallet/account/operations/transaction/high_level/minting/mint_nfts.rs +++ b/sdk/src/wallet/account/operations/transaction/high_level/minting/mint_nfts.rs @@ -112,6 +112,7 @@ impl MintNftParams { impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Mints NFTs. /// diff --git a/sdk/src/wallet/account/operations/transaction/high_level/send.rs b/sdk/src/wallet/account/operations/transaction/high_level/send.rs index 943aa87b9f..1da4896136 100644 --- a/sdk/src/wallet/account/operations/transaction/high_level/send.rs +++ b/sdk/src/wallet/account/operations/transaction/high_level/send.rs @@ -80,6 +80,7 @@ impl SendParams { impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Sends a certain amount of base coins to a single address. /// diff --git a/sdk/src/wallet/account/operations/transaction/high_level/send_native_tokens.rs b/sdk/src/wallet/account/operations/transaction/high_level/send_native_tokens.rs index 758074730e..f59c3d2144 100644 --- a/sdk/src/wallet/account/operations/transaction/high_level/send_native_tokens.rs +++ b/sdk/src/wallet/account/operations/transaction/high_level/send_native_tokens.rs @@ -82,6 +82,7 @@ impl SendNativeTokensParams { impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Sends native tokens in basic outputs with a [`StorageDepositReturnUnlockCondition`] and an /// [`ExpirationUnlockCondition`], so that the storage deposit is returned to the sender and the sender gets access diff --git a/sdk/src/wallet/account/operations/transaction/high_level/send_nft.rs b/sdk/src/wallet/account/operations/transaction/high_level/send_nft.rs index 32e56d3676..eb371cd421 100644 --- a/sdk/src/wallet/account/operations/transaction/high_level/send_nft.rs +++ b/sdk/src/wallet/account/operations/transaction/high_level/send_nft.rs @@ -42,6 +42,7 @@ impl SendNftParams { impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Sends native tokens in basic outputs with a /// [`StorageDepositReturnUnlockCondition`](crate::types::block::output::unlock_condition::StorageDepositReturnUnlockCondition) and an diff --git a/sdk/src/wallet/account/operations/transaction/mod.rs b/sdk/src/wallet/account/operations/transaction/mod.rs index c3003ef4f8..4a88d21660 100644 --- a/sdk/src/wallet/account/operations/transaction/mod.rs +++ b/sdk/src/wallet/account/operations/transaction/mod.rs @@ -33,6 +33,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Sends a transaction by specifying its outputs. /// diff --git a/sdk/src/wallet/account/operations/transaction/prepare_output.rs b/sdk/src/wallet/account/operations/transaction/prepare_output.rs index f682314eb9..b904acdb9f 100644 --- a/sdk/src/wallet/account/operations/transaction/prepare_output.rs +++ b/sdk/src/wallet/account/operations/transaction/prepare_output.rs @@ -28,6 +28,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Prepare a basic or NFT output for sending /// If the amount is below the minimum required storage deposit, by default the remaining amount will automatically diff --git a/sdk/src/wallet/account/operations/transaction/prepare_transaction.rs b/sdk/src/wallet/account/operations/transaction/prepare_transaction.rs index 659fbb028d..39086d7b2d 100644 --- a/sdk/src/wallet/account/operations/transaction/prepare_transaction.rs +++ b/sdk/src/wallet/account/operations/transaction/prepare_transaction.rs @@ -23,6 +23,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Get inputs and build the transaction essence pub async fn prepare_transaction( diff --git a/sdk/src/wallet/account/operations/transaction/sign_transaction.rs b/sdk/src/wallet/account/operations/transaction/sign_transaction.rs index 883d0631a4..01c2242481 100644 --- a/sdk/src/wallet/account/operations/transaction/sign_transaction.rs +++ b/sdk/src/wallet/account/operations/transaction/sign_transaction.rs @@ -23,6 +23,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Signs a transaction essence. pub async fn sign_transaction_essence( diff --git a/sdk/src/wallet/account/operations/transaction/submit_transaction.rs b/sdk/src/wallet/account/operations/transaction/submit_transaction.rs index 916f21a875..3175410e34 100644 --- a/sdk/src/wallet/account/operations/transaction/submit_transaction.rs +++ b/sdk/src/wallet/account/operations/transaction/submit_transaction.rs @@ -1,6 +1,8 @@ // Copyright 2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use crypto::keys::bip44::Bip44; + #[cfg(feature = "events")] use crate::wallet::events::types::{TransactionProgressEvent, WalletEvent}; use crate::{ @@ -12,6 +14,7 @@ use crate::{ impl Account where crate::wallet::Error: From, + crate::client::Error: From, { /// Submits a payload in a block pub(crate) async fn submit_transaction_payload( @@ -24,12 +27,13 @@ where let block = self .client() - .finish_basic_block_builder( + .build_basic_block( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), None, Some(Payload::from(transaction_payload)), + &*self.get_secret_manager().read().await, + Bip44::new(self.wallet.coin_type()), ) .await?; diff --git a/sdk/src/wallet/core/mod.rs b/sdk/src/wallet/core/mod.rs index 837408de50..0eb401fdf9 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -4,6 +4,7 @@ pub(crate) mod builder; pub(crate) mod operations; +use core::sync::atomic::Ordering; use std::sync::{ atomic::{AtomicU32, AtomicUsize}, Arc, @@ -88,6 +89,7 @@ pub struct WalletInner { impl Wallet where crate::wallet::Error: From, + crate::client::Error: From, { /// Get all accounts pub async fn get_accounts(&self) -> crate::wallet::Result>> { @@ -167,6 +169,10 @@ where } impl WalletInner { + pub fn coin_type(&self) -> u32 { + self.coin_type.load(Ordering::Relaxed) + } + /// Get the [SecretManager] pub fn get_secret_manager(&self) -> &Arc> { &self.secret_manager diff --git a/sdk/src/wallet/core/operations/account_recovery.rs b/sdk/src/wallet/core/operations/account_recovery.rs index f72ea75da8..743639080d 100644 --- a/sdk/src/wallet/core/operations/account_recovery.rs +++ b/sdk/src/wallet/core/operations/account_recovery.rs @@ -11,6 +11,7 @@ use crate::{ impl Wallet where crate::wallet::Error: From, + crate::client::Error: From, { /// Find accounts with unspent outputs. /// diff --git a/sdk/src/wallet/core/operations/address_generation.rs b/sdk/src/wallet/core/operations/address_generation.rs index f84277de38..6fb477fa87 100644 --- a/sdk/src/wallet/core/operations/address_generation.rs +++ b/sdk/src/wallet/core/operations/address_generation.rs @@ -132,6 +132,7 @@ impl Wallet { impl Wallet where crate::wallet::Error: From, + crate::client::Error: From, { /// Get the bech32 hrp from the first account address or if not existent, from the client pub async fn get_bech32_hrp(&self) -> crate::wallet::Result { diff --git a/sdk/src/wallet/core/operations/background_syncing.rs b/sdk/src/wallet/core/operations/background_syncing.rs index f7f59fa24d..174317c9c2 100644 --- a/sdk/src/wallet/core/operations/background_syncing.rs +++ b/sdk/src/wallet/core/operations/background_syncing.rs @@ -16,6 +16,7 @@ pub(crate) const DEFAULT_BACKGROUNDSYNCING_INTERVAL: Duration = Duration::from_s impl Wallet where crate::wallet::Error: From, + crate::client::Error: From, { /// Start the background syncing process for all accounts, default interval is 7 seconds pub async fn start_background_syncing( diff --git a/sdk/tests/client/node_api/core.rs b/sdk/tests/client/node_api/core.rs index ffc73afa7f..b44bae435a 100644 --- a/sdk/tests/client/node_api/core.rs +++ b/sdk/tests/client/node_api/core.rs @@ -50,7 +50,8 @@ async fn test_get_issuance() { #[ignore] #[tokio::test] async fn test_post_block_with_tagged_data() { - let block_id = setup_tagged_data_block().await; + let secret_manager = setup_secret_manager(); + let block_id = setup_tagged_data_block(&secret_manager).await; println!("{block_id}"); } @@ -66,8 +67,9 @@ async fn test_post_block_with_transaction() { #[tokio::test] async fn test_get_block_data() { let client = setup_client_with_node_health_ignored().await; + let secret_manager = setup_secret_manager(); - let block_id = setup_tagged_data_block().await; + let block_id = setup_tagged_data_block(&secret_manager).await; let r = client.get_block(&block_id).await.unwrap(); println!("{r:#?}"); @@ -76,7 +78,8 @@ async fn test_get_block_data() { #[ignore] #[tokio::test] async fn test_get_block_metadata() { - let block_id = setup_tagged_data_block().await; + let secret_manager = setup_secret_manager(); + let block_id = setup_tagged_data_block(&secret_manager).await; let r = setup_client_with_node_health_ignored() .await @@ -90,7 +93,8 @@ async fn test_get_block_metadata() { #[ignore] #[tokio::test] async fn test_get_block_raw() { - let block_id = setup_tagged_data_block().await; + let secret_manager = setup_secret_manager(); + let block_id = setup_tagged_data_block(&secret_manager).await; let r = setup_client_with_node_health_ignored() .await diff --git a/sdk/tests/client/node_api/mod.rs b/sdk/tests/client/node_api/mod.rs index d79dd52193..f4839038af 100644 --- a/sdk/tests/client/node_api/mod.rs +++ b/sdk/tests/client/node_api/mod.rs @@ -6,10 +6,11 @@ mod indexer; #[cfg(feature = "mqtt")] mod mqtt; +use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ - api::GetAddressesOptions, node_api::indexer::query_parameters::QueryParameter, request_funds_from_faucet, - secret::SecretManager, Client, + api::GetAddressesOptions, constants::IOTA_COIN_TYPE, node_api::indexer::query_parameters::QueryParameter, + request_funds_from_faucet, secret::SecretManager, Client, }, types::block::{ payload::{tagged_data::TaggedDataPayload, transaction::TransactionId, Payload}, @@ -23,22 +24,25 @@ use crate::client::common::{setup_client_with_node_health_ignored, FAUCET_URL}; const DEFAULT_DEVELOPMENT_SEED: &str = "0x256a818b2aac458941f7274985a410e57fb750f3a3a67969ece5bd9ae7eef5b2"; // Sends a tagged data block to the node to test against it. -async fn setup_tagged_data_block() -> BlockId { +async fn setup_tagged_data_block(secret_manager: &SecretManager) -> BlockId { let client = setup_client_with_node_health_ignored().await; - let block = client - .finish_basic_block_builder( + + let protocol_params = client.get_protocol_parameters().await.unwrap(); + + client + .build_basic_block( todo!("issuer id"), - todo!("block signature"), todo!("issuing time"), None, 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(); - - client.block_id(&block).await.unwrap() + .unwrap() + .id(&protocol_params) } pub fn setup_secret_manager() -> SecretManager { diff --git a/sdk/tests/types/block.rs b/sdk/tests/types/block.rs index a2939defba..0a19f5ff98 100644 --- a/sdk/tests/types/block.rs +++ b/sdk/tests/types/block.rs @@ -92,7 +92,7 @@ use packable::PackableExt; #[test] fn pack_unpack_valid() { let protocol_parameters = protocol_parameters(); - let block = rand_block_wrapper(&protocol_parameters); + let block = rand_block_wrapper(protocol_parameters.clone()); let packed_block = block.pack_to_vec(); assert_eq!(packed_block.len(), block.packed_len()); @@ -108,17 +108,15 @@ fn getters() { let parents = rand_strong_parents(); let payload = Payload::from(rand_tagged_data_payload()); - let block = rand_block_wrapper_with_block( - &protocol_parameters, - rand_basic_block_builder_with_strong_parents(parents.clone()) - .with_payload(payload.clone()) - .finish() - .unwrap(), - ); + let block = rand_basic_block_builder_with_strong_parents(parents.clone()) + .with_payload(payload.clone()) + .finish_block() + .unwrap(); + let wrapper = rand_block_wrapper_with_block(protocol_parameters.clone(), block); - assert_eq!(block.protocol_version(), protocol_parameters.version()); - assert_eq!(*block.as_basic().strong_parents(), parents); - assert_eq!(*block.as_basic().payload().as_ref().unwrap(), &payload); + 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); } #[test]