From 45df9fb3f227d808d4d46d76747e987ecf6145df Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Tue, 3 Mar 2020 15:53:42 +0100 Subject: [PATCH 1/5] docs: append file name to auto generated section label --- docs/commands.rst | 8 ++++---- docs/conf.py | 3 +++ docs/transfers.rst | 0 docs/tutorials.rst | 10 +++++----- iota/api.py | 6 +++--- iota/api_async.py | 6 +++--- 6 files changed, 18 insertions(+), 15 deletions(-) create mode 100644 docs/transfers.rst diff --git a/docs/commands.rst b/docs/commands.rst index a860a44..a3a5771 100644 --- a/docs/commands.rst +++ b/docs/commands.rst @@ -10,15 +10,15 @@ Advanced: PyOTA Commands However, if you are a curious mind or happen to do development on the library, the following information might be useful. -PyOTA provides the API interface (:ref:`Core API Methods` and -:ref:`Extended API Methods`) for users of the library. These handle +PyOTA provides the API interface (:ref:`core_api:Core API Methods` and +:ref:`extended_api:Extended API Methods`) for users of the library. These handle constructing and sending HTTP requests to the specified node through adapters, furthermore creating, transforming and translating between PyOTA-specific types and (JSON-encoded) raw data. They also filter outgoing requests and incoming responses to ensure that only appropriate data is communicated with the node. PyOTA implements the `Command Design Pattern`_. High level API interface -methods (:ref:`Core API Methods` and :ref:`Extended API Methods`) +methods (:ref:`core_api:Core API Methods` and :ref:`extended_api:Extended API Methods`) internally call PyOTA commands to get the job done. Most PyOTA commands are sub-classed from :py:class:`FilterCommand` class, which @@ -142,7 +142,7 @@ Extended Commands Core commands, like :py:meth:`~Iota.find_transactions` in the example above, are for direct communication with the node for simple tasks such as finding a transaction on the Tangle or getting info about the node. -Extended commands (that serve :ref:`Extended API Methods`) on the other hand +Extended commands (that serve :ref:`extended_api:Extended API Methods`) on the other hand carry out more complex operations such as combining core commands, building objects, etc... diff --git a/docs/conf.py b/docs/conf.py index 75e7ef2..be5b331 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -36,6 +36,9 @@ 'sphinx.ext.autosectionlabel', ] +# Add a document prefix to the created section lables +autosectionlabel_prefix_document = True + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/transfers.rst b/docs/transfers.rst new file mode 100644 index 0000000..e69de29 diff --git a/docs/tutorials.rst b/docs/tutorials.rst index dcbbdc8..02c3799 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -8,7 +8,7 @@ to help you understand how to carry out specific tasks with PyOTA. The example scripts displayed here can also be found under ``examples/tutorials/`` directory in the repository. Run them in a Python environment that has PyOTA -installed. See :ref:`Install PyOTA` for more info. +installed. See :ref:`README:Install PyOTA` for more info. If you feel that something is missing or not clear, please post your questions and suggestions in the `PyOTA Bug Tracker`_. @@ -43,7 +43,7 @@ something from the library, you need to import it from there. Notice, how we import the :py:class:`Iota` object, that defines a so-called extended API object. We will use this to send and receive data from -the network. Read more about API objects at :ref:`PyOTA API Classes`. +the network. Read more about API objects at :ref:`api:PyOTA API Classes`. We also import the ``pprint`` method that prettifies the output before printing it to the console. @@ -141,7 +141,7 @@ therefore we are restricted to the `tryte alphabet`_. :lines: 16-22 :lineno-start: 16 -It's time to construct the transaction. According to :ref:`Transaction Types`, +It's time to construct the transaction. According to :ref:`types:Transaction Types`, PyOTA uses :py:class:`ProposedTransaction` to build transactions that are not yet broadcast to the network. Oberve, that the ``value=0`` means this is a zero-value transaction. @@ -284,7 +284,7 @@ that has no transactions referencing it on the Tangle and was never spent from. If we were to generate more addresses starting from a desired index, we could specify the ``start`` and ``count`` parameters. Read more about how to -generate addresses in PyOTA at :ref:`Generating Addresses`. +generate addresses in PyOTA at :ref:`addresses:Generating Addresses`. On line 20 we access the first element of the list of addresses in the response dictionary. @@ -588,7 +588,7 @@ An address is also needed, so we generate one with the help of index of the generated address, and don't forget, that the method returns a ``dict`` with a list of addresses, even if it contains only one. For more detailed explanation on how addresses are generated in PyOTA, -refer to the :ref:`Generating Addresses` page. +refer to the :ref:`adresses:Generating Addresses` page. We also attach a custom :py:class:`Tag` to our :py:class:`ProposedTransaction`. Note, that if our ``trytes_encrypted_data`` was longer than the maximum payload diff --git a/iota/api.py b/iota/api.py index 4976a30..2c1a3e6 100644 --- a/iota/api.py +++ b/iota/api.py @@ -67,7 +67,7 @@ class StrictIota(AsyncStrictIota): to :py:meth:`attach_to_tangle` to `ccurl pow interface `_. - See :ref:`Optional Local Pow` for more info and + See :ref:`README:Optional Local Pow` for more info and :ref:`find out` how to use it. """ @@ -88,7 +88,7 @@ def __init__(self, adapter, devnet=False, local_pow=False): to :py:meth:`attach_to_tangle` to `ccurl pow interface `_. - See :ref:`Optional Local Pow` for more info and + See :ref:`README:Optional Local Pow` for more info and :ref:`find out` how to use it. """ super().__init__(adapter, devnet, local_pow) @@ -828,7 +828,7 @@ class Iota(StrictIota, AsyncIota): to :py:meth:`attach_to_tangle` to `ccurl pow interface `_. - See :ref:`Optional Local Pow` for more info and + See :ref:`README:Optional Local Pow` for more info and :ref:`find out` how to use it. References: diff --git a/iota/api_async.py b/iota/api_async.py index 6004242..c013cde 100644 --- a/iota/api_async.py +++ b/iota/api_async.py @@ -38,7 +38,7 @@ class AsyncStrictIota: to :py:meth:`attach_to_tangle` to `ccurl pow interface `_. - See :ref:`Optional Local Pow` for more info and + See :ref:`README:Optional Local Pow` for more info and :ref:`find out` how to use it. """ @@ -59,7 +59,7 @@ def __init__(self, adapter, devnet=False, local_pow=False): to :py:meth:`attach_to_tangle` to `ccurl pow interface `_. - See :ref:`Optional Local Pow` for more info and + See :ref:`README:Optional Local Pow` for more info and :ref:`find out` how to use it. """ super().__init__() @@ -769,7 +769,7 @@ class AsyncIota(AsyncStrictIota): to :py:meth:`attach_to_tangle` to `ccurl pow interface `_. - See :ref:`Optional Local Pow` for more info and + See :ref:`README:Optional Local Pow` for more info and :ref:`find out` how to use it. References: From ef3164614f61417babf1d894cb770238076921b0 Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Tue, 3 Mar 2020 15:54:27 +0100 Subject: [PATCH 2/5] Rename transaction's method - get_signature_validation_trytes() renamed to get_bundle_essence_trytes() fo clarity. --- docs/types.rst | 6 +++--- iota/transaction/base.py | 18 +++++++++++++++--- iota/transaction/creation.py | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/docs/types.rst b/docs/types.rst index 0b24971..e3b3044 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -249,9 +249,9 @@ See the class documentation below: ^^^^^^^^^^^^^^^^^^^^^ .. automethod:: Transaction.from_tryte_string -**get_signature_validation_trytes** -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automethod:: Transaction.get_signature_validation_trytes +**get_bundle_essence_trytes** +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. automethod:: Transaction.get_bundle_essence_trytes ProposedTransaction ~~~~~~~~~~~~~~~~~~~ diff --git a/iota/transaction/base.py b/iota/transaction/base.py index c904c70..2cf3ecd 100644 --- a/iota/transaction/base.py +++ b/iota/transaction/base.py @@ -570,11 +570,23 @@ def as_tryte_string(self): + self.nonce ) - def get_signature_validation_trytes(self): + def get_bundle_essence_trytes(self): # type: () -> TryteString """ - Returns the values needed to validate the transaction's - ``signature_message_fragment`` value. + Returns the values needed for calculating bundle hash. + The bundle hash is the hash of the bundle essence, which is itself + the hash of the following fields of transactions in the bundle: + + - ``address``, + - ``value``, + - ``legacy_tag``, + - ``current_index``, + - ``last_index``, + - and ``timestamp``. + + The transaction's ``signature_message_fragment`` field contains + the signature generated by signing the bundle hash with the address's + private key. :return: :py:class:`TryteString` object. diff --git a/iota/transaction/creation.py b/iota/transaction/creation.py index 302e5f8..3d5bc5a 100644 --- a/iota/transaction/creation.py +++ b/iota/transaction/creation.py @@ -476,7 +476,7 @@ def finalize(self): txn.current_index = i txn.last_index = last_index - sponge.absorb(txn.get_signature_validation_trytes().as_trits()) + sponge.absorb(txn.get_bundle_essence_trytes().as_trits()) bundle_hash_trits = [0] * HASH_LENGTH sponge.squeeze(bundle_hash_trits) From 9ea1f1625b70d53ede5ceee08eedf555eee33571 Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Tue, 3 Mar 2020 15:56:15 +0100 Subject: [PATCH 3/5] docs: Add section `Creating Transfers` - Explanation of how transfers are created - Two new figures on transfer creation and available API methods. - 3 code examples to show the different ways of transaction creation. --- docs/images/create_transfer.svg | 3 + docs/images/transfer_api.svg | 3 + docs/index.rst | 1 + docs/transfers.rst | 296 ++++++++++++++++++++++++++++++++ 4 files changed, 303 insertions(+) create mode 100644 docs/images/create_transfer.svg create mode 100644 docs/images/transfer_api.svg diff --git a/docs/images/create_transfer.svg b/docs/images/create_transfer.svg new file mode 100644 index 0000000..f88ba79 --- /dev/null +++ b/docs/images/create_transfer.svg @@ -0,0 +1,3 @@ + + +
Bundle
Bundle
- Create individual transactions.
- Specify:
  • address,
  • value,
  • message,
  • and tag.
