Skip to content

Commit 08e976d

Browse files
committed
Add more usage guides
1 parent 280c293 commit 08e976d

File tree

9 files changed

+411
-100
lines changed

9 files changed

+411
-100
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ format: ## runs code style and formatter
6666
poetry run black .
6767

6868
docs: ## build the documentation
69+
rm -r docs/build
6970
poetry run sphinx-build docs/source docs/build/html
7071
$(BROWSER) docs/build/html/index.html
7172

docs/source/conf.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,21 @@
3030
# Add any Sphinx extension module names here, as strings. They can be
3131
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
3232
# ones.
33-
extensions = ["sphinx.ext.autodoc", "sphinx.ext.napoleon", "sphinx_rtd_theme"]
33+
extensions = [
34+
"sphinx.ext.autodoc",
35+
"sphinx.ext.napoleon",
36+
"sphinx_rtd_theme",
37+
"sphinx_copybutton",
38+
]
3439

3540
master_doc = "index"
3641

3742
napoleon_google_docstring = True
3843
napoleon_include_init_with_doc = False
3944

45+
copybutton_prompt_text = r">>> |\.\.\. |\$ |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: "
46+
copybutton_prompt_is_regexp = True
47+
4048
autodoc_member_order = "bysource"
4149

4250
# Add any paths that contain templates here, relative to this directory.

docs/source/guides/address.rst

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,47 +13,48 @@ Payment key is usually used to sign transactions that involve funds transfers, w
1313
is usually used to sign transactions that involve staking-related activities, e.g. stake address registration,
1414
delegation. PyCardano provides APIs to create, save, and loads payment keys and stake keys.
1515

16-
New payment keys and stake keys could be generated using class method `generate()`. Their corresponding
17-
verification (public) key could be created using class method `from_signing_key()`::
16+
New payment keys and stake keys could be generated using class method
17+
`generate <../api/pycardano.key.html#pycardano.key.SigningKey.generate>`_. Their corresponding
18+
verification (public) key could be created using class method
19+
`from_signing_key <../api/pycardano.key.html#pycardano.key.VerificationKey.from_signing_key>`_::
1820

19-
from pycardano import PaymentSigningKey, StakeSigningKey, PaymentVerificationKey, StakeVerificationKey
21+
>>> from pycardano import PaymentSigningKey, StakeSigningKey, PaymentVerificationKey, StakeVerificationKey
22+
23+
>>> payment_signing_key = PaymentSigningKey.generate()
24+
>>> payment_verification_key = PaymentVerificationKey.from_signing_key(payment_signing_key)
2025

21-
payment_signing_key = PaymentSigningKey.generate()
22-
payment_verification_key = PaymentVerificationKey.from_signing_key(payment_signing_key)
23-
24-
25-
stake_signing_key = StakeSigningKey.generate()
26-
stake_verification_key = StakeVerificationKey.from_signing_key(stake_signing_key)
26+
>>> stake_signing_key = StakeSigningKey.generate()
27+
>>> stake_verification_key = StakeVerificationKey.from_signing_key(stake_signing_key)
2728

2829

2930
Alternatively, a key pair (signing key + verification key) could be generated together::
3031

31-
from pycardano import PaymentKeyPair, StakeKeyPair
32+
>>> from pycardano import PaymentKeyPair, StakeKeyPair
3233

33-
payment_key_pair = PaymentKeyPair.generate()
34-
payment_signing_key = payment_key_pair.signing_key
35-
payment_verification_key = payment_key_pair.verification_key
34+
>>> payment_key_pair = PaymentKeyPair.generate()
35+
>>> payment_signing_key = payment_key_pair.signing_key
36+
>>> payment_verification_key = payment_key_pair.verification_key
3637

37-
stake_key_pair = StakeKeyPair.generate()
38-
stake_signing_key = stake_key_pair.signing_key
39-
stake_verification_key = stake_key_pair.verification_key
38+
>>> stake_key_pair = StakeKeyPair.generate()
39+
>>> stake_signing_key = stake_key_pair.signing_key
40+
>>> stake_verification_key = stake_key_pair.verification_key
4041

4142

4243
A key could be saved to and loaded from a file::
4344

