Skip to content
This repository has been archived by the owner on Jan 13, 2023. It is now read-only.

Commit

Permalink
Merge pull request #247 from lzpap/release/2.1.0
Browse files Browse the repository at this point in the history
PyOTA v2.1.0
  • Loading branch information
lzpap committed Oct 21, 2019
2 parents b1368af + ab771b1 commit 3057a1b
Show file tree
Hide file tree
Showing 38 changed files with 642 additions and 115 deletions.
6 changes: 3 additions & 3 deletions CONTRIBUTING.rst
Expand Up @@ -156,12 +156,12 @@ When you submit a Pull Request, here is what you can expect from the individual
- If any changes are needed, or if we cannot accept your submission, we will provide a respectful and constructive explanation.


.. _come on over and help us out!: https://github.com/iotaledger/iota.lib.py/issues/145
.. _come on over and help us out!: https://github.com/iotaledger/iota.py/issues/145
.. _email you: https://help.github.com/articles/managing-notification-delivery-methods/
.. _help wanted: https://github.com/iotaledger/iota.lib.py/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22
.. _help wanted: https://github.com/iotaledger/iota.py/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22
.. _how to contribute to open source: https://opensource.guide/how-to-contribute/
.. _notifications: https://github.com/notifications
.. _pep-8: https://www.python.org/dev/peps/pep-0008/
.. _pyota bug tracker: https://github.com/iotaledger/iota.lib.py/issues
.. _pyota bug tracker: https://github.com/iotaledger/iota.py/issues
.. _discord: https://discord.iota.org
.. _tutorials: https://docs.iota.org
26 changes: 22 additions & 4 deletions README.rst
@@ -1,5 +1,5 @@
.. image:: https://travis-ci.org/iotaledger/iota.lib.py.svg?branch=master
:target: https://travis-ci.org/iotaledger/iota.lib.py
.. image:: https://travis-ci.org/iotaledger/iota.py.svg?branch=master
:target: https://travis-ci.org/iotaledger/iota.py

.. image:: https://readthedocs.org/projects/pyota/badge/?version=latest
:target: http://pyota.readthedocs.io/en/latest/?badge=latest
Expand Down Expand Up @@ -42,12 +42,28 @@ To install this extension, use the following command::

pip install pyota[ccurl]

Optional Local Pow
==================
To perform proof-of-work locally without relying on a node,
you can install an extension module called `PyOTA-PoW`_ .

Specifiy the ``local_pow=True`` argument when creating an
api instance, that will redirect all ``attach_to_tangle``
API calls to an interface function in the ``pow`` package.

To install this extension, use the following command::

pip install pyota[pow]

Alternativley you can take a look on the repository
`Ccurl.interface.py`_ to install Pyota-PoW.
Follow the steps depicted in the repo's README file.

Installing from Source
======================

#. `Create virtualenv`_ (recommended, but not required).
#. ``git clone https://github.com/iotaledger/iota.lib.py.git``
#. ``git clone https://github.com/iotaledger/iota.py.git``
#. ``pip install -e .``

Running Unit Tests
Expand Down Expand Up @@ -97,7 +113,9 @@ can also build the documentation locally:

.. _Create virtualenv: https://realpython.com/blog/python/python-virtual-environments-a-primer/
.. _Discord: https://discord.iota.org/
.. _PyOTA Bug Tracker: https://github.com/iotaledger/iota.lib.py/issues
.. _PyOTA Bug Tracker: https://github.com/iotaledger/iota.py/issues
.. _ReadTheDocs: https://pyota.readthedocs.io/
.. _official API: https://docs.iota.org/docs/node-software/0.1/iri/references/api-reference
.. _tox: https://tox.readthedocs.io/
.. _Ccurl.interface.py: https://github.com/iotaledger/ccurl.interface.py
.. _PyOTA-PoW: https://pypi.org/project/PyOTA-PoW/
16 changes: 16 additions & 0 deletions docs/adapters.rst
Expand Up @@ -213,6 +213,22 @@ depending on the command name.
For example, you could use this wrapper to direct all PoW requests to a
local node, while sending the other requests to a light wallet node.

.. note::