Timestamp is usually auto-generated.
- Create individual transactions....
- Create a bundle from the transactions.
- Bundle has to be balanced. Sum of the
  values of transactions is zero. 
- Index transactions within the bundle.
- Sign inputs if needed.
- Compute a unique identifier of the bundle,
  the bundle hash.
- Create a bundle from the transactions....

- Obtain two tips from the network.
- These will be the transactions referenced
  and hence validated by your bundle. 

- Obtain two tips from the network....

- Link together transactions in the bundle
  through their branch and trunk references.
- Find the nonce for each transaction
  individually.
- Transactions are finalized, transaction hash
  is available.

- Link together transactions in the bundle...
Create Transactions
Create Transactions
1
1
Create and Finalize Bundle
Create and Finalize Bundle
2
2
Select Two Tips
Select Two Tips
3
3
Do Proof-of-Work
Do Proof-of-Work
4
4
Broadcast & Store
Broadcast & Store
5
5

- Send transactions to the node.

- Transactions will be:
  • broadcast to the network, and
  • stored in the node's local database.
 - Once confirmed, transactions are part
   of the Tangle.
- Send transactions to the node....
List of Transactions
List of Transactions
Finalized Bundle
Finalized Bundle
Bundle and References
Bundle and References
Attached Transactions
Attached Transactions
Transactions become part of the Tangle
Transactions become part of the Tangle
- address
- value
- message
- tag
- timestamp
- current index
- last index
- signature
- bundle hash
- trunk hash
- branch hash
nonce
- address...
Transaction
Transaction
- address
- value
- message
- tag
- timestamp
- current index
- last index
- signature
- bundle hash
- trunk hash
- branch hash
nonce
- address...
Transaction
Transaction
- address
- value
- message
- tag
- timestamp
- current index
- last index
- signature
- bundle hash
- trunk hash
- branch hash
nonce
- address...
Transaction
Transaction
Bundle
Bundle
- address
- value
- message
- tag
- timestamp
current index
last index
signature
bundle hash
- address...
Transaction
Transaction
- address
- value
- message
- tag
- timestamp
current index
last index
signature
bundle hash
- address...
Transaction
Transaction
- address
- value
- message
- tag
- timestamp
current index
last index
signature
bundle hash
- address...
Transaction
Transaction
Bundle
Bundle
Transaction
Transaction
- address
- value
- message
- tag
- timestamp
- current index
- last index
- signature
- bundle hash
- trunk hash
- branch hash
- address...
Transaction
Transaction
- address
- value
- message
- tag
- timestamp
- current index
- last index
- signature
- bundle hash
- trunk hash
- branch hash
- address...
Transaction
Transaction
- address
- value
- message
- tag
- timestamp
- current index
- last index
- signature
- bundle hash
- trunk hash
- branch hash
- address...
Transaction
Transaction
- address
- value