44-
# Save
45-
payment_signing_key.save("payment.skey")
46-
payment_verification_key.save("payment.vkey")
45+
>>> # Save
46+
>>> payment_signing_key.save("payment.skey")
47+
>>> payment_verification_key.save("payment.vkey")
4748

48-
# Load
49-
payment_signing_key = payment_signing_key.load("payment.skey")
50-
payment_verification_key = payment_verification_key.load("payment.vkey")
49+
>>> # Load
50+
>>> payment_signing_key = payment_signing_key.load("payment.skey")
51+
>>> payment_verification_key = payment_verification_key.load("payment.vkey")
5152

5253
Signing keys can sign messages (in bytes)::
5354

54-
message = b"Hello world!"
55-
print(payment_signing_key.signing_key.sign(b"Hello world!"))
56-
# b'\xf1N\x96\x05\xe8[\xa3"g5\x95\x80\xca\x88\x93&\xefD\xc3\x9fXj{\xaf\x01mna\xa92+z\x08\x9d\x1eG\x9fN\xc2\xb8\xb1\xab\xbf\xee\xf7\xa6\x08\x87\xfa\xeb\x9bGW\xba\xb7\xd8\xb2\xbb\xe0\x9c"\x0b\xe0\x07'
55+
>>> message = b"Hello world!"
56+
>>> payment_signing_key.signing_key.sign(b"Hello world!")
57+
b'\xf1N\x96\x05\xe8[\xa3"g5\x95\x80\xca\x88\x93&\xefD\xc3\x9fXj{\xaf\x01mna\xa92+z\x08\x9d\x1eG\x9fN\xc2\xb8\xb1\xab\xbf\xee\xf7\xa6\x08\x87\xfa\xeb\x9bGW\xba\xb7\xd8\xb2\xbb\xe0\x9c"\x0b\xe0\x07'
5758

5859
This guide only covers address keys. There is another category of keys called "Node keys".
5960
You can learn more about keys `here <https://docs.cardano.org/core-concepts/cardano-keys>`_.
@@ -72,28 +73,28 @@ when creating an address.
7273
Base address is the most commonly used address type. It is generated from a payment verification key and
7374
a stake verification key::
7475

75-
from pycardano import Address, Network
76+
>>> from pycardano import Address, Network
7677

77-
base_address = Address(payment_part=payment_verification_key.hash(),
78-
staking_part=stake_verification_key.hash(),
79-
network=Network.TESTNET)
78+
>>> base_address = Address(payment_part=payment_verification_key.hash(),
79+
... staking_part=stake_verification_key.hash(),
80+
... network=Network.TESTNET)
8081

81-
print(base_address)
82-
# addr_test1vr2p8st5t5cxqglyjky7vk98k7jtfhdpvhl4e97cezuhn0cqcexl7
82+
>>> base_address
83+
"addr_test1vr2p8st5t5cxqglyjky7vk98k7jtfhdpvhl4e97cezuhn0cqcexl7"
8384

8485
An address object could also be created from an address string directly::
8586

86-
address = Address.from_primitive("addr_test1vr2p8st5t5cxqglyjky7vk98k7jtfhdpvhl4e97cezuhn0cqcexl7")
87+
>>> address = Address.from_primitive("addr_test1vr2p8st5t5cxqglyjky7vk98k7jtfhdpvhl4e97cezuhn0cqcexl7")
8788

8889

8990
An enterprise address does not have staking functionalities, it is created from a payment verification key only::
9091

91-
enterprise_address = Address(payment_part=payment_verification_key.hash(),
92-
network=Network.TESTNET)
92+
>>> enterprise_address = Address(payment_part=payment_verification_key.hash(),
93+
... network=Network.TESTNET)
9394

9495

9596
A stake address does not have payment functionalities, it is created from a stake verification key only::
9697