A common use case for ``RoutingWrapper`` is to perform proof-of-work on
a specific (local) node, but let all other requests go to another node.
Take care when you use ``RoutingWrapper`` adapter and ``local_pow``
parameter together in an API instance, because the behavior might not
be obvious.

``local_pow`` tells the API to perform proof-of-work (``attach_to_tangle``)
without relying on an actual node. It does this by calling an extension
package `PyOTA-PoW <https://pypi.org/project/PyOTA-PoW/>`_ that does the
job. In PyOTA, this means the request doesn't reach the adapter, it
is redirected before.
As a consequence, ``local_pow`` has precedence over the route that is
defined in ``RoutingWrapper``.

``RoutingWrapper`` must be initialized with a default URI/adapter. This
is the adapter that will be used for any command that doesn't have a
route associated with it.
Expand Down
19 changes: 19 additions & 0 deletions docs/api.rst
Expand Up @@ -216,6 +216,25 @@ This method returns a ``dict`` with the following items:
- ``addresses: List[Address]``: The generated address(es). Note that
this value is always a list, even if only one address was generated.

``get_transaction_objects``
---------------------------
Returns a list of transaction objects given a list of transaction hashes.
This is effectively calling ``get_trytes`` and converting the trytes to
transaction objects.
Similar to ``find_transaction_objects``, but input is list of hashes.

Parameters
~~~~~~~~~~

- ``hashes``: List of transaction hashes that should be fetched.

Return
~~~~~~

Returns a ``dict`` with the following items:

- ``transactions: List[Transaction]``: List of transaction objects.

``get_transfers``
-----------------

Expand Down
18 changes: 17 additions & 1 deletion docs/getting_started.rst
Expand Up @@ -6,7 +6,7 @@ Install PyOTA using `pip`:

.. code-block:: bash
pip install pyota[ccurl]
pip install pyota[ccurl,pow]
.. note::

Expand All @@ -15,6 +15,21 @@ Install PyOTA using `pip`:
This extension boosts the performance of certain crypto operations
significantly (speedups of 60x are common).

.. note::

The ``[pow]`` extra installs the optional `PyOTA-PoW extension`_.

This extension makes it possible to perform proof-of-work
(api call ``attach_to_tangle``) locally, without relying on an iota node.
Use the ``local_pow`` parameter at api instantiation:

.. code::
api = Iota('https://nodes.thetangle.org:443', local_pow=True)
Or the ``set_local_pow`` method of the api class to dynamically enable/disable
the local proof-of-work feature.

Getting Started
===============
In order to interact with the IOTA network, you will need access to a node.
Expand Down Expand Up @@ -78,6 +93,7 @@ your API requests so that they contain the necessary authentication metadata.
.. _forum: https://forum.iota.org/
.. _official api: https://docs.iota.org/docs/node-software/0.1/iri/references/api-reference
.. _pyota-ccurl extension: https://pypi.python.org/pypi/PyOTA-CCurl
.. _pyota-pow extension: https://pypi.org/project/PyOTA-PoW/
.. _run your own node.: http://iotasupport.com/headlessnode.shtml
.. _slack: http://slack.iota.org/
.. _use a light wallet node.: http://iotasupport.com/lightwallet.shtml
Expand Down
2 changes: 1 addition & 1 deletion docs/multisig.rst
Expand Up @@ -209,5 +209,5 @@ Never share your private keys

Under no circumstances - other than wanting to reduce the requirements for a multi-signature (see section **How M-of-N works**) - should you share your private keys. Sharing your private keys with others means that they can sign your part of the multi-signature successfully.

.. _example: https://github.com/iotaledger/iota.lib.py/blob/develop/examples/multisig.py
.. _example: https://github.com/iotaledger/iota.py/blob/develop/examples/multisig.py
.. _wiki: https://github.com/iotaledger/wiki/blob/master/multisigs.md
38 changes: 38 additions & 0 deletions examples/local_pow.py
@@ -0,0 +1,38 @@
from __future__ import absolute_import, division, print_function, \
unicode_literals

import iota
from pprint import pprint

# Generate a random seed.
myseed = iota.crypto.types.Seed.random()
# Get an address generator.
addres_generator = iota.crypto.addresses.AddressGenerator(myseed)

