diff --git a/.gitignore b/.gitignore index c14a0292..8897c7b3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,6 @@ coverage.xml # IDE .idea .code +.venv /integration-test/.env /integration-test/tmp_configs/* diff --git a/poetry.lock b/poetry.lock index 29c781dd..a2d36a52 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -171,55 +171,24 @@ requests = ">=2.28.0,<3.0.0" [[package]] name = "cbor2" -version = "5.6.4" +version = "0.1.dev432" description = "CBOR (de)serializer with extensive tag support" optional = false python-versions = ">=3.8" -files = [ - {file = "cbor2-5.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c40c68779a363f47a11ded7b189ba16767391d5eae27fac289e7f62b730ae1fc"}, - {file = "cbor2-5.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0625c8d3c487e509458459de99bf052f62eb5d773cc9fc141c6a6ea9367726d"}, - {file = "cbor2-5.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de7137622204168c3a57882f15dd09b5135bda2bcb1cf8b56b58d26b5150dfca"}, - {file = "cbor2-5.6.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3545e1e62ec48944b81da2c0e0a736ca98b9e4653c2365cae2f10ae871e9113"}, - {file = "cbor2-5.6.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d6749913cd00a24eba17406a0bfc872044036c30a37eb2fcde7acfd975317e8a"}, - {file = "cbor2-5.6.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:57db966ab08443ee54b6f154f72021a41bfecd4ba897fe108728183ad8784a2a"}, - {file = "cbor2-5.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:380e0c7f4db574dcd86e6eee1b0041863b0aae7efd449d49b0b784cf9a481b9b"}, - {file = "cbor2-5.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5c763d50a1714e0356b90ad39194fc8ef319356b89fb001667a2e836bfde88e3"}, - {file = "cbor2-5.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:58a7ac8861857a9f9b0de320a4808a2a5f68a2599b4c14863e2748d5a4686c99"}, - {file = "cbor2-5.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d715b2f101730335e84a25fe0893e2b6adf049d6d44da123bf243b8c875ffd8"}, - {file = "cbor2-5.6.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f53a67600038cb9668720b309fdfafa8c16d1a02570b96d2144d58d66774318"}, - {file = "cbor2-5.6.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f898bab20c4f42dca3688c673ff97c2f719b1811090430173c94452603fbcf13"}, - {file = "cbor2-5.6.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5e5d50fb9f47d295c1b7f55592111350424283aff4cc88766c656aad0300f11f"}, - {file = "cbor2-5.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:7f9d867dcd814ab8383ad132eb4063e2b69f6a9f688797b7a8ca34a4eadb3944"}, - {file = "cbor2-5.6.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e0860ca88edf8aaec5461ce0e498eb5318f1bcc70d93f90091b7a1f1d351a167"}, - {file = "cbor2-5.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c38a0ed495a63a8bef6400158746a9cb03c36f89aeed699be7ffebf82720bf86"}, - {file = "cbor2-5.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c8d8c2f208c223a61bed48dfd0661694b891e423094ed30bac2ed75032142aa"}, - {file = "cbor2-5.6.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24cd2ce6136e1985da989e5ba572521023a320dcefad5d1fff57fba261de80ca"}, - {file = "cbor2-5.6.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7facce04aed2bf69ef43bdffb725446fe243594c2451921e89cc305bede16f02"}, - {file = "cbor2-5.6.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f9c8ee0d89411e5e039a4f3419befe8b43c0dd8746eedc979e73f4c06fe0ef97"}, - {file = "cbor2-5.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:9b45d554daa540e2f29f1747df9f08f8d98ade65a67b1911791bc193d33a5923"}, - {file = "cbor2-5.6.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0a5cb2c16687ccd76b38cfbfdb34468ab7d5635fb92c9dc5e07831c1816bd0a9"}, - {file = "cbor2-5.6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6f985f531f7495527153c4f66c8c143e4cf8a658ec9e87b14bc5438e0a8d0911"}, - {file = "cbor2-5.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9d9c7b4bd7c3ea7e5587d4f1bbe073b81719530ddadb999b184074f064896e2"}, - {file = "cbor2-5.6.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d06184dcdc275c389fee3cd0ea80b5e1769763df15f93ecd0bf4c281817365"}, - {file = "cbor2-5.6.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e9ba7116f201860fb4c3e80ef36be63851ec7e4a18af70fea22d09cab0b000bf"}, - {file = "cbor2-5.6.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:341468ae58bdedaa05c907ab16e90dd0d5c54d7d1e66698dfacdbc16a31e815b"}, - {file = "cbor2-5.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:bcb4994be1afcc81f9167c220645d878b608cae92e19f6706e770f9bc7bbff6c"}, - {file = "cbor2-5.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:41c43abffe217dce70ae51c7086530687670a0995dfc90cc35f32f2cf4d86392"}, - {file = "cbor2-5.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:227a7e68ba378fe53741ed892b5b03fe472b5bd23ef26230a71964accebf50a2"}, - {file = "cbor2-5.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13521b7c9a0551fcc812d36afd03fc554fa4e1b193659bb5d4d521889aa81154"}, - {file = "cbor2-5.6.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4816d290535d20c7b7e2663b76da5b0deb4237b90275c202c26343d8852b8a"}, - {file = "cbor2-5.6.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1e98d370106821335efcc8fbe4136ea26b4747bf29ca0e66512b6c4f6f5cc59f"}, - {file = "cbor2-5.6.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:68743a18e16167ff37654a29321f64f0441801dba68359c82dc48173cc6c87e1"}, - {file = "cbor2-5.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:7ba5e9c6ed17526d266a1116c045c0941f710860c5f2495758df2e0d848c1b6d"}, - {file = "cbor2-5.6.4-py3-none-any.whl", hash = "sha256:fe411c4bf464f5976605103ebcd0f60b893ac3e4c7c8d8bc8f4a0cb456e33c60"}, - {file = "cbor2-5.6.4.tar.gz", hash = "sha256:1c533c50dde86bef1c6950602054a0ffa3c376e8b0e20c7b8f5b108793f6983e"}, -] +files = [] +develop = false [package.extras] benchmarks = ["pytest-benchmark (==4.0.0)"] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.3.0)", "typing-extensions"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.3.0)", "typing_extensions"] test = ["coverage (>=7)", "hypothesis", "pytest"] +[package.source] +type = "git" +url = "https://github.com/theeldermillenial/cbor2" +reference = "feat/local-decoders" +resolved_reference = "1bb3ea77c5a399c9697c15803f3d8ef36fc02371" + [[package]] name = "certifi" version = "2024.8.30" diff --git a/pycardano/backend/kupo.py b/pycardano/backend/kupo.py index 36fa409e..ca3b3438 100644 --- a/pycardano/backend/kupo.py +++ b/pycardano/backend/kupo.py @@ -21,6 +21,7 @@ MultiAsset, TransactionInput, TransactionOutput, + TransactionId, UTxO, Value, ) @@ -197,6 +198,8 @@ def _utxos_kupo(self, address: str) -> List[UTxO]: ) if datum_hash and result.get("datum_type", "inline"): datum = self._get_datum_from_kupo(result["datum_hash"]) + if datum: + datum_hash = None if not result["value"]["assets"]: tx_out = TransactionOutput( @@ -253,3 +256,27 @@ def evaluate_tx_cbor(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits] :class:`TransactionFailedException`: When fails to evaluate the transaction. """ return self._wrapped_backend.evaluate_tx_cbor(cbor) + + def get_metadata_cbor( + self, tx_id: TransactionId, slot: int + ) -> Optional[RawCBOR]: + """Get metadata cbor from Kupo. + + Args: + tx_id (TransactionId): Transaction id for metadata to query. + slot (int): Slot number. + + Returns: + Optional[RawCBOR]: Metadata cbor.""" + if self._kupo_url is None: + raise AssertionError( + "kupo_url object attribute has not been assigned properly." + ) + + kupo_metadata_url = self._kupo_url + f"/metadata/{slot}?transaction_id={tx_id}" + metadata_result = requests.get(kupo_metadata_url).json() + + if metadata_result and metadata_result[0]["transaction_id"] == tx_id: + return RawCBOR(bytes.fromhex(metadata_result[0]["raw"])) + + return None diff --git a/pycardano/backend/ogmios_v6.py b/pycardano/backend/ogmios_v6.py index 304cf24f..af638dc4 100644 --- a/pycardano/backend/ogmios_v6.py +++ b/pycardano/backend/ogmios_v6.py @@ -59,6 +59,7 @@ def __init__( self, host: str = "localhost", port: int = 1337, + path: str = "", secure: bool = False, refetch_chain_tip_interval: Optional[float] = None, utxo_cache_size: int = 10000, @@ -67,6 +68,7 @@ def __init__( ): self.host = host self.port = port + self.path = path self.secure = secure self._network = network self._service_name = "ogmios" @@ -86,26 +88,26 @@ def __init__( self._datum_cache = LRUCache(maxsize=datum_cache_size) def _query_current_era(self) -> OgmiosEra: - with OgmiosClient(self.host, self.port, self.secure) as client: + with OgmiosClient(self.host, self.port, self.path, self.secure) as client: return get_current_era(client) def _query_current_epoch(self) -> int: - with OgmiosClient(self.host, self.port, self.secure) as client: + with OgmiosClient(self.host, self.port, self.path, self.secure) as client: epoch, _ = client.query_epoch.execute() return epoch def _query_chain_tip(self) -> OgmiosTip: - with OgmiosClient(self.host, self.port, self.secure) as client: + with OgmiosClient(self.host, self.port, self.path, self.secure) as client: tip, _ = client.query_network_tip.execute() return tip def _query_utxos_by_address(self, address: Address) -> List[OgmiosUtxo]: - with OgmiosClient(self.host, self.port, self.secure) as client: + with OgmiosClient(self.host, self.port, self.path, self.secure) as client: utxos, _ = client.query_utxo.execute([address]) return utxos def _query_utxos_by_tx_id(self, tx_id: str, index: int) -> List[OgmiosUtxo]: - with OgmiosClient(self.host, self.port, self.secure) as client: + with OgmiosClient(self.host, self.port, self.path, self.secure) as client: utxos, _ = client.query_utxo.execute( [OgmiosTxOutputReference(tx_id, index)] ) @@ -135,7 +137,7 @@ def protocol_param(self) -> ProtocolParameters: return self._protocol_param def _fetch_protocol_param(self) -> ProtocolParameters: - with OgmiosClient(self.host, self.port, self.secure) as client: + with OgmiosClient(self.host, self.port, self.path, self.secure) as client: protocol_parameters, _ = client.query_protocol_parameters.execute() pyc_protocol_params = ProtocolParameters( min_fee_constant=protocol_parameters.min_fee_constant.lovelace, @@ -205,7 +207,7 @@ def genesis_param(self) -> GenesisParameters: return self._genesis_param # type: ignore[return-value] def _fetch_genesis_param(self) -> OgmiosGenesisParameters: - with OgmiosClient(self.host, self.port, self.secure) as client: + with OgmiosClient(self.host, self.port, self.path, self.secure) as client: return OgmiosGenesisParameters(client, self._query_current_era()) @property @@ -311,13 +313,13 @@ def utxo_by_tx_id(self, tx_id: str, index: int) -> Optional[UTxO]: def submit_tx_cbor(self, cbor: Union[bytes, str]): if isinstance(cbor, bytes): cbor = cbor.hex() - with OgmiosClient(self.host, self.port, self.secure) as client: + with OgmiosClient(self.host, self.port, self.path, self.secure) as client: client.submit_transaction.execute(cbor) def evaluate_tx_cbor(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits]: if isinstance(cbor, bytes): cbor = cbor.hex() - with OgmiosClient(self.host, self.port, self.secure) as client: + with OgmiosClient(self.host, self.port, self.path, self.secure) as client: result, _ = client.evaluate_transaction.execute(cbor) result_dict = {} for res in result: diff --git a/pycardano/hash.py b/pycardano/hash.py index e4023b8a..82f2b069 100644 --- a/pycardano/hash.py +++ b/pycardano/hash.py @@ -72,6 +72,9 @@ def __hash__(self): def payload(self) -> bytes: return self._payload + def to_shallow_primitive(self) -> bytes: + return self.payload + def to_primitive(self) -> bytes: return self.payload diff --git a/pycardano/serialization.py b/pycardano/serialization.py index 1b81a210..61009ef4 100644 --- a/pycardano/serialization.py +++ b/pycardano/serialization.py @@ -5,12 +5,14 @@ import re import typing from collections import OrderedDict, UserList, defaultdict +from collections.abc import Sequence from copy import deepcopy from dataclasses import Field, dataclass, fields from datetime import datetime from decimal import Decimal from functools import wraps from inspect import isclass +from io import BytesIO from typing import ( Any, Callable, @@ -24,7 +26,14 @@ get_type_hints, ) -from cbor2 import CBOREncoder, CBORSimpleValue, CBORTag, dumps, loads, undefined +from cbor2 import ( + CBORDecoder, + CBOREncoder, + CBORSimpleValue, + CBORTag, + dumps, +) +from cbor2._types import UndefinedType, break_marker from frozendict import frozendict from frozenlist import FrozenList from pprintpp import pformat @@ -86,6 +95,7 @@ class RawCBOR: Primitive = Union[ bytes, bytearray, + ByteString, str, int, float, @@ -98,6 +108,7 @@ class RawCBOR: dict, defaultdict, OrderedDict, + UndefinedType, datetime, re.Pattern, CBORSimpleValue, @@ -113,6 +124,7 @@ class RawCBOR: PRIMITIVE_TYPES = ( bytes, bytearray, + ByteString, str, int, float, @@ -125,7 +137,7 @@ class RawCBOR: dict, defaultdict, OrderedDict, - type(undefined), + UndefinedType, datetime, re.Pattern, CBORSimpleValue, @@ -169,6 +181,38 @@ def wrapper(cls, value: Primitive): CBORBase = TypeVar("CBORBase", bound="CBORSerializable") +class IndefiniteDecoder(CBORDecoder): + def decode_array(self, subtype: int) -> Sequence[Any]: + # Major tag 4 + length = self._decode_length(subtype, allow_indefinite=True) + if length is None: + # Indefinite length + items: list = [] + if not self._immutable: + self.set_shareable(items) + while True: + value = self._decode() + if value is break_marker: + break + else: + items.append(value) + + return IndefiniteList(items) + else: + return super().decode_array(subtype=subtype) + + major_decoders: dict[int, Callable[[Any, int], Any]] = { + 0: CBORDecoder.decode_uint, + 1: CBORDecoder.decode_negint, + 2: CBORDecoder.decode_bytestring, + 3: CBORDecoder.decode_string, + 4: decode_array, + 5: CBORDecoder.decode_map, + 6: CBORDecoder.decode_semantic, + 7: CBORDecoder.decode_special, + } + + def default_encoder( encoder: CBOREncoder, value: Union[CBORSerializable, IndefiniteList] ): @@ -235,7 +279,7 @@ class CBORSerializable: does not refer to itself, which could cause infinite loops. """ - def to_shallow_primitive(self) -> Primitive: + def to_shallow_primitive(self) -> Union[Primitive, "CBORSerializable"]: """ Convert the instance to a CBOR primitive. If the primitive is a container, e.g. list, dict, the type of its elements could be either a Primitive or a CBORSerializable. @@ -479,9 +523,13 @@ def from_cbor(cls, payload: Union[str, bytes]) -> CBORSerializable: TestParent(3, Test(1, 2)) """ - if type(payload) is str: + if isinstance(payload, str): payload = bytes.fromhex(payload) - value = loads(payload) # type: ignore + + with BytesIO(payload) as fp: + value = IndefiniteDecoder(fp).decode() + + # value = loads(payload) # type: ignore return cls.from_primitive(value) def __repr__(self): @@ -503,6 +551,7 @@ def _restore_dataclass_field( if "object_hook" in f.metadata: return f.metadata["object_hook"](v) + return _restore_typed_primitive(f.type, v) @@ -528,10 +577,14 @@ def _restore_typed_primitive( raise DeserializeException( f"List types need exactly one type argument, but got {t_args}" ) - t = t_args[0] - if not isinstance(v, list): + t_subtype = t_args[0] + if not isinstance(v, (list, IndefiniteList)): raise DeserializeException(f"Expected type list but got {type(v)}") - return IndefiniteList([_restore_typed_primitive(t, w) for w in v]) + v_list = [_restore_typed_primitive(t_subtype, w) for w in v] + if t == IndefiniteList: + return IndefiniteList(v_list) + else: + return v_list elif isclass(t) and t == ByteString: if not isinstance(v, bytes): raise DeserializeException(f"Expected type bytes but got {type(v)}") @@ -657,8 +710,10 @@ def to_shallow_primitive(self) -> Primitive: return primitives @classmethod - @limit_primitive_type(list, tuple) - def from_primitive(cls: Type[ArrayBase], values: Union[list, tuple]) -> ArrayBase: + @limit_primitive_type(list, tuple, IndefiniteList) + def from_primitive( + cls: Type[ArrayBase], values: Union[list, tuple, IndefiniteList] + ) -> ArrayBase: """Restore a primitive value to its original class type. Args: diff --git a/pycardano/transaction.py b/pycardano/transaction.py index 5d5c7c0e..16eb86e0 100644 --- a/pycardano/transaction.py +++ b/pycardano/transaction.py @@ -339,7 +339,7 @@ def from_primitive(cls: Type[_Script], values: List[Primitive]) -> _Script: class _DatumOption(ArrayCBORSerializable): _TYPE: int = field(init=False, default=0) - datum: Union[DatumHash, Any] + datum: Union[DatumHash, Datum] def __post_init__(self): if isinstance(self.datum, DatumHash): @@ -348,7 +348,7 @@ def __post_init__(self): self._TYPE = 1 def to_shallow_primitive(self) -> Primitive: - data: Union[CBORTag, DatumHash] + data: Union[CBORTag, DatumHash, Datum] if self._TYPE == 1: data = CBORTag(24, cbor2.dumps(self.datum, default=default_encoder)) else: @@ -465,9 +465,9 @@ def lovelace(self) -> int: def to_primitive(self) -> Primitive: if self.datum or self.script or self.post_alonzo: datum = ( - _DatumOption(self.datum_hash or self.datum) - if self.datum is not None or self.datum_hash is not None - else None + _DatumOption(self.datum_hash) + if self.datum_hash is not None + else _DatumOption(self.datum) if self.datum is not None else None ) script_ref = ( _ScriptRef(_Script(self.script)) if self.script is not None else None diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index 4ecf99ed..8b9fab6b 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -5,6 +5,7 @@ from typing import Dict, List, Optional, Set, Tuple, Union from pycardano import RedeemerMap +from pycardano import witness from pycardano.address import Address, AddressType from pycardano.backend.base import ChainContext from pycardano.certificate import ( @@ -1317,10 +1318,10 @@ def build( ) raise UTxOSelectionException( f"All UTxO selectors failed.\n" - f"Requested output:\n {requested_amount} \n" - f"Pre-selected inputs:\n {selected_amount} \n" - f"Additional UTxO pool:\n {additional_utxo_pool} \n" - f"Unfulfilled amount:\n {diff}" + f"Requested output:\n {requested_amount} \n" # noqa: E231 + f"Pre-selected inputs:\n {selected_amount} \n" # noqa: E231 + f"Additional UTxO pool:\n {additional_utxo_pool} \n" # noqa: E231 + f"Unfulfilled amount:\n {diff}" # noqa: E231 ) selected_utxos.sort( @@ -1467,7 +1468,7 @@ def _update_execution_units( r.tag is not None ), "Expected tag of redeemer to be set, but found None" tagname = r.tag.name.lower() - key = f"{tagname}:{r.index}" + key = f"{tagname}:{r.index}" # noqa: E231 if ( key not in estimated_execution_units or estimated_execution_units[key] is None diff --git a/pyproject.toml b/pyproject.toml index d7da7a26..0c4335e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ license = "MIT" [tool.poetry.dependencies] python = "^3.8.1" PyNaCl = "^1.5.0" -cbor2 = "^5.4.3" +cbor2 = { git = "https://github.com/theeldermillenial/cbor2", branch = "feat/local-decoders" } typeguard = "^4.3.0" blockfrost-python = "0.6.0" websocket-client = "^1.4.1" @@ -35,7 +35,7 @@ frozendict = "^2.3.8" frozenlist = "^1.3.3" cachetools = "^5.3.0" docker = "^7.1.0" -ogmios = "1.2.1" +ogmios = "^1.1.1" requests = "^2.32.3" websockets = "^13.0" @@ -76,6 +76,4 @@ profile = "black" ignore_missing_imports = true disable_error_code = ["str-bytes-safe"] python_version = 3.8 -exclude = [ - '^pycardano/crypto/bech32.py$', -] +exclude = ['^pycardano/crypto/bech32.py$'] diff --git a/test/pycardano/test_serialization.py b/test/pycardano/test_serialization.py index 890eb16a..deaa6909 100644 --- a/test/pycardano/test_serialization.py +++ b/test/pycardano/test_serialization.py @@ -6,7 +6,7 @@ import pytest import pycardano -from pycardano import Datum, RawPlutusData +from pycardano import Datum, PlutusData, RawPlutusData from pycardano.exception import DeserializeException from pycardano.plutus import PlutusV1Script, PlutusV2Script from pycardano.serialization import ( @@ -210,6 +210,30 @@ class Test1(MapCBORSerializable): check_two_way_cbor(t) +def test_datum_raw_round_trip(): + @dataclass + class TestDatum(PlutusData): + CONSTR_ID = 0 + a: int + b: List[bytes] + + datum = TestDatum(a=1, b=[b"test", b"datum"]) + restored = RawPlutusData.from_cbor(datum.to_cbor()) + assert datum.to_cbor_hex() == restored.to_cbor_hex() + + +def test_datum_round_trip(): + @dataclass + class TestDatum(PlutusData): + CONSTR_ID = 0 + a: int + b: List[bytes] + + datum = TestDatum(a=1, b=[b"test", b"datum"]) + restored = TestDatum.from_cbor(datum.to_cbor()) + assert datum.to_cbor_hex() == restored.to_cbor_hex() + + def test_wrong_primitive_type(): @dataclass class Test1(MapCBORSerializable): diff --git a/test/pycardano/test_transaction.py b/test/pycardano/test_transaction.py index 5ec6f51e..158d6fd6 100644 --- a/test/pycardano/test_transaction.py +++ b/test/pycardano/test_transaction.py @@ -77,6 +77,7 @@ def test_transaction_output_datum_hash_inline_plutus_script(): output = TransactionOutput( addr, 100000000000, datum_hash=datum_hash(datum), script=script ) + print(output.to_cbor_hex()) assert ( output.to_cbor_hex() == "a400581d60f6532850e1bccee9c72a9113ad98bcc5dbb30d2ac960262444f6e5f4011b000000174876" @@ -472,6 +473,23 @@ class TestDatum(PlutusData): assert cbor == TransactionOutput.from_cbor(cbor).to_cbor_hex() +def test_datum_witness(): + @dataclass + class TestDatum(PlutusData): + CONSTR_ID = 0 + a: int + b: bytes + + tx_body = make_transaction_body() + signed_tx = Transaction( + tx_body, + TransactionWitnessSet(vkey_witnesses=[], plutus_data=[TestDatum(1, b"test")]), + ) + restored_tx = Transaction.from_cbor(signed_tx.to_cbor()) + + assert signed_tx.to_cbor_hex() == restored_tx.to_cbor_hex() + + def test_out_of_bound_asset(): a = Asset({AssetName(b"abc"): 1 << 64})