97-
stake_address = Address(staking_part=payment_verification_key.hash(),
98-
network=Network.TESTNET)
98+
>>> stake_address = Address(staking_part=payment_verification_key.hash(),
99+
... network=Network.TESTNET)
99100

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
========================
2+
Instance/Object creation
3+
========================
4+
5+
In PyCardano, most components and data structures are embedded in Python classes. To construct an instance, we need to
6+
start from its child components, and build everything from bottom up.
7+
8+
For example, we need to create an instance of
9+
`TransactionId <../api/pycardano.hash.html#pycardano.hash.TransactionId>`_
10+
before creating a `TransactionInput <../api/pycardano.transaction.html#pycardano.transaction.TransactionInput>`_.
11+
Similarly, we need to provide an instance of
12+
`Address <../api/pycardano.address.html#pycardano.address.Address>`_
13+
before creating a `TransactionOutput <../api/pycardano.transaction.html#pycardano.transaction.TransactionOutput>`_::
14+
15+
>>> from pycardano import Address, TransactionId, TransactionInput, TransactionOutput
16+
>>> tx_id_hex = "732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5"
17+
>>> tx_id = TransactionId(bytes.fromhex(tx_id_hex))
18+
>>> tx_in = TransactionInput(tx_id, 0)
19+
>>> tx_in
20+
{'index': 0,
21+
'transaction_id': TransactionId(hex='732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5')}
22+
>>> addr = Address.decode(
23+
... "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x"
24+
... )
25+
>>> tx_out = TransactionOutput(addr, 100000000000)
26+
>>> tx_out
27+
{'address': addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x,
28+
'amount': 100000000000,
29+
'datum_hash': None}
30+
31+
32+
Another example is native asset::
33+
34+
>>> from pycardano import Asset, AssetName, MultiAsset, ScriptHash
35+
>>> # Create an asset container
36+
>>> my_asset = Asset()
37+
38+
>>> # Create names for our assets
39+
>>> nft1 = AssetName(b"MY_NFT_1")
40+
>>> nft2 = AssetName(b"MY_NFT_2")
41+
42+
>>> # Put assets into the asset container with a quantity of 1
43+
>>> my_asset[nft1] = 1
44+
>>> my_asset[nft2] = 1
45+
46+
>>> # Create a MultiAsset container
47+
>>> my_nft = MultiAsset()
48+
49+
>>> # Create a policy id
50+
>>> policy_id = ScriptHash(bytes.fromhex("9c83e0e86689ae56c0753c9a1714980e6b7603bca12530b0e19b0dae"))
51+
52+
>>> # Put assets into MultiAsset container.
53+
>>> my_nft[policy_id] = my_asset
54+
>>> my_nft
55+
{ScriptHash(hex='9c83e0e86689ae56c0753c9a1714980e6b7603bca12530b0e19b0dae'): {AssetName(b'MY_NFT_1'): 1, AssetName(b'MY_NFT_2'): 2}}
56+
57+
58+
It is rather verbose and tedious to build an instance from ground up. To solve this problem, PyCardano provides an
59+
alternative way of constructing instances: directly constructing an instance from Python primitive types. Because
60+
Python is quite concise in terms of creating dictionary and list literals, we can simplify instance construction by
61+
leveraging this Python feature.
62+
63+
Example of creating an equivalent ``TransactionInput`` and ``TransactionOutput`` from above::
64+
65+
>>> from pycardano import Address, TransactionId, TransactionInput, TransactionOutput
66+
>>> tx_in = TransactionInput.from_primitive(
67+
... [bytes.fromhex("732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5"), 0])
68+
>>> tx_in
69+
{'index': 0,
70+
'transaction_id': TransactionId(hex='732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5')}
71+
72+
>>> tx_out = TransactionOutput.from_primitive(
73+
... ["addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x", 100000000000])
74+
>>> tx_out
75+
{'address': addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x,
76+
'amount': 100000000000,
77+
'datum_hash': None}
78+
79+
80+
Example of creating an equivalent ``MultiAsset`` from above::
81+
82+
>>> my_nft_alternative = MultiAsset.from_primitive(
83+
... {
84+
... bytes.fromhex("9c83e0e86689ae56c0753c9a1714980e6b7603bca12530b0e19b0dae"): {
85+
... b"MY_NFT_1": 1,
86+
... b"MY_NFT_2": 1
87+
... }
88+
... }
89+
... )
90+
91+
>>> my_nft_alternative
92+
{ScriptHash(hex='9c83e0e86689ae56c0753c9a1714980e6b7603bca12530b0e19b0dae'): {AssetName(b'MY_NFT_1'): 1, AssetName(b'MY_NFT_2'): 1}}
93+
94+
95+
All child classes of `CBORSerializable <../api/pycardano.serialization.html#pycardano.serialization.CBORSerializable>`_
96+
has a class method
97+
`from_primitive <../api/pycardano.serialization.html#pycardano.serialization.CBORSerializable.from_primitive>`_ that takes
98+
a `Primitive <../api/pycardano.serialization.html#pycardano.serialization.Primitive>`_ as input, which is usually a list
99+
or dictionary. It is not hard to tell that creating an instance using primitives is much more concise and easier than
100+
building it from ground up.
101+
102+
.. note::
103+
The opposite operation of ``from_primitive`` is
104+
`to_primitive <../api/pycardano.serialization.html#pycardano.serialization.CBORSerializable.to_primitive>`_, which
105+
is often used in debugging and internal logic of `serialization <serialization.html>`_.

