Skip to content

Commit ac9c94a

Browse files
authored
Add some docs on the datum deserialization (#333)
1 parent b19a911 commit ac9c94a

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

docs/source/guides/plutus.rst

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,27 @@ To calculate the hash of a datum, we can leverage the helper class `PlutusData`.
2323

2424
Empty datum::
2525

26-
>>> empty_datum = PlutusData()
27-
>>> empty_datum.to_cbor_hex()
26+
>>> from pycardano import PlutusData, Unit
27+
>>> empty_datum = Unit()
28+
>>> empty_datum.to_cbor().hex()
2829
'd87980'
2930

3031
Sample datum with int, bytes, List and hashmap inputs::
3132

3233
>>> # Create sample datum
34+
>>> from typing import List, Dict
35+
>>> from dataclasses import dataclass
3336
>>> @dataclass
3437
... class MyDatum(PlutusData):
3538
... CONSTR_ID = 1
3639
... a: int
3740
... b: bytes
38-
... c: IndefiniteList
39-
... d: dict
41+
... c: List[int]
42+
... d: Dict[int, bytes]
4043

41-
>>> datum = MyDatum(123, b"1234", IndefiniteList([4, 5, 6]), {1: b"1", 2: b"2"})
42-
>>> datum.to_cbor_hex()
43-
'd87a9f187b43333231ff'
44+
>>> datum = MyDatum(123, b"1234", [4, 5, 6], {1: b"1", 2: b"2"})
45+
>>> datum.to_cbor().hex()
46+
'd87a9f187b443132333483040506a2014131024132ff'
4447

4548
You can also wrap `PlutusData` within `PlutusData`::
4649

@@ -53,9 +56,9 @@ You can also wrap `PlutusData` within `PlutusData`::
5356

5457
>>> key_hash = bytes.fromhex("c2ff616e11299d9094ce0a7eb5b7284b705147a822f4ffbd471f971a")
5558
>>> deadline = 1643235300000
56-
>>> other_datum = MyDatum(123, b"1234", IndefiniteList([4, 5, 6]), {1: b"1", 2: b"2"})
59+
>>> other_datum = MyDatum(123, b"1234", [4, 5, 6], {1: b"1", 2: b"2"})
5760
>>> include_datum = InclusionDatum(key_hash, deadline, other_datum)
58-
>>> include_datum.to_cbor_hex()
61+
>>> include_datum.to_cbor().hex()
5962
'd87a9f581cc2ff616e11299d9094ce0a7eb5b7284b705147a822f4ffbd471f971a1b0000017e9874d2a0d8668218829f187b44313233349f040506ffa2014131024132ffff'
6063

6164
`PlutusData` supports conversion from/to JSON format, which
@@ -67,9 +70,48 @@ Similarly, redeemer can be serialized like following::
6770

6871
>>> data = MyDatum(123, b"234", IndefiniteList([]), {1: b"1", 2: b"2"})
6972
>>> redeemer = Redeemer(data, ExecutionUnits(1000000, 1000000))
70-
>>> redeemer.to_cbor_hex()
73+
>>> redeemer.to_cbor().hex()
7174
'840000d8668218829f187b433233349fffa2014131024132ff821a000f42401a000f4240'
7275

76+
--------------------------------
77+
Datum Deserialization
78+
--------------------------------
79+
80+
Deserialization of PlutusData generally has two different paths, based on whether you know the structure of the Plutus Datum you are trying to deserialize or not.
81+
If you know the structure in advance, subclass the `PlutusData` type and configure it to match the data type that you expect to receive. If the datatype does not match, the deserialization will throw an Exception! So make sure that the data really follows the format that you expect.::
82+
83+
>>> # Create sample datum
84+
>>> from typing import List, Dict
85+
>>> @dataclass
86+
... class MyDatum(PlutusData):
87+
... CONSTR_ID = 1
88+
... a: int
89+
... b: bytes
90+
... c: List[int]
91+
... d: Dict[int, bytes]
92+
93+
>>> MyDatum.from_cbor(bytes.fromhex('d87a9f187b443132333483040506a2014131024132ff'))
94+
MyDatum(a=123, b=b'1234', c=[4, 5, 6], d={1: b'1', 2: b'2'})
95+
>>> # The Inclusion Datum will not be correctly deserialized
96+
>>> MyDatum.from_cbor(bytes.fromhex('d87a9f581cc2ff616e11299d9094ce0a7eb5b7284b705147a822f4ffbd471f971a1b0000017e9874d2a0d8668218829f187b44313233349f040506ffa2014131024132ffff'))
97+
DeserializeException(f"Cannot deserialize object: \n{v}\n to type {t}.")
98+
pycardano.exception.DeserializeException: Cannot deserialize object:
99+
b'\xc2\xffan\x11)\x9d\x90\x94\xce\n~\xb5\xb7(KpQG\xa8"\xf4\xff\xbdG\x1f\x97\x1a'
100+
to type <class 'int'>.
101+
102+
If you do not know the structure of the Datum in advance, use `RawPlutusDatum.from_cbor`.
103+
As you can see, this will not tell you anything about the `meaning` of specific fields, CBOR Tags etc - this is because the meaning are not stored on chain. In the CBOR, just the types are known and hence restoring a raw datum will return to you just the types.::
104+
105+
>>> from pycardano import RawPlutusData
106+
>>> RawPlutusData.from_cbor(bytes.fromhex("d87a9f187b443132333483040506a2014131024132ff"))
107+
RawPlutusData(data=CBORTag(122, [123, b'1234', [4, 5, 6], {1: b'1', 2: b'2'}]))
108+
109+
Note that there are specific fields you may need.
110+
* **Builtin**: If you don't know the structure of a datum inside a PlutusDatum. It will be decoded as RawPlutusDatum.
111+
* **IndefiniteList**: A list that is in theory unbounded. This may be required by the Cardano node in case a list has more than 64 elements.
112+
* **ByteString**: Similarly to IndefiniteList, this denotes a `bytes` element that may be longer than 64 bytes and correctly encodes it in CBOR so that the result is accepted by the Cardano node.
113+
114+
73115
-----------------------
74116
Example - Gift Contract
75117
-----------------------

docs/source/guides/serialization.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,9 @@ Examples::
6161
'update': None,
6262
'validity_start': None,
6363
'withdraws': None}
64+
65+
----------
66+
Plutus Data
67+
----------
68+
69+
Note that Plutus datums, passed to `smart contracts <./plutus.html>`_ follow slightly specific rules to `from_cbor`, outlined in the `plutus documentation <./plutus.html#...>`_.

0 commit comments

Comments
 (0)