diff --git a/.github/workflows/bindings-python.yml b/.github/workflows/bindings-python.yml index 8525900d93..dfa5f77a84 100644 --- a/.github/workflows/bindings-python.yml +++ b/.github/workflows/bindings-python.yml @@ -121,7 +121,6 @@ jobs: working-directory: bindings/python run: tox -e lint-examples - # TODO temporarily disabled https://github.com/iotaledger/iota-sdk/issues/647 - # - name: Run tests - # working-directory: bindings/python - # run: tox + - name: Run tests + working-directory: bindings/python + run: tox diff --git a/bindings/python/examples/client/07_get_block_data.py b/bindings/python/examples/client/07_get_block.py similarity index 93% rename from bindings/python/examples/client/07_get_block_data.py rename to bindings/python/examples/client/07_get_block.py index 595ac43fa0..d856995aeb 100644 --- a/bindings/python/examples/client/07_get_block_data.py +++ b/bindings/python/examples/client/07_get_block.py @@ -22,5 +22,5 @@ print(f'Block metadata: {json.dumps(asdict(metadata), indent=4)}') # Request the block by its id -block = client.get_block_data(block_ids[0]) +block = client.get_block(block_ids[0]) print(f'Block: {json.dumps(asdict(block), indent=4)}') diff --git a/bindings/python/examples/client/08_data_block.py b/bindings/python/examples/client/08_data_block.py index 7ecd85e81b..fb068471bb 100644 --- a/bindings/python/examples/client/08_data_block.py +++ b/bindings/python/examples/client/08_data_block.py @@ -3,7 +3,7 @@ import os from dataclasses import asdict from dotenv import load_dotenv -from iota_sdk import Client, utf8_to_hex, hex_to_utf8, TaggedDataPayload +from iota_sdk import BasicBlock, Client, utf8_to_hex, hex_to_utf8, TaggedDataPayload load_dotenv() @@ -13,17 +13,21 @@ client = Client(nodes=[node_url]) # Create and post a block with a tagged data payload -block = client.submit_payload( +block_id = client.submit_payload( TaggedDataPayload( utf8_to_hex("tag"), - utf8_to_hex("data"))) + utf8_to_hex("data")))[0] -print(f'Data block sent: {os.environ["EXPLORER_URL"]}/block/{block[0]}') +print(f'Data block sent: {os.environ["EXPLORER_URL"]}/block/{block_id}') -block = client.get_block_data(block[0]) -print(f'Block data: {json.dumps(asdict(block), indent=4)}') +block = client.get_block(block_id).block -payload = block.payload +if isinstance(block, BasicBlock): + print(f'Block data: {json.dumps(asdict(block), indent=4)}') -if payload and 'data' in payload and payload['data']: - print(f'Decoded data: { hex_to_utf8(payload["data"]) }') + payload = block.payload + + if payload and 'data' in payload and payload['data']: + print(f'Decoded data: { hex_to_utf8(payload["data"]) }') +else: + raise ValueError("block must be an instance of BasicBlock") diff --git a/bindings/python/examples/client/submit_and_read_block.py b/bindings/python/examples/client/submit_and_read_block.py index fde7768396..e5211702e7 100644 --- a/bindings/python/examples/client/submit_and_read_block.py +++ b/bindings/python/examples/client/submit_and_read_block.py @@ -11,7 +11,7 @@ # Make sure you have first installed it with `pip install iota_sdk` import os from dotenv import load_dotenv -from iota_sdk import Client, hex_to_utf8, utf8_to_hex, TaggedDataPayload +from iota_sdk import BasicBlock, Client, hex_to_utf8, utf8_to_hex, TaggedDataPayload load_dotenv() @@ -82,15 +82,18 @@ metadata = client.get_block_metadata(block_id) # Get the whole block -block = client.get_block_data(block_id) -payload_out = block.payload -tag_hex_out = block.payload.tag -message_hex_out = block.payload.data - -# Unpackage the payload (from hex to text) -message_out = hex_to_utf8(message_hex_out) -print('\nYour message, read from the Shimmer network:') -print(f' {message_out}') +block = client.get_block(block_id).block +if isinstance(block, BasicBlock): + payload_out = block.payload + tag_hex_out = block.payload.tag + message_hex_out = block.payload.data + + # Unpackage the payload (from hex to text) + message_out = hex_to_utf8(message_hex_out) + print('\nYour message, read from the Shimmer network:') + print(f' {message_out}') +else: + raise ValueError("block must be an instance of BasicBlock") # Or see the message online, with the testnet explorer. print( diff --git a/bindings/python/iota_sdk/__init__.py b/bindings/python/iota_sdk/__init__.py index d77785ee3f..ffcd2c2305 100644 --- a/bindings/python/iota_sdk/__init__.py +++ b/bindings/python/iota_sdk/__init__.py @@ -12,7 +12,11 @@ from .prefix_hex import * from .types.address import * from .types.balance import * -from .types.block import * +from .types.block.basic import * +from .types.block.block import * +from .types.block.metadata import * +from .types.block.wrapper import * +from .types.block.validation import * from .types.block_builder_options import * from .types.burn import * from .types.client_options import * diff --git a/bindings/python/iota_sdk/client/_high_level_api.py b/bindings/python/iota_sdk/client/_high_level_api.py index 08dd84cdcc..f7947d4676 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 import Block +from iota_sdk.types.block.wrapper import BlockWrapper 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[Block]: + def find_blocks(self, block_ids: List[HexStr]) -> List[BlockWrapper]: """Find all blocks by provided block IDs. Args: @@ -106,7 +106,7 @@ def find_blocks(self, block_ids: List[HexStr]) -> List[Block]: blocks = self._call_method('findBlocks', { 'blockIds': block_ids }) - return [Block.from_dict(block) for block in blocks] + return [BlockWrapper.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 3db17d052d..43b93216df 100644 --- a/bindings/python/iota_sdk/client/_node_core_api.py +++ b/bindings/python/iota_sdk/client/_node_core_api.py @@ -5,7 +5,8 @@ from abc import ABCMeta, abstractmethod from dacite import from_dict -from iota_sdk.types.block import Block, BlockMetadata +from iota_sdk.types.block.wrapper import BlockWrapper +from iota_sdk.types.block.metadata import BlockMetadata from iota_sdk.types.common import HexStr from iota_sdk.types.node_info import NodeInfo, NodeInfoWrapper from iota_sdk.types.output_metadata import OutputWithMetadata, OutputMetadata @@ -57,7 +58,7 @@ def get_tips(self) -> List[HexStr]: """ return self._call_method('getTips') - def post_block(self, block: Block) -> HexStr: + def post_block(self, block: BlockWrapper) -> HexStr: """Post a block. Args: @@ -70,10 +71,10 @@ def post_block(self, block: Block) -> HexStr: 'block': block.__dict__ }) - def get_block_data(self, block_id: HexStr) -> Block: + def get_block(self, block_id: HexStr) -> BlockWrapper: """Get the block corresponding to the given block id. """ - return Block.from_dict(self._call_method('getBlock', { + return BlockWrapper.from_dict(self._call_method('getBlock', { 'blockId': block_id })) @@ -127,13 +128,13 @@ def get_output_metadata( 'outputId': output_id_str })) - def get_included_block(self, transaction_id: HexStr) -> Block: + def get_included_block(self, transaction_id: HexStr) -> BlockWrapper: """Returns the included block of the given transaction. Returns: The included block. """ - return Block.from_dict(self._call_method('getIncludedBlock', { + return BlockWrapper.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 2d501d06e2..d7d1fd55c4 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 import Block +from iota_sdk.types.block.wrapper import BlockWrapper from iota_sdk.types.common import HexStr, Node from iota_sdk.types.feature import Feature from iota_sdk.types.native_token import NativeToken @@ -394,7 +394,8 @@ def sign_transaction( 'preparedTransactionData': prepared_transaction_data })) - def submit_payload(self, payload: Payload) -> List[Union[HexStr, Block]]: + def submit_payload( + self, payload: Payload) -> List[Union[HexStr, BlockWrapper]]: """Submit a payload in a block. Args: @@ -406,7 +407,7 @@ def submit_payload(self, payload: Payload) -> List[Union[HexStr, Block]]: result = self._call_method('postBlockPayload', { 'payload': payload.to_dict() }) - result[1] = Block.from_dict(result[1]) + result[1] = BlockWrapper.from_dict(result[1]) return result def listen_mqtt(self, topics: List[str], handler): diff --git a/bindings/python/iota_sdk/types/block/basic.py b/bindings/python/iota_sdk/types/block/basic.py new file mode 100644 index 0000000000..ee4b56b9f7 --- /dev/null +++ b/bindings/python/iota_sdk/types/block/basic.py @@ -0,0 +1,32 @@ +# Copyright 2023 IOTA Stiftung +# SPDX-License-Identifier: Apache-2.0 + +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.common import HexStr, json +from iota_sdk.types.payload import PayloadUnion + + +@json +@dataclass +class BasicBlock(Block): + """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. + + Attributes: + strong_parents: Blocks that are strongly directly approved. + weak_parents: Blocks that are weakly directly approved. + shallow_like_parents: Blocks that are directly referenced to adjust opinion. + max_burned_mana: The amount of Mana the Account identified by the IssuerId is at most willing to burn for this block. + payload: The optional payload of this block. + """ + strong_parents: List[HexStr] + weak_parents: List[HexStr] + shallow_like_parents: List[HexStr] + max_burned_mana: str + payload: Optional[PayloadUnion] = 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 new file mode 100644 index 0000000000..026f8d4b5e --- /dev/null +++ b/bindings/python/iota_sdk/types/block/block.py @@ -0,0 +1,26 @@ +# Copyright 2023 IOTA Stiftung +# SPDX-License-Identifier: Apache-2.0 + +from __future__ import annotations +from enum import IntEnum +from dataclasses import dataclass +from iota_sdk.types.common import json + + +class BlockType(IntEnum): + """Block types. + + Attributes: + Basic (0): A Basic Block. + Validation (1): A Validation Block. + """ + Basic = 0 + Validation = 1 + + +@json +@dataclass +class Block: + """Base class for blocks. + """ + type: int diff --git a/bindings/python/iota_sdk/types/block.py b/bindings/python/iota_sdk/types/block/metadata.py similarity index 60% rename from bindings/python/iota_sdk/types/block.py rename to bindings/python/iota_sdk/types/block/metadata.py index 6e26a1e9b9..22b8b4b539 100644 --- a/bindings/python/iota_sdk/types/block.py +++ b/bindings/python/iota_sdk/types/block/metadata.py @@ -2,66 +2,82 @@ # SPDX-License-Identifier: Apache-2.0 from __future__ import annotations -from enum import Enum +from enum import Enum, IntEnum from dataclasses import dataclass -from typing import List, Optional, Union, Dict -from dacite import from_dict +from typing import Optional from iota_sdk.types.common import HexStr, json -from iota_sdk.types.payload import TaggedDataPayload, TransactionPayload -from iota_sdk.utils import Utils @json @dataclass -class Block: - """Represent the object that nodes gossip around the network. +class BlockMetadata: + """Represents the metadata of a block. + Response of GET /api/core/v3/blocks/{blockId}/metadata. Attributes: - protocol_version: The protocol version with which this block was issued. - strong_parents: Blocks that are strongly directly approved. - weak_parents: Blocks that are weakly directly approved. - shallow_like_parents: Blocks that are directly referenced to adjust opinion. - max_burned_mana: The amount of Mana the Account identified by the IssuerId is at most willing to burn for this block. - payload: The optional payload of this block. + block_state: The block state. + tx_state: The transaction state. + block_failure_reason: The block failure reason. + tx_failure_reason: The transaction failure reason. """ + block_id: HexStr + # TODO: verify if really optional: + # https://github.com/iotaledger/tips-draft/pull/24/files#r1293426314 + block_state: Optional[BlockState] = None + tx_state: Optional[TransactionState] = None + block_failure_reason: Optional[BlockFailureReason] = None + tx_failure_reason: Optional[TransactionFailureReason] = None - protocol_version: int - strong_parents: List[HexStr] - weak_parents: List[HexStr] - shallow_like_parents: List[HexStr] - max_burned_mana: str - payload: Optional[Union[TaggedDataPayload, - TransactionPayload]] = None - @classmethod - def from_dict(cls, block_dict: Dict) -> Block: - """ - The function `from_dict` takes a dictionary that contains the data needed to - create an instance of the `Block` class. +class BlockState(Enum): + """Describes the state of a block. + + Attributes: + Pending: Stored but not confirmed. + Confirmed: Confirmed with the first level of knowledge. + Finalized: Included and can no longer be reverted. + Rejected: Rejected by the node, and user should reissue payload if it contains one. + Failed: Not successfully issued due to failure reason. + """ + Pending = 0 + Confirmed = 1 + Finalized = 2 + Rejected = 3 + Failed = 4 - Returns: - An instance of the `Block` class. - """ - return from_dict(Block, block_dict) +class TransactionState(Enum): + """Describes the state of a transaction. - def id(self) -> HexStr: - """Rreturns the block ID as a hexadecimal string. - """ - return Utils.block_id(self) + Attributes: + Pending: Stored but not confirmed. + Confirmed: Confirmed with the first level of knowledge. + Finalized: Included and can no longer be reverted. + Failed: The block is not successfully issued due to failure reason. + """ + Pending = 0 + Confirmed = 1 + Finalized = 2 + Failed = 3 -class LedgerInclusionState(str, Enum): - """Represents whether a block is included in the ledger. +class BlockFailureReason(IntEnum): + """Describes the reason of a block failure. Attributes: - noTransaction: The block does not contain a transaction. - included: The block contains an included transaction. - conflicting: The block contains a conflicting transaction. + TooOldToIssue (1): The block is too old to issue. + ParentTooOld (2): One of the block's parents is too old. + ParentDoesNotExist (3): One of the block's parents does not exist. + ParentInvalid (4): One of the block's parents is invalid. + DroppedDueToCongestion (5): The block is dropped due to congestion. + Invalid (6): The block is invalid. """ - noTransaction = 'noTransaction' - included = 'included' - conflicting = 'conflicting' + TooOldToIssue = 1 + ParentTooOld = 2 + ParentDoesNotExist = 3 + ParentInvalid = 4 + DroppedDueToCongestion = 5 + Invalid = 6 class TransactionFailureReason(Enum): @@ -139,34 +155,3 @@ def __str__(self): 21: "Failed to claim delegation reward.", 255: "The semantic validation failed for a reason not covered by the previous variants." }[self.value] - - -@json -@dataclass -class BlockMetadata: - """Block Metadata. - - Attributes: - block_id: The id of the block. - strong_parents: Blocks that are strongly directly approved. - weak_parents: Blocks that are weakly directly approved. - shallow_like_parents: Blocks that are directly referenced to adjust opinion. - is_solid: Whether the block is solid. - referenced_by_milestone_index: The milestone index referencing the block. - milestone_index: The milestone index if the block contains a milestone payload. - ledger_inclusion_state: The ledger inclusion state of the block. - conflict_reason: The optional conflict reason of the block. - should_promote: Whether the block should be promoted. - should_reattach: Whether the block should be reattached. - """ - block_id: HexStr - strong_parents: List[HexStr] - weak_parents: List[HexStr] - shallow_like_parents: List[HexStr] - is_solid: bool - referenced_by_milestone_index: Optional[int] = None - milestone_index: Optional[int] = None - ledger_inclusion_state: Optional[LedgerInclusionState] = None - conflict_reason: Optional[TransactionFailureReason] = None - should_promote: Optional[bool] = None - should_reattach: Optional[bool] = None diff --git a/bindings/python/iota_sdk/types/block/validation.py b/bindings/python/iota_sdk/types/block/validation.py new file mode 100644 index 0000000000..2bcaaf2232 --- /dev/null +++ b/bindings/python/iota_sdk/types/block/validation.py @@ -0,0 +1,32 @@ +# Copyright 2023 IOTA Stiftung +# SPDX-License-Identifier: Apache-2.0 + +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.common import HexStr, json + + +@json +@dataclass +class ValidationBlock(Block): + """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. + + Attributes: + strong_parents: Blocks that are strongly directly approved. + weak_parents: Blocks that are weakly directly approved. + shallow_like_parents: Blocks that are directly referenced to adjust opinion. + highest_supported_version: The highest supported protocol version the issuer of this block supports. + protocol_parameters_hash: The hash of the protocol parameters for the Highest Supported Version. + """ + strong_parents: List[HexStr] + weak_parents: List[HexStr] + shallow_like_parents: List[HexStr] + highest_supported_version: int + protocol_parameters_hash: HexStr + type: int = field( + default_factory=lambda: BlockType.Validation, + init=False) diff --git a/bindings/python/iota_sdk/types/block/wrapper.py b/bindings/python/iota_sdk/types/block/wrapper.py new file mode 100644 index 0000000000..c1ebf2db80 --- /dev/null +++ b/bindings/python/iota_sdk/types/block/wrapper.py @@ -0,0 +1,45 @@ +# Copyright 2023 IOTA Stiftung +# SPDX-License-Identifier: Apache-2.0 + +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.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] + + +@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. + + 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`. + signature: The Block signature. + """ + protocol_version: int + network_id: str + issuing_time: str + slot_commitment_id: HexStr + latest_finalized_slot: SlotIndex + issuer_id: HexStr + block: BlockUnion + signature: SignatureUnion + + def id(self, params: ProtocolParameters) -> HexStr: + """Returns the block ID as a hexadecimal string. + """ + return Utils.block_id(self, params) diff --git a/bindings/python/iota_sdk/types/signature.py b/bindings/python/iota_sdk/types/signature.py index cb0b6f6031..9dbc96e2fe 100644 --- a/bindings/python/iota_sdk/types/signature.py +++ b/bindings/python/iota_sdk/types/signature.py @@ -1,6 +1,7 @@ # Copyright 2023 IOTA Stiftung # SPDX-License-Identifier: Apache-2.0 +from typing import TypeAlias, Union from dataclasses import dataclass, field from iota_sdk.types.common import HexStr, CoinType, json @@ -28,6 +29,9 @@ class Ed25519Signature(Signature): type: int = field(default_factory=lambda: 0, init=False) +SignatureUnion: TypeAlias = Union[Ed25519Signature] + + @json @dataclass class Bip44(): diff --git a/bindings/python/iota_sdk/types/unlock.py b/bindings/python/iota_sdk/types/unlock.py index 82e71e486e..2851b9085b 100644 --- a/bindings/python/iota_sdk/types/unlock.py +++ b/bindings/python/iota_sdk/types/unlock.py @@ -77,7 +77,8 @@ class NftUnlock: type: int = field(default_factory=lambda: int(UnlockType.Nft), init=False) -def deserialize_unlock(d: Dict[str, Any]) -> Union[SignatureUnlock, ReferenceUnlock, AccountUnlock, NftUnlock]: +def deserialize_unlock(d: Dict[str, Any]) -> Union[SignatureUnlock, + ReferenceUnlock, AccountUnlock, NftUnlock]: """ Takes a dictionary as input and returns an instance of a specific class based on the value of the 'type' key in the dictionary. diff --git a/bindings/python/iota_sdk/types/unlock_condition.py b/bindings/python/iota_sdk/types/unlock_condition.py index e13f118516..6676f9681b 100644 --- a/bindings/python/iota_sdk/types/unlock_condition.py +++ b/bindings/python/iota_sdk/types/unlock_condition.py @@ -179,7 +179,8 @@ def deserialize_unlock_condition(d: Dict[str, Any]) -> UnlockConditionUnion: raise Exception(f'invalid unlock condition type: {uc_type}') -def deserialize_unlock_conditions(dicts: List[Dict[str, Any]]) -> List[UnlockConditionUnion]: +def deserialize_unlock_conditions( + dicts: List[Dict[str, Any]]) -> List[UnlockConditionUnion]: """ 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 1eef9756a0..86929441fd 100644 --- a/bindings/python/iota_sdk/utils.py +++ b/bindings/python/iota_sdk/utils.py @@ -9,13 +9,15 @@ from iota_sdk.types.signature import Ed25519Signature from iota_sdk.types.address import Address, AddressType, Ed25519Address, AccountAddress, NFTAddress from iota_sdk.types.common import HexStr +from iota_sdk.types.essence import TransactionEssence +from iota_sdk.types.node_info import ProtocolParameters from iota_sdk.types.output_id import OutputId from iota_sdk.types.output import Output from iota_sdk.external import call_utils_method # Required to prevent circular import if TYPE_CHECKING: - from iota_sdk.types.block import Block + from iota_sdk.types.block.wrapper import BlockWrapper class Utils(): @@ -172,19 +174,20 @@ def compute_token_id(account_id: HexStr, serial_number: int, }) @staticmethod - def block_id(block: Block) -> HexStr: + def block_id(block: BlockWrapper, params: ProtocolParameters) -> HexStr: """ Return a block ID (Blake2b256 hash of block bytes) from a block. """ return _call_method('blockId', { - 'block': block.to_dict() + 'block': block.to_dict(), + 'protocol_parameters': params.to_dict(), }) @staticmethod - def hash_transaction_essence(essence) -> HexStr: + def hash_transaction_essence(essence: TransactionEssence) -> HexStr: """ Compute the hash of a transaction essence. """ return _call_method('hashTransactionEssence', { - 'essence': essence + 'essence': essence.to_dict(), }) @staticmethod diff --git a/bindings/python/tests/address_generation_test.py b/bindings/python/tests/address_generation_test.py index d7037dc94e..616f50e0a9 100644 --- a/bindings/python/tests/address_generation_test.py +++ b/bindings/python/tests/address_generation_test.py @@ -1,11 +1,12 @@ - # Copyright 2023 IOTA Stiftung # SPDX-License-Identifier: Apache-2.0 from iota_sdk import Wallet, MnemonicSecretManager, CoinType, ClientOptions +import pytest import shutil +@pytest.mark.skip(reason="https://github.com/iotaledger/iota-sdk/issues/1387") def test_address_generation_iota(): db_path = './test_address_generation_iota' shutil.rmtree(db_path, ignore_errors=True) @@ -27,6 +28,7 @@ def test_address_generation_iota(): shutil.rmtree(db_path, ignore_errors=True) +@pytest.mark.skip(reason="https://github.com/iotaledger/iota-sdk/issues/1387") def test_address_generation_shimmer(): db_path = './test_address_generation_shimmer' shutil.rmtree(db_path, ignore_errors=True) diff --git a/bindings/python/tests/test_block.py b/bindings/python/tests/test_block.py index d59654dcd5..ad9f651e5f 100644 --- a/bindings/python/tests/test_block.py +++ b/bindings/python/tests/test_block.py @@ -1,48 +1,116 @@ # Copyright 2023 IOTA Stiftung # SPDX-License-Identifier: Apache-2.0 -from iota_sdk import Block, Payload, PayloadType +from iota_sdk import BasicBlock, BlockType, BlockWrapper, Payload, PayloadType +import pytest -def test_block(): - # with tx payload - block_dict = {"protocolVersion": 2, - "strong_parents": ["0x27532565d4c8cc886dfc6a2238e8d2a72369672bb1d1d762c33b72d41b0b07b8", - "0x604e6996bd1ec110642fec5b9c980d4b126eba5683e80a6e2cb905ded0cebd98", - "0x6a14368f99e875aee0e7078d9e2ec2ba6c4fff6a3cd63c73a9b2c296d4a8e697", - "0xc3f20eb06ce8be091579e2fbe6c109d108983fb0eff2c768e98c61e6fe71b4b7"], - "weak_parents": [], - "shallow_like_parents": [], - "payload": {"type": 6, - "essence": {"type": 1, - "networkId": "1856588631910923207", - "inputs": [{"type": 0, - "transactionId": "0xc6765035e75e319e9cd55ab16e7619f6cd658e7f421c71d9fe276c77fdf3f5b3", - "transactionOutputIndex": 1}], - "inputsCommitment": "0x2468f946993ac949c890d7f895797c6b86075dc1e1556f04f3772903eaf51932", - "outputs": [{"type": 3, - "amount": "1000000", +def test_basic_block_with_tagged_data_payload(): + block_dict = { + "type": 0, + "strongParents": [ + "0x17c297a273facf4047e244a65eb34ee33b1f1698e1fff28679466fa2ad81c0e8", + "0x9858e80fa0b37b6d9397e23d1f58ce53955a9be1aa8020c0d0e11672996c6db9"], + "weakParents": [], + "shallowLikeParents": [], + "maxBurnedMana": "180500", + "payload": { + "type": 5, + "tag": "0x484f524e4554205370616d6d6572", + "data": "0x57652061726520616c6c206d616465206f662073746172647573742e0a436f756e743a20353436333730330a54696d657374616d703a20323032332d30372d31395430373a32323a32385a0a54697073656c656374696f6e3a20343732c2b573"}} + block = BasicBlock.from_dict(block_dict) + assert block.to_dict() == block_dict + assert isinstance(block.payload, Payload) + assert block.payload.type == PayloadType.TaggedData + + +def test_block_wrapper_with_tagged_data_payload(): + block_dict = { + "protocolVersion": 3, + "networkId": "10549460113735494767", + "issuingTime": "1675563954966263210", + "slotCommitmentId": "0x498bf08a5ed287bc87340341ffab28706768cd3a7035ae5e33932d9a12bb30940000000000000000", + "latestFinalizedSlot": 21, + "issuerId": "0x3370746f30705b7d0b42597459714d45241e5a64761b09627c447b751c7e145c", + "block": { + "type": 0, + "strongParents": [ + "0x304442486c7a05361408585e4b5f7a67441c437528755a70041e0e557a6d4b2d7d4362083d492b57", + "0x5f736978340a243d381b343b160b316a6b7d4b1e3c0355492e2e72113c2b126600157e69113c0b5c" + ], + "weakParents": [ + "0x0b5a48384f382f4a49471c4860683c6f0a0d446f012e1b117c4e405f5e24497c72691f43535c0b42" + ], + "shallowLikeParents": [ + "0x163007217803006078040b0f51507d3572355a457839095e572f125500401b7d220c772b56165a12" + ], + "maxBurnedMana": "180500", + "payload": { + "type": 5, + "tag": "0x68656c6c6f20776f726c64", + "data": "0x01020304" + } + }, + "signature": { + "type": 0, + "publicKey": "0x024b6f086177156350111d5e56227242034e596b7e3d0901180873740723193c", + "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, Payload) + assert block_wrapper.block.payload.type == PayloadType.TaggedData + # TODO: determine the actual hash of the block wrapper + # assert block_wrapper.id() == "0x7ce5ad074d4162e57f83cfa01cd2303ef5356567027ce0bcee0c9f57bc11656e" + + +@pytest.mark.skip(reason="https://github.com/iotaledger/iota-sdk/issues/1387") +def test_basic_block_with_tx_payload(): + block_dict = { + "type": 0, + "strongParents": ["0x27532565d4c8cc886dfc6a2238e8d2a72369672bb1d1d762c33b72d41b0b07b8", + "0x604e6996bd1ec110642fec5b9c980d4b126eba5683e80a6e2cb905ded0cebd98", + "0x6a14368f99e875aee0e7078d9e2ec2ba6c4fff6a3cd63c73a9b2c296d4a8e697", + "0xc3f20eb06ce8be091579e2fbe6c109d108983fb0eff2c768e98c61e6fe71b4b7"], + "weakParents": [], + "shallowLikeParents": [], + "maxBurnedMana": "180500", + "payload": {"type": 6, + "essence": {"type": 1, + "networkId": "1856588631910923207", + "inputs": [{"type": 0, + "transactionId": "0xc6765035e75e319e9cd55ab16e7619f6cd658e7f421c71d9fe276c77fdf3f5b3", + "transactionOutputIndex": 1}], + "inputsCommitment": "0x2468f946993ac949c890d7f895797c6b86075dc1e1556f04f3772903eaf51932", + "outputs": [{"type": 3, + "amount": "1000000", "unlockConditions": [{"type": 0, "address": {"type": 0, "pubKeyHash": "0xa119005b26d46fc74cf9188b3cef8d01623e68146741ee698cabefd425dc01be"}}]}, - {"type": 3, - "amount": "995000000", + {"type": 3, + "amount": "995000000", "unlockConditions": [{"type": 0, "address": {"type": 0, "pubKeyHash": "0xa119005b26d46fc74cf9188b3cef8d01623e68146741ee698cabefd425dc01be"}}]}]}, - "unlocks": [{"type": 0, - "signature": {"type": 0, - "publicKey": "0xa7af600976f440ec97d7bddbf17eacf0bfbf710e8cfb4ae3eae475d4ae8e1b16", - "signature": "0x6bbe2eed95300a3d707af1bb17e04f83087fe31261256020fd00c24a54543c084079bed29c6d1479ee5acfd1e2fa32316e88c4c1577b4fbea3fe247f71114500"}}]}} - block = Block.from_dict(block_dict) + "unlocks": [{"type": 0, + "signature": {"type": 0, + "publicKey": "0xa7af600976f440ec97d7bddbf17eacf0bfbf710e8cfb4ae3eae475d4ae8e1b16", + "signature": "0x6bbe2eed95300a3d707af1bb17e04f83087fe31261256020fd00c24a54543c084079bed29c6d1479ee5acfd1e2fa32316e88c4c1577b4fbea3fe247f71114500"}}]}} + block = BasicBlock.from_dict(block_dict) assert block.to_dict() == block_dict assert isinstance(block.payload, Payload) assert block.payload.type == PayloadType.Transaction - # with tx payload, all output types + +@pytest.mark.skip(reason="https://github.com/iotaledger/iota-sdk/issues/1387") +def test_basic_block_with_tx_payload_all_output_types(): block_dict = { - "protocolVersion": 2, "strong_parents": [ - "0x053296e7434e8a4d602f8db30a5aaf16c01140212fe79d8132137cda1c38a60a", "0x559ec1d9a31c55bd27588ada2ade70fb5b13764ddd600e29c3b018761ba30e15", "0xe78e8cdbbeda89e3408eed51b77e0db5ba035f5f3bf79a8365435bba40697693", "0xee9d6e45dbc080694e6c827fecbc31ad9f654cf57404bc98f4cbca033f8e3139"], "weak_parents": [], "shallow_like_parents": [], "payload": { + "type": 0, + "strongParents": [ + "0x053296e7434e8a4d602f8db30a5aaf16c01140212fe79d8132137cda1c38a60a", "0x559ec1d9a31c55bd27588ada2ade70fb5b13764ddd600e29c3b018761ba30e15", "0xe78e8cdbbeda89e3408eed51b77e0db5ba035f5f3bf79a8365435bba40697693", "0xee9d6e45dbc080694e6c827fecbc31ad9f654cf57404bc98f4cbca033f8e3139"], "weakParents": [], "shallowLikeParents": [], "payload": { "type": 6, "essence": { "type": 1, "networkId": "1856588631910923207", "inputs": [ { @@ -172,66 +240,53 @@ def test_block(): "type": 1, "reference": 0}, { "type": 2, "reference": 1}, { "type": 1, "reference": 0}]}} - block = Block.from_dict(block_dict) + block = BasicBlock.from_dict(block_dict) assert block.to_dict() == block_dict assert isinstance(block.payload, Payload) assert block.payload.type == PayloadType.Transaction - # with tx payload that has a tagged data payload - block_dict = {"protocolVersion": 2, - "strong_parents": ["0x4bbba1f1fbfa58d8e65c018d0518da1c3ab57f05ffdd9c2e20565a99b42948df", - "0x9962a18f0161f6b883cb1e36b936684793867d97dc9ac226a929d8e434385e96", - "0xe532853c4a1e03e00a37c78a42afebf3570b1bb4a756c5ad651c0f0377548348", - "0xedbd8bd428bcff342de0656e368a881022dd353b51f272ed40c604c86915d97d"], - "weak_parents": [], - "shallow_like_parents": [], - "payload": {"type": 6, - "essence": {"type": 1, - "networkId": "1856588631910923207", - "inputs": [{"type": 0, - "transactionId": "0xeccfbdb73c0a4c9c0301b53a17e5aa301fbf0b079db9e88ff0e32e9e64214b28", - "transactionOutputIndex": 5}, - {"type": 0, - "transactionId": "0xf8052938858750c9c69b92b615a685fa2bb5833912b264142fc724e9510b0d0e", - "transactionOutputIndex": 0}], - "inputsCommitment": "0x9702f2a625db14db2f67289828a9fdbe342477393572b9165b19964b2449061a", - "outputs": [{"type": 3, - "amount": "1000000", + +@pytest.mark.skip(reason="https://github.com/iotaledger/iota-sdk/issues/1387") +def test_basic_block_with_tx_payload_with_tagged_data_payload(): + block_dict = { + "type": 0, + "strongParents": ["0x4bbba1f1fbfa58d8e65c018d0518da1c3ab57f05ffdd9c2e20565a99b42948df", + "0x9962a18f0161f6b883cb1e36b936684793867d97dc9ac226a929d8e434385e96", + "0xe532853c4a1e03e00a37c78a42afebf3570b1bb4a756c5ad651c0f0377548348", + "0xedbd8bd428bcff342de0656e368a881022dd353b51f272ed40c604c86915d97d"], + "weakParents": [], + "shallowLikeParents": [], + "maxBurnedMana": "180500", + "payload": {"type": 6, + "essence": {"type": 1, + "networkId": "1856588631910923207", + "inputs": [{"type": 0, + "transactionId": "0xeccfbdb73c0a4c9c0301b53a17e5aa301fbf0b079db9e88ff0e32e9e64214b28", + "transactionOutputIndex": 5}, + {"type": 0, + "transactionId": "0xf8052938858750c9c69b92b615a685fa2bb5833912b264142fc724e9510b0d0e", + "transactionOutputIndex": 0}], + "inputsCommitment": "0x9702f2a625db14db2f67289828a9fdbe342477393572b9165b19964b2449061a", + "outputs": [{"type": 3, + "amount": "1000000", "unlockConditions": [{"type": 0, "address": {"type": 0, "pubKeyHash": "0x60200bad8137a704216e84f8f9acfe65b972d9f4155becb4815282b03cef99fe"}}]}, - {"type": 3, - "amount": "50600", + {"type": 3, + "amount": "50600", "unlockConditions": [{"type": 0, "address": {"type": 0, "pubKeyHash": "0x74e8b1f10396eb5e8aeb16d666416802722436a88b5dd1a88e59c170b724c9cc"}}]}], - "payload": {"type": 5, - "tag": "0x746167", - "data": "0x64617461"}}, - "unlocks": [{"type": 0, - "signature": {"type": 0, - "publicKey": "0x67b7fc3f78763c9394fc4fcdb52cf3a973b6e064bdc3defb40a6cb2c880e6f5c", - "signature": "0x30cb012af3402be1b4b2ed18e2aba86839da06ba38ff3277c481e17c003f0199ba26f5613199e0d24035628bb2b69a6ea2a7682e41c30244996baf3a2adc1c00"}}, - {"type": 1, - "reference": 0}]}} - block = Block.from_dict(block_dict) + "payload": {"type": 5, + "tag": "0x746167", + "data": "0x64617461"}}, + "unlocks": [{"type": 0, + "signature": {"type": 0, + "publicKey": "0x67b7fc3f78763c9394fc4fcdb52cf3a973b6e064bdc3defb40a6cb2c880e6f5c", + "signature": "0x30cb012af3402be1b4b2ed18e2aba86839da06ba38ff3277c481e17c003f0199ba26f5613199e0d24035628bb2b69a6ea2a7682e41c30244996baf3a2adc1c00"}}, + {"type": 1, + "reference": 0}]}} + block = BasicBlock.from_dict(block_dict) assert block.to_dict() == block_dict assert isinstance(block.payload, Payload) assert block.payload.type == PayloadType.Transaction - - # with tagged data payload - block_dict = { - "protocolVersion": 2, - "strong_parents": [ - "0x17c297a273facf4047e244a65eb34ee33b1f1698e1fff28679466fa2ad81c0e8", - "0x9858e80fa0b37b6d9397e23d1f58ce53955a9be1aa8020c0d0e11672996c6db9"], - "weak_parents": [], - "shallow_like_parents": [], - "payload": { - "type": 5, - "tag": "0x484f524e4554205370616d6d6572", - "data": "0x57652061726520616c6c206d616465206f662073746172647573742e0a436f756e743a20353436333730330a54696d657374616d703a20323032332d30372d31395430373a32323a32385a0a54697073656c656374696f6e3a20343732c2b573"}} - block = Block.from_dict(block_dict) - assert block.to_dict() == block_dict - assert isinstance(block.payload, Payload) - assert block.payload.type == PayloadType.TaggedData diff --git a/bindings/python/tests/test_offline.py b/bindings/python/tests/test_offline.py index f81ca2f36d..49032355fb 100644 --- a/bindings/python/tests/test_offline.py +++ b/bindings/python/tests/test_offline.py @@ -1,9 +1,9 @@ - # Copyright 2023 IOTA Stiftung # SPDX-License-Identifier: Apache-2.0 -from iota_sdk import Block, Client, MnemonicSecretManager, Utils, SecretManager, OutputId, hex_to_utf8, utf8_to_hex, Bip44, CoinType, Irc27Metadata, Irc30Metadata +from iota_sdk import BasicBlock, Client, MnemonicSecretManager, Utils, SecretManager, OutputId, hex_to_utf8, utf8_to_hex, Bip44, CoinType, Irc27Metadata, Irc30Metadata import json +import pytest import unittest # Read the test vector @@ -32,6 +32,7 @@ def test_mnemonic_address_generation(): assert test['bech32_address'] == generated_address[0] +@pytest.mark.skip(reason="https://github.com/iotaledger/iota-sdk/issues/1387") def test_sign_verify_ed25519(): secret_manager = MnemonicSecretManager( "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast") @@ -97,24 +98,6 @@ def test_hex_utf8(): assert hex_to_utf8(hex_data) == utf8_data -def test_block(): - block_dict = { - "protocolVersion": 2, - "strong_parents": [ - "0x28dbf8f5005c0de388cbbf23d14645a579fc0cb8278ad9cdc5a4252c7e8f0ed3", - "0x440dbc33bf05c334c6d49f06514526d7f3e3c758028a2e87636e19f886290900", - "0xd76cdb7acf228ecdad590a42b91acc077c1518c1a271411229e33e050fc19b44", - "0xecef38d3af7e63da78a5e70128efe371f2191088b31879f7b0e81da657fa21c6"], - "weak_parents": [], - "shallow_like_parents": [], - "payload": { - "type": 5, - "tag": "0x68656c6c6f", - "data": "0x68656c6c6f"}} - block = Block.from_dict(block_dict) - assert block.id() == "0x7ce5ad074d4162e57f83cfa01cd2303ef5356567027ce0bcee0c9f57bc11656e" - - def test_irc_27(): metadata = Irc27Metadata( "video/mp4", diff --git a/bindings/python/tests/test_output.py b/bindings/python/tests/test_output.py index 76c9f7aee1..2ec6918444 100644 --- a/bindings/python/tests/test_output.py +++ b/bindings/python/tests/test_output.py @@ -1,4 +1,3 @@ - # Copyright 2023 IOTA Stiftung # SPDX-License-Identifier: Apache-2.0 diff --git a/bindings/python/tests/test_wallet_destroy.py b/bindings/python/tests/test_wallet_destroy.py index 132b491602..cbb91575f8 100644 --- a/bindings/python/tests/test_wallet_destroy.py +++ b/bindings/python/tests/test_wallet_destroy.py @@ -2,11 +2,13 @@ # SPDX-License-Identifier: Apache-2.0 from iota_sdk import Wallet, MnemonicSecretManager, CoinType, ClientOptions, WalletError +import pytest import shutil import unittest class WalletDestroy(unittest.TestCase): + @pytest.mark.skip(reason="https://github.com/iotaledger/iota-sdk/issues/1387") def test_wallet_destroy(self): db_path = './test_wallet_destroy' shutil.rmtree(db_path, ignore_errors=True)