diff --git a/docs/handcraft.rst b/docs/handcraft.rst index 4fe65cb..ebdb932 100644 --- a/docs/handcraft.rst +++ b/docs/handcraft.rst @@ -262,7 +262,10 @@ As for the details: .. ipython:: - In [0]: ed25519.to_dict() + In [0]: condition_details = { + ...: 'type': ed25519.TYPE_NAME, + ...: 'public_key': base58.b58encode(ed25519.public_key), + ...: } We can now easily assemble the ``dict`` for the output: @@ -271,7 +274,7 @@ We can now easily assemble the ``dict`` for the output: In [0]: output = { ...: 'amount': '1', ...: 'condition': { - ...: 'details': ed25519.to_dict(), + ...: 'details': condition_details, ...: 'uri': ed25519.condition_uri, ...: }, ...: 'public_keys': (alice.public_key,), @@ -288,7 +291,10 @@ Let's recap and set the ``outputs`` key with our self-constructed condition: In [0]: output = { ...: 'amount': '1', ...: 'condition': { - ...: 'details': ed25519.to_dict(), + ...: 'details': { + ...: 'type': ed25519.TYPE_NAME, + ...: 'public_key': base58.b58encode(ed25519.public_key), + ...: }, ...: 'uri': ed25519.condition_uri, ...: }, ...: 'public_keys': (alice.public_key,), @@ -401,7 +407,10 @@ above payload: output = { 'amount': '1', 'condition': { - 'details': ed25519.to_dict(), + 'details': { + 'type': ed25519.TYPE_NAME, + 'public_key': base58.b58encode(ed25519.public_key), + }, 'uri': ed25519.condition_uri, }, 'public_keys': (alice.public_key,), @@ -554,6 +563,7 @@ Handcrafting a ``CREATE`` transaction can be done as follows: import json + import base58 import sha3 from cryptoconditions import Ed25519Sha256 @@ -582,7 +592,10 @@ Handcrafting a ``CREATE`` transaction can be done as follows: output = { 'amount': '1', 'condition': { - 'details': ed25519.to_dict(), + 'details': { + 'type': ed25519.TYPE_NAME, + 'public_key': base58.b58encode(ed25519.public_key), + }, 'uri': ed25519.condition_uri, }, 'public_keys': (alice.public_key,), @@ -675,7 +688,7 @@ transfer transaction was prepared and fulfilled as follows: In [0]: transfer_input = { ...: 'fulfillment': output['condition']['details'], ...: 'fulfills': { - ...: 'output': output_index, + ...: 'output_index': output_index, ...: 'transaction_id': creation_tx['id'], ...: }, ...: 'owners_before': output['public_keys'], @@ -748,7 +761,10 @@ outputs In [0]: output = { ...: 'amount': '1', ...: 'condition': { - ...: 'details': ed25519.to_dict(), + ...: 'details': { + ...: 'type': ed25519.TYPE_NAME, + ...: 'public_key': base58.b58encode(ed25519.public_key), + ...: }, ...: 'uri': ed25519.condition_uri, ...: }, ...: 'public_keys': (bob.public_key,), @@ -764,7 +780,7 @@ fulfillments ...: 'fulfillment': None, ...: 'fulfills': { ...: 'transaction_id': creation_tx['id'], - ...: 'output': 0, + ...: 'output_index': 0, ...: }, ...: 'owners_before': (alice.public_key,) ...: } @@ -819,7 +835,10 @@ Before we generate the ``id``, let's recap how we got here: output = { 'amount': '1', 'condition': { - 'details': ed25519.to_dict(), + 'details': { + 'type': ed25519.TYPE_NAME, + 'public_key': base58.b58encode(ed25519.public_key), + }, 'uri': ed25519.condition_uri, }, 'public_keys': (bob.public_key,), @@ -830,7 +849,7 @@ Before we generate the ``id``, let's recap how we got here: 'fulfillment': None, 'fulfills': { 'transaction_id': creation_tx['id'], - 'output': 0, + 'output_index': 0, }, 'owners_before': (alice.public_key,) } @@ -962,6 +981,7 @@ In a nutshell import json + import base58 import sha3 from cryptoconditions import Ed25519Sha256 @@ -972,7 +992,7 @@ In a nutshell operation = 'TRANSFER' version = '1.0' - asset = {'id': creation_tx['id']} + asset = {'id': handcrafted_creation_tx['id']} metadata = None ed25519 = Ed25519Sha256(public_key=base58.b58decode(bob.public_key)) @@ -980,7 +1000,10 @@ In a nutshell output = { 'amount': '1', 'condition': { - 'details': ed25519.to_dict(), + 'details': { + 'type': ed25519.TYPE_NAME, + 'public_key': base58.b58encode(ed25519.public_key), + }, 'uri': ed25519.condition_uri, }, 'public_keys': (bob.public_key,), @@ -991,7 +1014,7 @@ In a nutshell 'fulfillment': None, 'fulfills': { 'transaction_id': creation_txid, - 'output': 0, + 'output_index': 0, }, 'owners_before': (alice.public_key,) } @@ -1093,8 +1116,11 @@ Handcrafting the ``CREATE`` transaction for our :ref:`bicycle sharing example # CRYPTO-CONDITIONS: generate the condition uri condition_uri = ed25519.condition.serialize_uri() - # CRYPTO-CONDITIONS: get the unsigned fulfillment dictionary (details) - unsigned_fulfillment_dict = ed25519.to_dict() + # CRYPTO-CONDITIONS: construct an unsigned fulfillment dictionary + unsigned_fulfillment_dict = { + 'type': ed25519.TYPE_NAME, + 'public_key': base58.b58encode(ed25519.public_key), + } output = { 'amount': '10', @@ -1202,8 +1228,14 @@ to Bob: carly_condition_uri = carly_ed25519.condition.serialize_uri() # CRYPTO-CONDITIONS: get the unsigned fulfillment dictionary (details) - bob_unsigned_fulfillment_dict = bob_ed25519.to_dict() - carly_unsigned_fulfillment_dict = carly_ed25519.to_dict() + bob_unsigned_fulfillment_dict = { + 'type': bob_ed25519.TYPE_NAME, + 'public_key': base58.b58encode(bob_ed25519.public_key), + } + carly_unsigned_fulfillment_dict = { + 'type': carly_ed25519.TYPE_NAME, + 'public_key': base58.b58encode(carly_ed25519.public_key), + } bob_output = { 'amount': '2', @@ -1226,7 +1258,7 @@ to Bob: 'fulfillment': None, 'fulfills': { 'transaction_id': token_creation_tx['id'], - 'output': 0, + 'output_index': 0, }, 'owners_before': (carly.public_key,) } @@ -1353,7 +1385,7 @@ their car over to ``carol``: In [0]: input_ = { ...: 'fulfillment': output['condition']['details'], ...: 'fulfills': { - ...: 'output': output_index, + ...: 'output_index': output_index, ...: 'transaction_id': signed_car_creation_tx['id'], ...: }, ...: 'owners_before': output['public_keys'], @@ -1420,14 +1452,24 @@ Generate the output condition: In [0]: threshold_sha256.add_subfulfillment(bob_ed25519) - In [0]: unsigned_subfulfillments_dict = threshold_sha256.to_dict() - In [0]: condition_uri = threshold_sha256.condition.serialize_uri() + In [0]: condition_details = { + ...: 'subconditions': [ + ...: {'type': s['body'].TYPE_NAME, + ...: 'public_key': base58.b58encode(s['body'].public_key)} + ...: for s in threshold_sha256.subconditions + ...: if (s['type'] == 'fulfillment' and + ...: s['body'].TYPE_NAME == 'ed25519-sha-256') + ...: ], + ...: 'threshold': threshold_sha256.threshold, + ...: 'type': threshold_sha256.TYPE_NAME, + ...: } + In [0]: output = { ...: 'amount': '1', ...: 'condition': { - ...: 'details': unsigned_subfulfillments_dict, + ...: 'details': condition_details, ...: 'uri': condition_uri, ...: }, ...: 'public_keys': (alice.public_key, bob.public_key), @@ -1447,7 +1489,7 @@ Generate the output condition: In [0]: alt_threshold_sha256.condition.serialize_uri() == condition_uri - The ``details`` on the other hand holds the associated fulfillments not yet + The ``details`` on the other hand hold the associated fulfillments not yet fulfilled. The yet to be fulfilled input: @@ -1531,7 +1573,10 @@ The transfer to Carol: In [0]: carol_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key)) - In [0]: unsigned_fulfillments_dict = carol_ed25519.to_dict() + In [0]: unsigned_fulfillments_dict = { + ...: 'type': carol_ed25519.TYPE_NAME, + ...: 'public_key': base58.b58encode(carol_ed25519.public_key), + ...: } In [0]: condition_uri = carol_ed25519.condition.serialize_uri() @@ -1552,7 +1597,7 @@ The yet to be fulfilled input: ...: 'fulfillment': None, ...: 'fulfills': { ...: 'transaction_id': handcrafted_car_creation_tx['id'], - ...: 'output': 0, + ...: 'output_index': 0, ...: }, ...: 'owners_before': (alice.public_key, bob.public_key), ...: } @@ -1605,18 +1650,16 @@ Sign the transaction: In [0]: threshold_sha256 = ThresholdSha256(threshold=2) + In [0]: alice_ed25519.sign(message=message.encode(), + private_key=base58.b58decode(alice.private_key)) + + In [0]: bob_ed25519.sign(message=message.encode(), + private_key=base58.b58decode(bob.private_key)) + In [0]: threshold_sha256.add_subfulfillment(alice_ed25519) In [0]: threshold_sha256.add_subfulfillment(bob_ed25519) - In [102]: alice_condition = threshold_sha256.get_subcondition_from_vk(base58.b58decode(alice.public_key))[0] - - In [103]: bob_condition = threshold_sha256.get_subcondition_from_vk(base58.b58decode(bob.public_key))[0] - - In [106]: alice_condition.sign(message.encode(), private_key=base58.b58decode(alice.private_key)) - - In [107]: bob_condition.sign(message.encode(), private_key=base58.b58decode(bob.private_key)) - In [0]: fulfillment_uri = threshold_sha256.serialize_uri() In [0]: handcrafted_car_transfer_tx['inputs'][0]['fulfillment'] = fulfillment_uri @@ -1638,6 +1681,7 @@ Handcrafting the ``'CREATE'`` transaction import json + import base58 import sha3 from cryptoconditions import Ed25519Sha256, ThresholdSha256 @@ -1670,17 +1714,27 @@ Handcrafting the ``'CREATE'`` transaction # CRYPTO-CONDITIONS: add bob ed25519 to the threshold SHA 256 condition threshold_sha256.add_subfulfillment(bob_ed25519) - - # CRYPTO-CONDITIONS: get the unsigned fulfillment dictionary (details) - unsigned_subfulfillments_dict = threshold_sha256.to_dict() - + # CRYPTO-CONDITIONS: generate the condition uri condition_uri = threshold_sha256.condition.serialize_uri() + # CRYPTO-CONDITIONS: get the unsigned fulfillment dictionary (details) + condition_details = { + 'subconditions': [ + {'type': s['body'].TYPE_NAME, + 'public_key': base58.b58encode(s['body'].public_key)} + for s in threshold_sha256.subconditions + if (s['type'] == 'fulfillment' and + s['body'].TYPE_NAME == 'ed25519-sha-256') + ], + 'threshold': threshold_sha256.threshold, + 'type': threshold_sha256.TYPE_NAME, + } + output = { 'amount': '1', 'condition': { - 'details': unsigned_subfulfillments_dict, + 'details': condition_details, 'uri': threshold_sha256.condition_uri, }, 'public_keys': (alice.public_key, bob.public_key), @@ -1768,7 +1822,10 @@ Handcrafting the ``'TRANSFER'`` transaction carol_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key)) - unsigned_fulfillments_dict = carol_ed25519.to_dict() + unsigned_fulfillments_dict = { + 'type': carol_ed25519.TYPE_NAME, + 'public_key': base58.b58encode(carol_ed25519.public_key), + } condition_uri = carol_ed25519.condition.serialize_uri() @@ -1786,7 +1843,7 @@ Handcrafting the ``'TRANSFER'`` transaction 'fulfillment': None, 'fulfills': { 'transaction_id': handcrafted_car_creation_tx['id'], - 'output': 0, + 'output_index': 0, }, 'owners_before': (alice.public_key, bob.public_key), } @@ -1794,7 +1851,7 @@ Handcrafting the ``'TRANSFER'`` transaction # Craft the payload: handcrafted_car_transfer_tx = { 'operation': 'TRANSFER', - 'asset': {'id': car_asset['id']}, + 'asset': {'id': handcrafted_car_creation_tx['id']}, 'metadata': None, 'outputs': (output,), 'inputs': (input_,), @@ -1824,18 +1881,15 @@ Handcrafting the ``'TRANSFER'`` transaction threshold_sha256 = ThresholdSha256(threshold=2) + alice_ed25519.sign(message=message.encode(), + private_key=base58.b58decode(alice.private_key)) + bob_ed25519.sign(message=message.encode(), + private_key=base58.b58decode(bob.private_key)) + threshold_sha256.add_subfulfillment(alice_ed25519) threshold_sha256.add_subfulfillment(bob_ed25519) - alice_condition = threshold_sha256.get_subcondition_from_vk(base58.b58decode(alice.public_key))[0] - - bob_condition = threshold_sha256.get_subcondition_from_vk(base58.b58decode(bob.public_key))[0] - - alice_condition.sign(message.encode(), private_key=base58.b58decode(alice.private_key)) - - bob_condition.sign(message.encode(), private_key=base58.b58decode(bob.private_key)) - fulfillment_uri = threshold_sha256.serialize_uri() handcrafted_car_transfer_tx['inputs'][0]['fulfillment'] = fulfillment_uri @@ -1876,6 +1930,7 @@ Handcrafting the ``'CREATE'`` transaction import json + import base58 import sha3 from cryptoconditions import Ed25519Sha256, ThresholdSha256 @@ -1909,17 +1964,27 @@ Handcrafting the ``'CREATE'`` transaction # CRYPTO-CONDITIONS: add bob ed25519 to the threshold SHA 256 condition threshold_sha256.add_subfulfillment(bob_ed25519) - - # CRYPTO-CONDITIONS: get the unsigned fulfillment dictionary (details) - unsigned_subfulfillments_dict = threshold_sha256.to_dict() - + # CRYPTO-CONDITIONS: generate the condition uri condition_uri = threshold_sha256.condition.serialize_uri() + # CRYPTO-CONDITIONS: get the unsigned fulfillment dictionary (details) + condition_details = { + 'subconditions': [ + {'type': s['body'].TYPE_NAME, + 'public_key': base58.b58encode(s['body'].public_key)} + for s in threshold_sha256.subconditions + if (s['type'] == 'fulfillment' and + s['body'].TYPE_NAME == 'ed25519-sha-256') + ], + 'threshold': threshold_sha256.threshold, + 'type': threshold_sha256.TYPE_NAME, + } + output = { 'amount': '1', 'condition': { - 'details': unsigned_subfulfillments_dict, + 'details': condition_details, 'uri': threshold_sha256.condition_uri, }, 'public_keys': (alice.public_key, bob.public_key), @@ -2008,14 +2073,15 @@ Handcrafting the ``'TRANSFER'`` transaction carol_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key)) - unsigned_fulfillments_dict = carol_ed25519.to_dict() - condition_uri = carol_ed25519.condition.serialize_uri() output = { 'amount': '1', 'condition': { - 'details': unsigned_fulfillments_dict, + 'details': { + 'type': carol_ed25519.TYPE_NAME, + 'public_key': base58.b58encode(carol_ed25519.public_key), + }, 'uri': condition_uri, }, 'public_keys': (carol.public_key,), @@ -2026,7 +2092,7 @@ Handcrafting the ``'TRANSFER'`` transaction 'fulfillment': None, 'fulfills': { 'transaction_id': handcrafted_car_creation_tx['id'], - 'output': 0, + 'output_index': 0, }, 'owners_before': (alice.public_key, bob.public_key), } @@ -2064,7 +2130,8 @@ Handcrafting the ``'TRANSFER'`` transaction threshold_sha256 = ThresholdSha256(threshold=1) - alice_ed25519.sign(message.encode(), private_key=base58.b58decode(alice.private_key)) + alice_ed25519.sign(message.encode(), + private_key=base58.b58decode(alice.private_key)) threshold_sha256.add_subfulfillment(alice_ed25519) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 3d207ed..c55d1bb 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -5,15 +5,16 @@ Quickstart / Installation The BigchainDB Python Driver depends on: 1. ``libffi/ffi.h`` -2. Python 3.5+ -3. A recent Python 3 version of ``pip`` -4. A recent Python 3 version of ``setuptools`` +2. ``libssl-dev`` +3. Python 3.5+ +4. A recent Python 3 version of ``pip`` +5. A recent Python 3 version of ``setuptools`` If you're missing one of those, then see below. Otherwise, you can install the BigchainDB Python Driver (``bigchaindb_driver``) using: .. code-block:: bash - pip install bigchaindb_driver + $ pip3 install bigchaindb_driver Next: :doc:`determine the BigchainDB Root URL of the BigchainDB node or cluster you want to connect to `. @@ -34,34 +35,58 @@ On Ubuntu 14.04 and 16.04, this works: .. code-block:: bash - sudo apt-get update + $ sudo apt-get update - sudo apt-get install libffi-dev + $ sudo apt-get install libffi-dev On Fedora 23 and 24, this works: .. code-block:: bash - sudo dnf update + $ sudo dnf update - sudo dnf install libffi-devel + $ sudo dnf install libffi-devel For other operating systems, just do some web searches for "ffi.h" with the name of your OS. +Dependency 2: libssl-dev +^^^^^^^^^^^^^^^^^^^^^^^^ +BigchainDB (server and driver) also depends on `cryptography`_, +which in turn depends on `libssl`_ AND `libcrypto`_. +Hence, depending on your setup you need to install the `libssl-dev`_ (Ubuntu) +OR `openssl-devel`_ (RHEL) package, which installs the development +libraries and header files for `libssl`_ and `libcrypto`_. + +On Ubuntu 14.04 and 16.04: + +.. code-block:: bash + + $ sudo apt-get install libssl-dev + +On Fedora 23 and 24: + +.. code-block:: bash + + $ sudo dnf install openssl-devel + -Dependency 2: Python 3.5+ +Dependency 3: Python 3.5+ ^^^^^^^^^^^^^^^^^^^^^^^^^ The BigchainDB Python Driver uses Python 3.5+. You can check your version of Python using: .. code-block:: bash - python --version + $ python --version + + OR + + $ python3 --version An easy way to install a specific version of Python, and to switch between versions of Python, is to use `virtualenv `_. Another option is `conda `_. -Dependency 3: pip +Dependency 4: pip ^^^^^^^^^^^^^^^^^ You also need to get a recent, Python 3 version of ``pip``, the Python package manager. @@ -72,7 +97,11 @@ You can check your version of ``pip`` using: .. code-block:: bash - pip --version + $ pip --version + + OR + + $ pip3 --version ``pip`` was at version 9.0.0 as of November 2016. If you need to upgrade your version of ``pip``, @@ -80,14 +109,19 @@ then see `the pip documentation `_ or our page about that in the `BigchainDB Server docs `_. -Dependency 4: setuptools +Dependency 5: setuptools ^^^^^^^^^^^^^^^^^^^^^^^^ Once you have a recent Python 3 version of ``pip``, you should be able to upgrade ``setuptools`` using: .. code-block:: bash - pip install --upgrade setuptools + $ pip install --upgrade setuptools + + OR + + $ pip3 install --upgrade setuptools + Installing the Driver @@ -97,7 +131,11 @@ Now you can install the BigchainDB Python Driver (``bigchaindb_driver``) using: .. code-block:: bash - pip install bigchaindb_driver + $ pip install bigchaindb_driver + + OR + + $ pip3 install bigchaindb_driver Next: :doc:`determine the BigchainDB Root URL of the BigchainDB node or cluster you want to connect to `. @@ -111,3 +149,8 @@ See the :doc:`Advanced Installation Options ` page. .. _pynacl: https://github.com/pyca/pynacl/ .. _Networking and Cryptography library: https://nacl.cr.yp.to/ .. _cryptoconditions: https://github.com/bigchaindb/cryptoconditions +.. _cryptography: https://cryptography.io/en/latest/ +.. _libssl-dev: https://packages.debian.org/jessie/libssl-dev +.. _openssl-devel: https://rpmfind.net/linux/rpm2html/search.php?query=openssl-devel +.. _libssl: https://github.com/openssl/openssl +.. _libcrypto: https://github.com/openssl/openssl