docs/source/guides/serialization.rst

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
=============
2+
Serialization
3+
=============
4+
5+
6+
Cardano uses Concise Binary Object Representation (`CBOR <https://cbor.io/>`_) to
7+
store on-chain data. Reading and writing data from/to blockchain requires serialization and deserialization of CBOR
8+
binaries.
9+
10+
A core feature PyCardano provides is serialization. It can serialize Python objects into CBOR bytes and deserialize
11+
CBOR bytes back to Python objects. Most Classes in PyCardano are child class of
12+
`CBORSerializable <../api/pycardano.serialization.html#pycardano.serialization.CBORSerializable>`_, which provides two
13+
CBOR-related methods. `to_cbor <../api/pycardano.serialization.html#pycardano.serialization.CBORSerializable.to_cbor>`_
14+
generates CBOR bytes from an instance, and
15+
`from_cbor <../api/pycardano.serialization.html#pycardano.serialization.CBORSerializable.from_cbor>`_ restore an instance.
16+
17+
Examples::
18+
19+
>>> from pycardano import (TransactionBody,
20+
... TransactionInput,
21+
... TransactionId,
22+
... TransactionOutput)
23+
>>>
24+
>>> tx_id_hex = "732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5"
25+
>>> tx_in = TransactionInput(TransactionId(bytes.fromhex(tx_id_hex)), 0)
26+
>>> addr = Address.decode(
27+
... "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x"
28+
... )
29+
>>> output1 = TransactionOutput(addr, 100000000000)
30+
>>> output2 = TransactionOutput(addr, 799999834103)
31+
>>> fee = 165897
32+
>>> tx_body = TransactionBody(
33+
... inputs=[tx_in],
34+
... outputs=[output1, output2],
35+
... fee=fee
36+
... )
37+
>>> cbor_hex = tx_body.to_cbor()
38+
a50081825820732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e500018282581d60f6532850e1bccee9c72a9113ad98bcc5dbb30d2ac960262444f6e5f41b000000174876e80082581d60f6532850e1bccee9c72a9113ad98bcc5dbb30d2ac960262444f6e5f41b000000ba43b4b7f7021a000288090d800e80
39+
40+
>>> restored_tx_body = TransactionBody.from_cbor(cbor_hex)
41+
>>> assert tx_body == restored_tx_body
42+
43+
>>> restored_tx_body
44+
{'auxiliary_data_hash': None,
45+
'certificates': None,
46+
'collateral': [],
47+
'fee': 165897,
48+
'inputs': [{'index': 0,
49+
'transaction_id': TransactionId(hex='732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5')}],
50+
'mint': None,
51+
'network_id': None,
52+
'outputs': [{'address': addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x,
53+
'amount': 100000000000,
54+
'datum_hash': None},
55+
{'address': addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x,
56+
'amount': 799999834103,
57+
'datum_hash': None}],
58+
'required_signers': [],
59+
'script_data_hash': None,
60+
'ttl': None,
61+
'update': None,
62+
'validity_start': None,
63+
'withdraws': None}

0 commit comments

Comments
 (0)