# Instantiate API. Note the `local_pow=True` argument.
# This will cause PyOTA to do proof-of-work locally,
# by using the pyota-pow extension package. (if installed)
# Find it at: https://pypi.org/project/PyOTA-PoW/
api = iota.Iota("https://nodes.thetangle.org:443",myseed,local_pow=True)

# Generate two addresses
addys = addres_generator.get_addresses(1, count=2)
pprint('Generated addresses are:')
pprint(addys)

# Preparing transactions
pt = iota.ProposedTransaction(address = iota.Address(addys[0]),
message = iota.TryteString.from_unicode('Tx1: The PoW for this transaction was done by Pyota-Pow.'),
tag = iota.Tag(b'LOCALATTACHINTERFACE99999'), # Up to 27 trytes
value = 0)

pt2 = iota.ProposedTransaction(address = iota.Address(addys[1]),
message = iota.TryteString.from_unicode('Tx2: The PoW for this transaction was done by Pyota-Pow.'),
tag = iota.Tag(b'LOCALATTACHINTERFACE99999'), # Up to 27 trytes
value = 0)

# `send_transfer` will take care of the rest
response = api.send_transfer([pt,pt2])

pprint('Broadcasted bundle:')
pprint(response['bundle'].as_json_compatible())
16 changes: 13 additions & 3 deletions iota/adapter/__init__.py
Expand Up @@ -33,13 +33,13 @@
# (note: ``imp`` is deprecated since Python 3.4 in favor of
# ``importlib``).
# https://docs.python.org/3/library/imp.html
# https://travis-ci.org/iotaledger/iota.lib.py/jobs/191974244
# https://travis-ci.org/iotaledger/iota.py/jobs/191974244
__all__ = map(binary_type, __all__)

API_VERSION = '1'
"""
API protocol version.
https://github.com/iotaledger/iota.lib.py/issues/84
https://github.com/iotaledger/iota.py/issues/84
"""

# Custom types for type hints and docstrings.
Expand Down Expand Up @@ -157,6 +157,7 @@ def __init__(self):
super(BaseAdapter, self).__init__()

self._logger = None # type: Logger
self.local_pow = False # type: boolean

@abstract_method
def get_uri(self):
Expand Down Expand Up @@ -209,6 +210,15 @@ def _log(self, level, message, context=None):
if self._logger:
self._logger.log(level, message, extra={'context': context or {}})

def set_local_pow(self, local_pow):
# type: (bool) -> None
"""
Sets the local_pow attribute of the adapter. If it is true,
attach_to_tangle command calls external interface to perform
pow, instead of sending the request to a node.
By default, it is set to false.
"""
self.local_pow = local_pow

class HttpAdapter(BaseAdapter):
"""
Expand All @@ -219,7 +229,7 @@ class HttpAdapter(BaseAdapter):
DEFAULT_HEADERS = {
'Content-type': 'application/json',

# https://github.com/iotaledger/iota.lib.py/issues/84
# https://github.com/iotaledger/iota.py/issues/84
'X-IOTA-API-Version': API_VERSION,
}
"""
Expand Down
2 changes: 1 addition & 1 deletion iota/adapter/sandbox.py
Expand Up @@ -35,7 +35,7 @@ class SandboxAdapter(HttpAdapter):
completed successfully.
References:
- https://github.com/iotaledger/iota.lib.py/issues/19
- https://github.com/iotaledger/iota.py/issues/19
- https://github.com/iotaledger/documentation/blob/sandbox/source/index.html.md
"""
DEFAULT_POLL_INTERVAL = 15
Expand Down
67 changes: 60 additions & 7 deletions iota/api.py
Expand Up @@ -67,8 +67,8 @@ class StrictIota(object):
"""
commands = discover_commands('iota.commands.core')