- message
- tag
- timestamp
- address...
Transaction
Transaction
address
- value

- message
- tag
timestamp
- address...
Transaction
Transaction
address
- value

- message
- tag
timestamp
- address...
Transaction
Transaction
The Tangle
The Tangle
Transaction
Transaction
Transaction
Transaction
Transaction
Transaction
Trunk
Trunk
Branch
Branch
Branch Reference
Branch Reference
Trunk Reference
Trunk Reference
Bundle
Bundle
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/images/transfer_api.svg b/docs/images/transfer_api.svg new file mode 100644 index 0000000..9b2d2f7 --- /dev/null +++ b/docs/images/transfer_api.svg @@ -0,0 +1,3 @@ + + +
Extended API Methods
Extended API Methods
Core API Methods
Core API Methods
PyOTA API
PyOTA API
send_transfer()
send_transfer()
send_trytes()
send_trytes()
prepare_transfer()
prepare_transfer()
broadcast_and_store()
broadcast_and_store()
broadcast_transactions()
broadcast_transactions()
store_transactions()
store_transactions()
attach_to_tangle()
attach_to_tangle()
get_transactions_to_approve()
get_transactions_to_approve()
ProposedBundle(...)
ProposedBundle(...)
ProposedBundle.finalize()
ProposedBundle.finalize()
ProposedTransaction(...)
ProposedTransaction(...)
Create Transactions
Create Transactions
1
1
Select Two Tips
Select Two Tips
3
3
Do Proof-of-Work
Do Proof-of-Work
4
4
Broadcast & Store
Broadcast & Store
5
5
Create and Finalize Bundle
Create and Finalize Bundle
2
2
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 2a6a0da..bf8652e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,6 +10,7 @@ core_api extended_api addresses + transfers multisig commands tutorials diff --git a/docs/transfers.rst b/docs/transfers.rst index e69de29..bf0b1cb 100644 --- a/docs/transfers.rst +++ b/docs/transfers.rst @@ -0,0 +1,296 @@ +Creating transfers +================== + +IOTA is a permissionless DLT solution, therefore anyone can send transactions +to the network and initiate transfers. The IOTA client libraries help you to +abstract away low level operations required to construct and send a transfer +to the Tangle. + +In this section, we will explore in depth how to create transactions and +bundles with IOTA, furthermore what tools you can use in PyOTA to ease your +development process. + +.. note:: + + Before proceeding, make sure you read and understood the + :ref:`basic_concepts:Basic Concepts` and :ref:`types:PyOTA Types` sections! + +Anatomy of a Transfer +--------------------- + +We already now that the Tangle consists of :ref:`transactions ` +referencing each other, each of them two others to be more precise. +Transactions can be grouped together in :ref:`bundles `. +`Zero-value bundles`_ contain only zero value transactions, while +`transfer bundles`_ may also contain input and output transactions. + +But how to construct these bundles and send them to the network? + +The process can be boiled down to 5 steps: + + 1. Create individual transaction(s). + 2. Construct a bundle from the transaction(s). + 3. Obtain references to two transactions waiting to be confirmed (tips) from the Tangle. + 4. Do proof-of-work for each transaction in the bundle. + 5. Send the bundle to the network. + + +.. figure:: images/create_transfer.svg + :scale: 100 % + :alt: Process of sending a transfer in IOTA. + + Process of creating and sending a transfer to the Tangle. + +.. py:currentmodule:: iota + +1. Create Transactions +~~~~~~~~~~~~~~~~~~~~~~ +The first step is to create the individual transaction objects. You have to +specify ``address`` and ``value`` for each transaction. A negative ``value`` +means spending from ``address``. Furthermore, you can define a ``tag``, and for +zero-value transactions, a ``message``. ``timestamp`` is usually auto-generated +by the IOTA libraries. + +In PyOTA, use :py:class:`ProposedTransaction` to declare transactions. + +2. Create Bundle from Transactions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +A bundle is a collection of transactions, treated as an atomic unit +when sent to the network. A bundle makes a value (token) transfer possible by +grouping together input an output transactions. + +A bundle always has to be balanced: the sum of ``value`` attributes of the +transactions in the bundle should always be zero. Transactions in the bundle +are indexed individually, and also contain information on how many other +transactions there are in the bundle. + +Once complete, a bundle has to be finalized to generate the bundle hash based +on the `bundle essence`_. The bundle hash is the unique identifier of the +bundle. + +After finalization, input transactions in the bundle need to be signed to prove +ownership of tokens being transferred. + +:py:class:`ProposedBundle` helps you in PyOTA to create bundles, add transactions, +finalize the bundle and sign the inputs. + +3. Select two tips +~~~~~~~~~~~~~~~~~~ + +Tips are transactions that are yet to be confirmed by the network. We can +obtain two tips by requesting them from a node. In PyOTA, :py:meth:`~Iota.get_transactions_to_approve` +does the job: it returns a ``trunk`` and a ``branch`` :py:class:`TransactionHash`. + +Our bundle will validate these two transactions once in the Tangle. + +4. Do Proof-of-Work +~~~~~~~~~~~~~~~~~~~ + +The bundle has been finalized, inputs have been signed, we have two tips, +now it's time to prepare the bundle to be attached to the Tangle. All +transactions reference two other transactions in the Tangle, therefore we need +to select these references for each transaction in our bundle. + +We also know that transactions `within the bundle are linked together`_ through +their trunk references. So how do we construct the correct bundle structure +and also reference two tips from the network? + +.. figure:: images/bundle-structure.png + :scale: 100 % + :alt: Bundle structure with four transactions. + + Structure of a bundle with four transactions. Numbers in brackets denote + (``currentIndex``, ``lastIndex``) fields. Head of the bundle has index 3, + while tail has index 0. + +For all non-head transactions in the bundle, the trunk reference is the next +transaction in the bundle, while the branch reference is the trunk transaction +hash, one of the tips. + +The head transaction is different: the trunk reference is the trunk tip, while +the branch reference is the branch tip. + +The proof-of-work calculation has to be done for each transaction individually, +therefore the more transactions you have in the bundle, the more time it will +take. The difficulty of the calculation also depends on the `minimum weight magnitude`_ +set by the network. + +The output of the proof-of-work algorithm is a ``nonce`` value that is appended +to the the transaction, resulting in the attached transaction trytes. +Nodes validate the proof-of-work of a transaction by calculating the transaction's +hash from the attached transaction trytes. If the resulting hash has at least +``minimum weight magnitude`` number of trailing zero trits, it is correct. + +In PyOTA, use :py:meth:`~Iota.attach_to_tangle` to carry out this step. + +5. Broadcast and Store +~~~~~~~~~~~~~~~~~~~~~~ + +The final step is to send the bundle to the network. Nodes will broadcast +the transactions in the network, and store them in their local database. + +In PyOTA, use :py:meth:`~Iota.broadcast_and_store` to achieve this. + +Observe the bird-eye view of the Tangle depicted at the last step of the +process. Our transactions are part of the Tangle, reference each other and +the two tips. Newer transactions may reference our transactions as branch or +trunk. + +Use the Library +--------------- + +The IOTA libraries help you to abstract away the low-level operations needed +to create transfers. The figure below illustrates the different ways you can +build and send a transfer. + +.. figure:: images/transfer_api.svg + :scale: 100 % + :alt: Different ways of sending a transfer in IOTA. + + API commands for sending transfers. + +Let's look at some code snippets on how to perform the above with an imaginary +bundle that has 3 fictional transactions. + +1. Level Padawan +~~~~~~~~~~~~~~~~ +The easiest and most convenient way is to use :py:meth:`~Iota.send_transfer` +extended API method. You still need to create the transactions yourself +with :py:class:`ProposedTransaction`. + +.. code-block:: + + from iota import Iota, ProposedTransaction, Address + + api = Iota('https://nodes.devnet.iota.org:443') + + fictional_transactions = [ + ProposedTransaction( + address=Address(b'FIRSTRANDOMADDRESS'), + value=0, + # You could add a tag or message here too! + ), + ProposedTransaction( + address=Address(b'SECONDRANDOMADDRESS'), + value=0, + ), + ProposedTransaction( + address=Address(b'THIRDRANDOMADDRESS'), + value=0, + ) + ] + + imaginary_bundle = api.send_transfer( + transfers=transactions + )['bundle'] + +As all API methods in PyOTA, :py:meth:`~Iota.send_transfer` also returns +a ``dict``. The ``bundle`` key holds the value of :py:class:`Bundle`. + +It's important to note, that for value transfers, you will need your seed as well. +:py:meth:`~Iota.send_transfer` will look for ``input addresses`` to fund outgoing +transactions in the bundle, and auto-generate an unused ``change address`` if +there is a remainder amount of tokens. It will also take care of finalizing the +bundle and signing the necessary input transactions. + +2. Level Obi-Wan +~~~~~~~~~~~~~~~~ +Instead of :py:meth:`~Iota.send_transfer`, you can use the combination of +:py:meth:`~Iota.prepare_transfer` and :py:meth:`~Iota.send_trytes` to achieve +the same result. + +.. code-block:: + + from iota import Iota, ProposedTransaction, Address + + api = Iota('https://nodes.devnet.iota.org:443') + + transactions = [ + ProposedTransaction( + address=Address(b'FIRSTRANDOMADDRESS'), + value=0, + ), + ProposedTransaction( + address=Address(b'SECONDRANDOMADDRESS'), + value=0, + ), + ProposedTransaction( + address=Address(b'THIRDRANDOMADDRESS'), + value=0, + ) + ] + + prepared_trytes = api.prepare_transfer( + transfers=transactions + )['trytes'] + + imaginary_bundle_trytes = api.send_trytes( + trytes=prepared_trytes + )['trytes'] + +A difference here is that the end result, ``imaginary_bundle_trytes`` is a list +of :py:class:`TransactionTrytes`, and not a :py:class:`Bundle` object. + +3. Level Yoda +~~~~~~~~~~~~~ +Being the master Jedi of the PyOTA universe means that you know the most about +the force of low-level API methods. Use it wisely! + +.. code-block:: + + from iota import Iota, ProposedTransaction, Address, ProposedBundle + + api = Iota('https://nodes.devnet.iota.org:443') + + transactions = [ + ProposedTransaction( + address=Address(b'FIRSTRANDOMADDRESS'), + value=0, + ), + ProposedTransaction( + address=Address(b'SECONDRANDOMADDRESS'), + value=0, + ), + ProposedTransaction( + address=Address(b'THIRDRANDOMADDRESS'), + value=0, + ) + ] + + bundle = ProposedBundle() + + for tx in transactions: + bundle.add_transaction(tx) + + # If it was a value transfer, we could + # bundle.add_inputs() + # bundle.send_unspent_inputs_to() + + bundle.finalize() + + # Again, for value transfers, we could: + # bundle.sign_inputs(KeyGenerator(b'SEEDGOESHERE')) + + gtta_response = api.get_transactions_to_approve(depth=3) + + trunk = gtta_response['trunkTransaction'] + branch = gtta_response['branchTransaction'] + + attached_trytes = api.attach_to_tangle( + trunk_transaction=trunk, + branch_transaction=branch, + trytes=bundle.as_tryte_strings() + )['trytes'] + + api.broadcast_transactions(attached_trytes) + + api.store_transactions(attached_trytes) + + imaginary_bundle = Bundle.from_tryte_strings(attached_trytes) + + +.. _transfer bundles: https://docs.iota.org/docs/getting-started/0.1/transactions/bundles#transfer-bundles +.. _zero-value bundles: https://docs.iota.org/docs/getting-started/0.1/transactions/bundles#zero-value-bundle +.. _bundle essence: https://docs.iota.org/docs/getting-started/0.1/transactions/bundles#bundle-essence +.. _within the bundle are linked together: https://docs.iota.org/docs/getting-started/0.1/transactions/bundles +.. _minimum weight magnitude: https://docs.iota.org/docs/getting-started/0.1/network/minimum-weight-magnitude \ No newline at end of file From 676f913176345194accfbcb63fa2bb3f6fffd36b Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Thu, 5 Mar 2020 18:51:21 +0100 Subject: [PATCH 4/5] Apply suggestions from code review Co-Authored-By: Phoenix --- docs/transfers.rst | 57 ++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/docs/transfers.rst b/docs/transfers.rst index bf0b1cb..fbf8fd0 100644 --- a/docs/transfers.rst +++ b/docs/transfers.rst @@ -3,7 +3,7 @@ Creating transfers IOTA is a permissionless DLT solution, therefore anyone can send transactions to the network and initiate transfers. The IOTA client libraries help you to -abstract away low level operations required to construct and send a transfer +abstract away low-level operations required to construct and send a transfer to the Tangle. In this section, we will explore in depth how to create transactions and @@ -18,7 +18,7 @@ development process. Anatomy of a Transfer --------------------- -We already now that the Tangle consists of :ref:`transactions ` +We already know that the Tangle consists of :ref:`transactions ` referencing each other, each of them two others to be more precise. Transactions can be grouped together in :ref:`bundles `. `Zero-value bundles`_ contain only zero value transactions, while @@ -30,7 +30,7 @@ The process can be boiled down to 5 steps: 1. Create individual transaction(s). 2. Construct a bundle from the transaction(s). - 3. Obtain references to two transactions waiting to be confirmed (tips) from the Tangle. + 3. Obtain references to two unconfirmed transactions ("tips") from the Tangle. 4. Do proof-of-work for each transaction in the bundle. 5. Send the bundle to the network. @@ -46,22 +46,27 @@ The process can be boiled down to 5 steps: 1. Create Transactions ~~~~~~~~~~~~~~~~~~~~~~ The first step is to create the individual transaction objects. You have to -specify ``address`` and ``value`` for each transaction. A negative ``value`` -means spending from ``address``. Furthermore, you can define a ``tag``, and for -zero-value transactions, a ``message``. ``timestamp`` is usually auto-generated +specify ``address`` and ``value`` for each transaction. Furthermore, you can define a ``tag``, and for +zero-value transactions, a ``message``. A ``timestamp`` is also required, though this value is usually auto-generated by the IOTA libraries. +.. note:: + Unlike on other decentralised ledgers, IOTA transactions can have positive *or* negative ``value`` amounts. In order to send iotas from one address to another, at least two transactions are required: + + * one with *positive* ``value`` (to increment the balance of the receiver), and + * one with *negative* ``value`` (to decrement the balance of the sender). + In PyOTA, use :py:class:`ProposedTransaction` to declare transactions. 2. Create Bundle from Transactions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A bundle is a collection of transactions, treated as an atomic unit -when sent to the network. A bundle makes a value (token) transfer possible by -grouping together input an output transactions. +when sent to the network. A bundle makes a value (iota token) transfer possible by +grouping together input and output transactions. A bundle always has to be balanced: the sum of ``value`` attributes of the transactions in the bundle should always be zero. Transactions in the bundle -are indexed individually, and also contain information on how many other +are also indexed individually and contain information on how many other transactions there are in the bundle. Once complete, a bundle has to be finalized to generate the bundle hash based @@ -69,10 +74,12 @@ on the `bundle essence`_. The bundle hash is the unique identifier of the bundle. After finalization, input transactions in the bundle need to be signed to prove -ownership of tokens being transferred. +ownership of iotas being transferred. -:py:class:`ProposedBundle` helps you in PyOTA to create bundles, add transactions, -finalize the bundle and sign the inputs. +.. tip: + :py:class:`ProposedBundle` helps you in PyOTA to create bundles, add transactions, + finalize the bundle and sign the inputs. We'll see how to use :py:class:`ProposedBundle` in + :ref:`Use the Library` below. 3. Select two tips ~~~~~~~~~~~~~~~~~~ @@ -81,14 +88,14 @@ Tips are transactions that are yet to be confirmed by the network. We can obtain two tips by requesting them from a node. In PyOTA, :py:meth:`~Iota.get_transactions_to_approve` does the job: it returns a ``trunk`` and a ``branch`` :py:class:`TransactionHash`. -Our bundle will validate these two transactions once in the Tangle. +Because our bundle references these two transactions, it will validate them once it is added to the Tangle. 4. Do Proof-of-Work ~~~~~~~~~~~~~~~~~~~ -The bundle has been finalized, inputs have been signed, we have two tips, -now it's time to prepare the bundle to be attached to the Tangle. All -transactions reference two other transactions in the Tangle, therefore we need +The bundle has been finalized, inputs have been signed, and we have two tips; +now it's time to prepare the bundle to be attached to the Tangle. As noted in the previous section, every +transaction references two other transactions in the Tangle; therefore we need to select these references for each transaction in our bundle. We also know that transactions `within the bundle are linked together`_ through @@ -119,7 +126,7 @@ The output of the proof-of-work algorithm is a ``nonce`` value that is appended to the the transaction, resulting in the attached transaction trytes. Nodes validate the proof-of-work of a transaction by calculating the transaction's hash from the attached transaction trytes. If the resulting hash has at least -``minimum weight magnitude`` number of trailing zero trits, it is correct. +``minimum weight magnitude`` number of trailing zero trits, the transaction is valid. In PyOTA, use :py:meth:`~Iota.attach_to_tangle` to carry out this step. @@ -131,8 +138,8 @@ the transactions in the network, and store them in their local database. In PyOTA, use :py:meth:`~Iota.broadcast_and_store` to achieve this. -Observe the bird-eye view of the Tangle depicted at the last step of the -process. Our transactions are part of the Tangle, reference each other and +Observe the bird's-eye view of the Tangle depicted at the last step of the +process. Our transactions are part of the Tangle, referencing each other and the two tips. Newer transactions may reference our transactions as branch or trunk. @@ -199,6 +206,9 @@ Instead of :py:meth:`~Iota.send_transfer`, you can use the combination of :py:meth:`~Iota.prepare_transfer` and :py:meth:`~Iota.send_trytes` to achieve the same result. +.. tip:: + This can be useful if you want to prepare the transactions (including signing inputs) on one device, but you want to then transfer the data to another device for transmission to the Tangle. For example, you might :py:meth:`~Iota.prepare_transfer` on an air-gapped computer that has your seed stored on it, but then transfer the resulting trytes to a networked computer (that does not have your seed) to :py:meth:`~Iota.send_trytes`. + .. code-block:: from iota import Iota, ProposedTransaction, Address @@ -236,6 +246,9 @@ of :py:class:`TransactionTrytes`, and not a :py:class:`Bundle` object. Being the master Jedi of the PyOTA universe means that you know the most about the force of low-level API methods. Use it wisely! +.. tip:: + You generally won't need to split out the process explicitly like this in your application code, but it is useful to understand what :py:meth:`~Iota.send_transfer` does under-the-hood, so that you are better-equipped to troubleshoot any issues that may occur during the process. + .. code-block:: from iota import Iota, ProposedTransaction, Address, ProposedBundle @@ -262,13 +275,13 @@ the force of low-level API methods. Use it wisely! for tx in transactions: bundle.add_transaction(tx) - # If it was a value transfer, we could + # If it was a value transfer, we would also need to: # bundle.add_inputs() # bundle.send_unspent_inputs_to() bundle.finalize() - # Again, for value transfers, we could: + # Again, for value transfers, we would need to: # bundle.sign_inputs(KeyGenerator(b'SEEDGOESHERE')) gtta_response = api.get_transactions_to_approve(depth=3) @@ -293,4 +306,4 @@ the force of low-level API methods. Use it wisely! .. _zero-value bundles: https://docs.iota.org/docs/getting-started/0.1/transactions/bundles#zero-value-bundle .. _bundle essence: https://docs.iota.org/docs/getting-started/0.1/transactions/bundles#bundle-essence .. _within the bundle are linked together: https://docs.iota.org/docs/getting-started/0.1/transactions/bundles -.. _minimum weight magnitude: https://docs.iota.org/docs/getting-started/0.1/network/minimum-weight-magnitude \ No newline at end of file +.. _minimum weight magnitude: https://docs.iota.org/docs/getting-started/0.1/network/minimum-weight-magnitude From 06d5a94ce0262d2c36e3c1de964a712d6bc30967 Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Fri, 6 Mar 2020 10:37:56 +0100 Subject: [PATCH 5/5] docs: Improvements on `Creating Transfers` --- docs/transfers.rst | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/docs/transfers.rst b/docs/transfers.rst index fbf8fd0..26d6361 100644 --- a/docs/transfers.rst +++ b/docs/transfers.rst @@ -46,12 +46,15 @@ The process can be boiled down to 5 steps: 1. Create Transactions ~~~~~~~~~~~~~~~~~~~~~~ The first step is to create the individual transaction objects. You have to -specify ``address`` and ``value`` for each transaction. Furthermore, you can define a ``tag``, and for -zero-value transactions, a ``message``. A ``timestamp`` is also required, though this value is usually auto-generated +specify ``address`` and ``value`` for each transaction. Furthermore, you can +define a ``tag``, and for zero-value transactions, a ``message``. A +``timestamp`` is also required, though this value is usually auto-generated by the IOTA libraries. .. note:: - Unlike on other decentralised ledgers, IOTA transactions can have positive *or* negative ``value`` amounts. In order to send iotas from one address to another, at least two transactions are required: + Unlike on other decentralised ledgers, IOTA transactions can have positive + *or* negative ``value`` amounts. In order to send iotas from one address to + another, at least two transactions are required: * one with *positive* ``value`` (to increment the balance of the receiver), and * one with *negative* ``value`` (to decrement the balance of the sender). @@ -76,10 +79,10 @@ bundle. After finalization, input transactions in the bundle need to be signed to prove ownership of iotas being transferred. -.. tip: +.. tip:: :py:class:`ProposedBundle` helps you in PyOTA to create bundles, add transactions, - finalize the bundle and sign the inputs. We'll see how to use :py:class:`ProposedBundle` in - :ref:`Use the Library` below. + finalize the bundle and sign the inputs. We'll see how to use + :py:class:`ProposedBundle` in :ref:`transfers:Use the Library` below. 3. Select two tips ~~~~~~~~~~~~~~~~~~ @@ -88,15 +91,17 @@ Tips are transactions that are yet to be confirmed by the network. We can obtain two tips by requesting them from a node. In PyOTA, :py:meth:`~Iota.get_transactions_to_approve` does the job: it returns a ``trunk`` and a ``branch`` :py:class:`TransactionHash`. -Because our bundle references these two transactions, it will validate them once it is added to the Tangle. +Because our bundle references these two transactions, it will validate them once +it is added to the Tangle. 4. Do Proof-of-Work ~~~~~~~~~~~~~~~~~~~ The bundle has been finalized, inputs have been signed, and we have two tips; -now it's time to prepare the bundle to be attached to the Tangle. As noted in the previous section, every -transaction references two other transactions in the Tangle; therefore we need -to select these references for each transaction in our bundle. +now it's time to prepare the bundle to be attached to the Tangle. As noted in +the previous section, every transaction references two other transactions in +the Tangle; therefore we need to select these references for each transaction +in our bundle. We also know that transactions `within the bundle are linked together`_ through their trunk references. So how do we construct the correct bundle structure @@ -143,6 +148,13 @@ process. Our transactions are part of the Tangle, referencing each other and the two tips. Newer transactions may reference our transactions as branch or trunk. +.. note:: + As more transactions are added to the Tangle that reference our transactions + – and then more are added that reference those transactions, and so on – this + increases the `cumulative weight`_ of our transactions. The higher the + cumulative weight of our transactions, the higher the chance for them to + get confirmed. + Use the Library --------------- @@ -307,3 +319,4 @@ the force of low-level API methods. Use it wisely! .. _bundle essence: https://docs.iota.org/docs/getting-started/0.1/transactions/bundles#bundle-essence .. _within the bundle are linked together: https://docs.iota.org/docs/getting-started/0.1/transactions/bundles .. _minimum weight magnitude: https://docs.iota.org/docs/getting-started/0.1/network/minimum-weight-magnitude +.. _cumulative weight: https://blog.iota.org/the-tangle-an-illustrated-introduction-f359b8b2ec80