def __init__(self, adapter, testnet=False):
# type: (AdapterSpec, bool) -> None
def __init__(self, adapter, testnet=False, local_pow=False):
# type: (AdapterSpec, bool, bool) -> None
"""
:param adapter:
URI string or BaseAdapter instance.
Expand All @@ -82,6 +82,17 @@ def __init__(self, adapter, testnet=False):
adapter = resolve_adapter(adapter)

self.adapter = adapter # type: BaseAdapter
# Note that the `local_pow` parameter is passed to adapter,
# the api class has no notion about it. The reason being,
# that this parameter is used in `AttachToTangeCommand` calls,
# that is called from various api calls (`attach_to_tangle`,
# `send_trytes` or `send_transfer`). Inside `AttachToTangeCommand`,
# we no longer have access to the attributes of the API class, therefore
# `local_pow` needs to be associated with the adapter.
# Logically, `local_pow` will decide if the api call does pow
# via pyota-pow extension, or sends the request to a node.
# But technically, the parameter belongs to the adapter.
self.adapter.set_local_pow(local_pow)
self.testnet = testnet

def __getattr__(self, command):
Expand All @@ -103,13 +114,13 @@ def __getattr__(self, command):
- https://docs.iota.org/docs/node-software/0.1/iri/references/api-reference
"""
# Fix an error when invoking :py:func:`help`.
# https://github.com/iotaledger/iota.lib.py/issues/41
# https://github.com/iotaledger/iota.py/issues/41
if command == '__name__':
# noinspection PyTypeChecker
return None

# Fix an error when invoking dunder methods.
# https://github.com/iotaledger/iota.lib.py/issues/206
# https://github.com/iotaledger/iota.py/issues/206
if command.startswith("__"):
# noinspection PyUnresolvedReferences
return super(StrictIota, self).__getattr__(command)
Expand Down Expand Up @@ -139,6 +150,18 @@ def create_command(self, command):
"""
return CustomCommand(self.adapter, command)

def set_local_pow(self, local_pow):
# type: (bool) -> None
"""
Sets the local_pow attribute of the adapter of the api instance.
If it is true, attach_to_tangle command calls external interface
to perform pow, instead of sending the request to a node.
By default, it is set to false.
This particular method is needed if one wants to change
local_pow behavior dynamically.
"""
self.adapter.set_local_pow(local_pow)

@property
def default_min_weight_magnitude(self):
# type: () -> int
Expand Down Expand Up @@ -527,8 +550,8 @@ class Iota(StrictIota):
"""
commands = discover_commands('iota.commands.extended')

def __init__(self, adapter, seed=None, testnet=False):
# type: (AdapterSpec, Optional[TrytesCompatible], bool) -> None
def __init__(self, adapter, seed=None, testnet=False, local_pow=False):
# type: (AdapterSpec, Optional[TrytesCompatible], bool, bool) -> None
"""
:param seed:
Seed used to generate new addresses.
Expand All @@ -537,7 +560,7 @@ def __init__(self, adapter, seed=None, testnet=False):
.. note::
This value is never transferred to the node/network.
"""
super(Iota, self).__init__(adapter, testnet)
super(Iota, self).__init__(adapter, testnet, local_pow)

self.seed = Seed(seed) if seed else Seed.random()
self.helpers = Helpers(self)
Expand Down Expand Up @@ -877,6 +900,36 @@ def get_new_addresses(
seed=self.seed,
)

def get_transaction_objects(
self,
hashes, # type: [Iterable[TransactionHash]]
):
# type: (...) -> dict
"""
Fetches transaction objects from the Tangle given their
transaction IDs (hashes).
Effectively, this is ``get_trytes`` +
converting the trytes into transaction objects.
Similar to :py:meth:`find_transaction_objects`, but accepts
list of trnsaction hashes as input.
:param hashes:
List of transaction IDs (transaction hashes).
:return:
Dict with the following structure::
{
'transactions': List[Transaction],
List of Transaction objects that match the input.
}
"""
return extended.GetTransactionObjectsCommand(self.adapter)(
hashes=hashes,
)

def get_transfers(self, start=0, stop=None, inclusion_states=False):
# type: (int, Optional[int], bool) -> dict
"""
Expand Down
2 changes: 1 addition & 1 deletion iota/commands/__init__.py
Expand Up @@ -59,7 +59,7 @@ def discover_commands(package, recursively=True):

# Prefix in name module move to function "walk_packages" for fix
# conflict with names importing packages
# Bug https://github.com/iotaledger/iota.lib.py/issues/63
# Bug https://github.com/iotaledger/iota.py/issues/63
sub_package = import_module(name)

# Index any command classes that we find.
Expand Down

0 comments on commit 3057a1b

Please sign in to comment.