Giter VIP home page Giter VIP logo

iota.py's Introduction


The official Python client library for interacting with the Tangle

Developer documentation portal

Auto-generated docs Discord StackExchange MIT license Supported IRI API endpoints Build status

AboutPrerequisitesInstallationGetting startedExamplesSupporting the projectJoining the discussion


About

This is the official Python client library, which allows you to do the following:

  • Create transactions
  • Read transactions
  • Sign transactions
  • Generate addresses

This is beta software, so there may be performance and stability issues. Please report any issues in our issue tracker.

Prerequisites

To install the IOTA Python client library and its dependencies, you need Python version 3.7 or 3.6 installed on your device.

Installation

To download the IOTA Python client library and its dependencies, do the following:

pip install pyota

Installing the optional C extension

PyOTA has an optional C extension that improves the performance of its cryptography features by an average of 60 times.

To install this extension, do the following:

pip install pyota[ccurl]

Installing the optional module for local proof of work

To do proof of work on your local device without relying on a node, you can install the PyOTA-PoW extension module.

To install this extension, use the following command::

pip install pyota[pow]

When you've installed this module, you can use it by passing the local_pow=True argument to your API instance. Doing so will redirect all attach_to_tangle API calls to an interface function in the pow package.

Installing from source

To install the library from the source code on GitHub, do the following:

# Recommended, but not required
Create virtualenv
git clone https://github.com/iotaledger/iota.py.git
pip install -e .

Getting started

After you've installing the library, you can connect to an IRI node to send transactions to it and interact with the ledger. An extended guide can be found on our documentation portal, we strongly recommend you to go here for starting off. A quick starting tutorial is shown below.

To connect to a local IRI node, you can do the following:

from iota import Iota

# Create a new instance of the IOTA API object
# Specify which node to connect to
api = Iota(adapter = 'https://nodes.devnet.iota.org:443')

# Call the `get_node_info()` method for information about the node and the Tangle
response = api.get_node_info()

print(response)

Examples

We have a list of test cases in the examples directory that you can use as a reference when developing apps with IOTA.

Here's how you could send a zero-value transaction, using the library. For the guide, see the documentation portal.

# You don't need a seed to send zero-value transactions
api = Iota('https://nodes.devnet.iota.org:443', devnet=True)

# Define a message to send.
# This message must include only ASCII characters.
message = TryteString.from_unicode('Hello world')

# Define an address.
# This does not need to belong to anyone or have IOTA tokens.
# It must only contain a maximum of 81 trytes
# or 90 trytes with a valid checksum
address = 'ZLGVEQ9JUZZWCZXLWVNTHBDX9G9KZTJP9VEERIIFHY9SIQKYBVAHIMLHXPQVE9IXFDDXNHQINXJDRPFDXNYVAPLZAW'

# Define a zero-value transaction object
# that sends the message to the address
tx = ProposedTransaction(
    address = Address(address),
    message = message,
    value = 0
)

# Create a bundle from the `ProposedTransaction` object
# and send the transaction to the node
result = api.send_transfer(transfers=[tx])

print('Bundle: ')

print(result['bundle'].hash)

Supporting the project

If the IOTA Python client library has been useful to you and you feel like contributing, consider posting a bug report, feature request or a pull request.

We have some basic contribution guidelines to keep our code base stable and consistent.

Running test cases

To run test, do the following:

python setup.py test

PyOTA is also compatible with tox, which will run the unit tests in different virtual environments (one for each supported version of Python).

To run the unit tests, it is recommended that you use the -p argument. This speeds up the tests by running them in parallel.

Install PyOTA with the test-runner extra to set up the necessary dependencies, and then you can run the tests with the tox command::

pip install -e .[test-runner]
tox -v -p all

Building the autogenerated documentation

The autogenerated documentation can be generated on your local device by doing the following:

# Install extra dependencies (you only have to do this once)
pip install .[docs-builder]
cd docs
# Build the documentation::
make html

Joining the discussion

If you want to get involved in the community, need help with getting set up, have any issues related with the library or just want to discuss blockchain, distributed ledgers, and IoT with other people, feel free to join our Discord.

iota.py's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

iota.py's Issues

Seed.__init__ should raise a warning when the seed is longer than 81 trytes

Beyond 81 trytes, you can't increase the security of your seed — not even against brute force attacks (see Why aren't seeds longer than 81 trytes more secure? for more info).

We should still allow users to create seeds longer than 81 trytes, just in case, but this should cause a warning to be raised. The error message should include a link to the above forum post.

Example:

# 81 trytes; this is OK.
seed = Seed(b'9' * Hash.LEN)

# 82 trytes; this should raise a warning (note: not an exception)
seed = Seed(b'9' * (Hash.LEN + 1))

# If the user is sure they know what they are doing, they can suppress the warning.
with warnings.catch_warnings():
  warnings.simplefilter('ignore')
  seed = Seed(b'9' * (Hash.LEN + 1))

Note: Do not strip trailing 9s when checking the length.

Neighbor URIs must use udp protocol

The IRI implementation only supports udp:// URIs for neighbors. If you send an addNeighbors API request containing an http:// URI, that URI will be silently ignored.

When validating an addNeighbors or removeNeighbors request, treat any URIs that don't use udp:// protocol as invalid.

Need documentation explaining how to handle snapshots

After a snapshot, previous transactions are lost. This means that methods such as get_account_data, get_new_addresses, get_transfers, etc. can no longer identify "used" addresses correctly.

At this time, the only way to properly identify "pre-snapshot" addresses is to keep track of them before the snapshot, then be sure to set the correct starting index (for key generation) when calling API methods.

  1. Determine which API commands are impacted by snapshots (basically anything that relies on iter_used_addresses).
  2. Update the documentation for each of these API commands with more info about how they are impacted by snapshots.

transfer = ProposedTransaction(...) naming convention doesn't follow other libs

both in iota.lib.js and iota.lib.java there are explicit transfer objects.
iota.lib.js
iota.lib.java

however, in iota.lib.py these objects are constructed with iota.ProposedTransaction(...), which is also used as an intermediary representation of transactions & bundles.
from examples:
https://github.com/iotaledger/iota.lib.py/blob/master/examples/send_transfer.py#L24

this is confusing for users moving from other library implementations. like myself. :)


I propose a new class named Transfer, that inherits from ProposedTransaction and is functionally the same, but adheres to the naming conventions of the other libs. (without breaking code that already uses ProposedTransaction of course).

Incorrect attribute names in GetBalancesCommand response (using sandbox example script)

PyOTA 1.1.3

Python 2.7.10

Mac OS El Capitan 10.11.6

Description:
Running sandbox example. iota.send_transfer gives following error: TypeError: 'NoneType' object is not iterable

Traceback:
Traceback (most recent call last):
File "sandbox.py", line 51, in
message = TryteString.from_string('Hello, Tangle!'),
File "/Users/johngrant/Downloads/iota/env/lib/python2.7/site-packages/iota/api.py", line 822, in send_transfer
minWeightMagnitude = min_weight_magnitude,
File "/Users/johngrant/Downloads/iota/env/lib/python2.7/site-packages/iota/commands/init.py", line 122, in call
self.response = self._execute(self.request)
File "/Users/johngrant/Downloads/iota/env/lib/python2.7/site-packages/iota/commands/extended/send_transfer.py", line 46, in _execute
transfers = transfers,
File "/Users/johngrant/Downloads/iota/env/lib/python2.7/site-packages/iota/commands/init.py", line 122, in call
self.response = self._execute(self.request)
File "/Users/johngrant/Downloads/iota/env/lib/python2.7/site-packages/iota/commands/extended/prepare_transfer.py", line 54, in _execute
threshold = want_to_spend,
File "/Users/johngrant/Downloads/iota/env/lib/python2.7/site-packages/iota/commands/init.py", line 122, in call
self.response = self._execute(self.request)
File "/Users/johngrant/Downloads/iota/env/lib/python2.7/site-packages/iota/commands/extended/get_inputs.py", line 62, in _execute
for i, balance in enumerate(gb_response['balances']):
TypeError: 'NoneType' object is not iterable

Possible fix? (Creating a Pull request)
In get_inputs.py, Line 51, gb_response = GetBalancesCommand( ) is returning: {u'MilestoneIndex': 123423, …. u'Duration': 0, u'Balances': [0, 0, 41, 0, 0, 0]}

Line 62 uses: enumerate(gb_response['balances'])

Changing 'balances' to 'Balances' seems to fix the problem.

segfault on pip install pyota

Linux lappy 4.10.0-21-generic #23-Ubuntu SMP Fri Apr 28 16:14:22 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

lotus@lappy:~$ pip --version
pip 9.0.1 from /usr/lib/python2.7/dist-packages (python 2.7)


lotus@lappy:~$ python
Python 2.7.13 (default, Jan 19 2017, 14:48:08) 
[GCC 6.3.0 20170118] on linux2

lotus@lappy:~$ pip install  pyota
Collecting pyota
  Using cached PyOTA-2.0.0-py2.py3-none-any.whl
Collecting filters (from pyota)
  Using cached filters-1.3.2-py2.py3-none-any.whl
Collecting pysha3 (from pyota)
  Using cached pysha3-1.0.2-cp27-cp27mu-manylinux1_x86_64.whl
Collecting requests[security]>=2.4.1 (from pyota)
  Using cached requests-2.18.4-py2.py3-none-any.whl
Collecting typing; python_version < "3.0" (from pyota)
  Using cached typing-3.6.2-py2-none-any.whl
Collecting six (from pyota)
  Using cached six-1.11.0-py2.py3-none-any.whl
Collecting regex (from filters->pyota)
Collecting py2casefold; python_version < "3.0" (from filters->pyota)
  Using cached py2casefold-0.2.1-py2-none-any.whl
Collecting pytz (from filters->pyota)
  Using cached pytz-2017.2-py2.py3-none-any.whl
Collecting class-registry (from filters->pyota)
  Using cached class_registry-2.1.0-py2.py3-none-any.whl
Collecting python-dateutil (from filters->pyota)
  Using cached python_dateutil-2.6.1-py2.py3-none-any.whl
Collecting chardet<3.1.0,>=3.0.2 (from requests[security]>=2.4.1->pyota)
  Using cached chardet-3.0.4-py2.py3-none-any.whl
Collecting certifi>=2017.4.17 (from requests[security]>=2.4.1->pyota)
  Using cached certifi-2017.7.27.1-py2.py3-none-any.whl
Collecting urllib3<1.23,>=1.21.1 (from requests[security]>=2.4.1->pyota)
  Using cached urllib3-1.22-py2.py3-none-any.whl
Collecting idna<2.7,>=2.5 (from requests[security]>=2.4.1->pyota)
  Using cached idna-2.6-py2.py3-none-any.whl
Collecting pyOpenSSL>=0.14; extra == "security" (from requests[security]>=2.4.1->pyota)
  Using cached pyOpenSSL-17.3.0-py2.py3-none-any.whl
Collecting cryptography>=1.3.4; extra == "security" (from requests[security]>=2.4.1->pyota)
  Using cached cryptography-2.1.1-cp27-cp27mu-manylinux1_x86_64.whl
Collecting cffi>=1.7; platform_python_implementation != "PyPy" (from cryptography>=1.3.4; extra == "security"->requests[security]>=2.4.1->pyota)
  Using cached cffi-1.11.2-cp27-cp27mu-manylinux1_x86_64.whl
Collecting enum34; python_version < "3" (from cryptography>=1.3.4; extra == "security"->requests[security]>=2.4.1->pyota)
  Using cached enum34-1.1.6-py2-none-any.whl
Collecting ipaddress; python_version < "3" (from cryptography>=1.3.4; extra == "security"->requests[security]>=2.4.1->pyota)
  Using cached ipaddress-1.0.18-py2-none-any.whl
Collecting asn1crypto>=0.21.0 (from cryptography>=1.3.4; extra == "security"->requests[security]>=2.4.1->pyota)
  Using cached asn1crypto-0.23.0-py2.py3-none-any.whl
Collecting pycparser (from cffi>=1.7; platform_python_implementation != "PyPy"->cryptography>=1.3.4; extra == "security"->requests[security]>=2.4.1->pyota)
Installing collected packages: regex, py2casefold, six, pytz, typing, class-registry, python-dateutil, filters, pysha3, chardet, certifi, urllib3, idna, pycparser, cffi, enum34, ipaddress, asn1crypto, cryptography, pyOpenSSL, requests, pyota
Successfully installed asn1crypto-0.23.0 certifi-2017.7.27.1 cffi-1.11.2 chardet-3.0.4 class-registry-2.1.0 cryptography-2.1.1 enum34-1.1.6 filters-1.3.2 idna-2.6 ipaddress-1.0.18 py2casefold-0.2.1 pyOpenSSL-17.3.0 pycparser-2.18 pyota-2.0.0 pysha3-1.0.2 python-dateutil-2.6.1 pytz-2017.2 regex-2017.9.23 requests-2.18.4 six-1.11.0 typing-3.6.2 urllib3-1.22
Segmentation fault (core dumped)




lotus@lappy:~$ pip install pyota
Collecting pyota
  Using cached PyOTA-2.0.0-py2.py3-none-any.whl
Collecting filters (from pyota)
  Using cached filters-1.3.2-py2.py3-none-any.whl
Collecting pysha3 (from pyota)
  Using cached pysha3-1.0.2-cp27-cp27mu-manylinux1_x86_64.whl
Collecting requests[security]>=2.4.1 (from pyota)
  Using cached requests-2.18.4-py2.py3-none-any.whl
Collecting typing; python_version < "3.0" (from pyota)
  Using cached typing-3.6.2-py2-none-any.whl
Collecting six (from pyota)
  Using cached six-1.11.0-py2.py3-none-any.whl
Collecting regex (from filters->pyota)
Collecting py2casefold; python_version < "3.0" (from filters->pyota)
  Using cached py2casefold-0.2.1-py2-none-any.whl
Collecting pytz (from filters->pyota)
  Using cached pytz-2017.2-py2.py3-none-any.whl
Collecting class-registry (from filters->pyota)
  Using cached class_registry-2.1.0-py2.py3-none-any.whl
Collecting python-dateutil (from filters->pyota)
  Using cached python_dateutil-2.6.1-py2.py3-none-any.whl
Collecting chardet<3.1.0,>=3.0.2 (from requests[security]>=2.4.1->pyota)
  Using cached chardet-3.0.4-py2.py3-none-any.whl
Collecting certifi>=2017.4.17 (from requests[security]>=2.4.1->pyota)
  Using cached certifi-2017.7.27.1-py2.py3-none-any.whl
Collecting urllib3<1.23,>=1.21.1 (from requests[security]>=2.4.1->pyota)
  Using cached urllib3-1.22-py2.py3-none-any.whl
Collecting idna<2.7,>=2.5 (from requests[security]>=2.4.1->pyota)
  Using cached idna-2.6-py2.py3-none-any.whl
Collecting pyOpenSSL>=0.14; extra == "security" (from requests[security]>=2.4.1->pyota)
  Using cached pyOpenSSL-17.3.0-py2.py3-none-any.whl
Collecting cryptography>=1.3.4; extra == "security" (from requests[security]>=2.4.1->pyota)
  Using cached cryptography-2.1.1-cp27-cp27mu-manylinux1_x86_64.whl
Collecting cffi>=1.7; platform_python_implementation != "PyPy" (from cryptography>=1.3.4; extra == "security"->requests[security]>=2.4.1->pyota)
  Using cached cffi-1.11.2-cp27-cp27mu-manylinux1_x86_64.whl
Collecting enum34; python_version < "3" (from cryptography>=1.3.4; extra == "security"->requests[security]>=2.4.1->pyota)
  Using cached enum34-1.1.6-py2-none-any.whl
Collecting ipaddress; python_version < "3" (from cryptography>=1.3.4; extra == "security"->requests[security]>=2.4.1->pyota)
  Using cached ipaddress-1.0.18-py2-none-any.whl
Collecting asn1crypto>=0.21.0 (from cryptography>=1.3.4; extra == "security"->requests[security]>=2.4.1->pyota)
  Using cached asn1crypto-0.23.0-py2.py3-none-any.whl
Collecting pycparser (from cffi>=1.7; platform_python_implementation != "PyPy"->cryptography>=1.3.4; extra == "security"->requests[security]>=2.4.1->pyota)
Installing collected packages: regex, py2casefold, six, pytz, typing, class-registry, python-dateutil, filters, pysha3, chardet, certifi, urllib3, idna, pycparser, cffi, enum34, ipaddress, asn1crypto, cryptography, pyOpenSSL, requests, pyota
Successfully installed asn1crypto-0.23.0 certifi-2017.7.27.1 cffi-1.11.2 chardet-3.0.4 class-registry-2.1.0 cryptography-2.1.1 enum34-1.1.6 filters-1.3.2 idna-2.6 ipaddress-1.0.18 py2casefold-0.2.1 pyOpenSSL-17.3.0 pycparser-2.18 pyota-2.0.0 pysha3-1.0.2 python-dateutil-2.6.1 pytz-2017.2 regex-2017.9.23 requests-2.18.4 six-1.11.0 typing-3.6.2 urllib3-1.22
Segmentation fault (core dumped)

Address generate - checksum missing

Hi I created IOTA address from seed using below code. But generated address are 81 char length. cannot able to send IOTA to those address. checksum is missing. how to generate Address with check sum in pyota?

from iota import Iota
seed = 'seed here'
api = Iota('https://n1.iota.nu:443', seed=seed)
addresses = api.get_new_addresses(index=0, count=2)
for key in addresses:
    for addr in addresses[key]:
        print addr

Detect testnet mode automatically if not specified

When StrictIota.__init__ is invoked, permit the developer to specify testnet=None. In this case, the API instance will issue a getNodeInfo command and detect the IRI version automatically.

Requirements:

  • Convert StrictIota.testnet into a @property.
  • When testnet is invoked, check for a cached value first (e.g. if self._testnet is None:).
    • If there is no cached value, issue a get_node_info.
  • The user can still provide a testnet arg to StrictIota.__init__, but this sets the cached value explicitly.
  • Any time StrictIota.get_node_info is invoked (even outside the context of caching the testnet flag), automatically cache the testnet flag from the response (if not already cached) before returning the result.

Add support for IPv6 neighbor/node URIs

IRI supports IPv6 addresses, so PyOTA should, too (:

Example:

http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]:14265

Note that IPv6 addresses can be abbreviated. For example, the following addresses are equivalent:

http://[fe80:0:0:0:200:f8ff:fe21:67cf]:14265
http://[fe80::200:f8ff:fe21:67cf]:14265

Seed.random().as_string() throws TrytesDecodeError

Executing Seed.random().as_string() and Seed.random().as_bytes() raises TrytesDecodeError.

Traceback (most recent call last):
  File "/Users/jinnerbi/.pyenv/versions/working_env/lib/python3.5/site-packages/iota/codecs.py", line 147, in decode
    + (self.index[second] * len(self.index))
ValueError: byte must be in range(0, 256)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/jinnerbi/Development/_projects/iota_mail/iota_mail/wallet/api/iota_api.py", line 55, in <module>
    Seed.random().as_string()
  File "/Users/jinnerbi/.pyenv/versions/working_env/lib/python3.5/site-packages/iota/types.py", line 529, in as_string
    return decode(trytes, 'trytes', errors).decode('utf-8', errors)
  File "/Users/jinnerbi/.pyenv/versions/working_env/lib/python3.5/site-packages/iota/codecs.py", line 165, in decode
    'input': input,
iota.codecs.TrytesDecodeError: 'trytes' codec can't decode trytes BT at position 4-5: ordinal not in range(255)

The calculation in lines https://github.com/iotaledger/iota.lib.py/blob/master/iota/codecs.py#L145-L148 exceeds the valid range for bytes.

Add Multisig Support

Add support for multisig transactions:
https://github.com/iotaledger/wiki/blob/master/multisigs.md

Notes for documentation:

  • A bundle may contain multiple multisig inputs. For parity with the JS lib, PyOTA will only support creating a bundle with a single multisig input.
  • A bundle may contain multisig and non-multisig inputs. For parity with the JS lib, PyOTA will not support combining multisig and non-multisig inputs in a single bundle.
  • If there are any unspent inputs, the change address must be specified explicitly.

Max Polling Attempts setting for SandboxAdapter

Imagine a scenario where a sandbox node gets stuck or severely overloaded, and a job remains in QUEUED or RUNNING for a really long time.

As it is implemented currently, SandboxAdapter will happily poll every 15 seconds, until the end of the universe, if necessary.

Add a polling timeout argument to SandboxAdapter.__init__ that will cause it to raise an exception if a job hasn't completed after x number of polling requests.

Port documentation to Sphinx

We need your help to port the existing documentation from Markdown to reStructuredText so that we can publish it on ReadTheDocs!

The Markdown files are located here:
https://github.com/iotaledger/documentation/tree/iota.lib.py/1.2.x/source/includes

These need to be copied into the PyOTA repository and converted to reStructuredText here:
https://github.com/iotaledger/iota.lib.py/tree/develop/docs

Note: This is a big project, and multiple people might end up working on this. Please be sure to post here so that you can coordinate with others, to avoid duplicating work.

If you are not familiar with Sphinx and/or reStructuredText, here's a quickstart:

  1. Install PyOTA locally.
  2. pip install sphinx
  3. cd docs
  4. make html
    • This will generate the static HTML documentation. You can then open docs/_build/html/index.html in your browser to see what it will (sort of) look like when it is published to RTD.
  5. To make changes to the documentation, edit the corresponding .rst file, and then do another make html.

Important: If you add a new .rst file, be sure to update the toctree directive in index.rst!

Here are some references for reStructuredText directives and markup syntax (once you get used to it, you will never want to go back to Markdown 😸):

You can also use this online rst editor to try stuff out:
http://rst.ninjs.org/

Installation

I tried all of your install description but nothing worked. Especially pip doesn't work.

Exception when invoking `help(iota)` in examples/shell.py

  1. Launch examples/shell.py.
  2. Type help(iota).
In [3]: help(iota)
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
pyota/iota/api.py in __getattr__(self, command)
     97     try:
---> 98       command_class = self.commands[command]
     99     except KeyError:

KeyError: '__name__'

During handling of the above exception, another exception occurred:

InvalidCommand                            Traceback (most recent call last)
pyota/examples/shell.py in <module>()
----> 1 help(iota)

python3.6/site.py in __call__(self, *args, **kwds)
    503     def __call__(self, *args, **kwds):
    504         import pydoc
--> 505         return pydoc.help(*args, **kwds)
    506
    507 def sethelper():

python3.6/pydoc.py in __call__(self, request)
   1856     def __call__(self, request=_GoInteractive):
   1857         if request is not self._GoInteractive:
-> 1858             self.help(request)
   1859         else:
   1860             self.intro()

python3.6/pydoc.py in help(self, request)
   1909             else: doc(str, 'Help on %s:', output=self._output)
   1910         elif isinstance(request, Helper): self()
-> 1911         else: doc(request, 'Help on %s:', output=self._output)
   1912         self.output.write('\n')
   1913

python3.6/pydoc.py in doc(thing, title, forceload, output)
   1643     try:
   1644         if output is None:
-> 1645             pager(render_doc(thing, title, forceload))
   1646         else:
   1647             output.write(render_doc(thing, title, forceload, plaintext))

python3.6/pydoc.py in render_doc(thing, title, forceload, renderer)
   1618     if renderer is None:
   1619         renderer = text
-> 1620     object, name = resolve(thing, forceload)
   1621     desc = describe(object)
   1622     module = inspect.getmodule(object)

python3.6/pydoc.py in resolve(thing, forceload)
   1610         return object, thing
   1611     else:
-> 1612         name = getattr(thing, '__name__', None)
   1613         return thing, name if isinstance(name, str) else None
   1614

pyota/iota/api.py in __getattr__(self, command)
    101         '{cls} does not support {command!r} command.'.format(
    102           cls     = type(self).__name__,
--> 103           command = command,
    104         ),
    105       )

InvalidCommand: Iota does not support '__name__' command.

udp is not a valid protocol for `HttpAdapter`

tl;dr HttpAdapter does not actually send API requests via UDP, so it should not accept udp:// URIs.

udp:// URIs are only valid as neighbor URIs (i.e., as inputs for addNeighbors and removeNeighbors), because the node uses UDP for communication with other nodes.

The API, however, is an HTTP service; it doesn't use UDP, so HttpAdapter should not accept udp:// URIs.

Conflict with names when importing library.

I import Pyota in my django project and get exception:

 File "/home/user/venv/BCTC/local/lib/python2.7/site-packages/django/conf/urls/__init__.py", line 50, in include
   urlconf_module = import_module(urlconf_module)
 File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
   __import__(name)
 File "/home/user/PycharmProjects/BCTC/BCTClient/BCTClient/iotaapp/urls.py", line 6, in <module>
   from .views import CreateIotaAccountView
 File "/home/user/PycharmProjects/BCTC/BCTClient/BCTClient/iotaapp/views.py", line 14, in <module>
   from iota.crypto.types import Seed
 File "/home/user/venv/BCTC/src/pyota/iota/__init__.py", line 39, in <module>
   from .api import *
 File "/home/user/venv/BCTC/src/pyota/iota/api.py", line 10, in <module>
   from iota.commands import BaseCommand, CustomCommand, core, discover_commands, extended
 File "/home/user/venv/BCTC/src/pyota/iota/commands/__init__.py", line 347, in <module>
   discover_commands(__name__)
 File "/home/user/venv/BCTC/src/pyota/iota/commands/__init__.py", line 66, in discover_commands
   sub_package = import_module(package.__name__ + '.' + name)
 File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
   __import__(name)
ImportError: No module named admin

In Pyota isn't package "admin", but in my project there is django application "core" and it have admin.py.

MemoryAddressCache is not thread-safe

MemoryAddressCache is designed to be injected globally, which means it needs to be thread-safe, and we need to be extra clever in how we go about it:

  • Add an acquire_lock method to the cache.
  • AddressGenerator should acquire lock before it generates a new address (i.e., after a cache miss). This is necessary both to prevent a cache stampede, and to ensure that the cached address doesn't get overwritten.

hello_world.py fails out-of-the-box (defaults udp://)

In example/hello_world.py - the default URI is udp://localhost:14265/
This will cause an error:

File "/home/alon/iota/iota.lib.py/iota/adapter/__init__.py", line 97, in resolve_adapter
    'uri':    uri,
iota.adapter.InvalidUri: Unrecognized protocol u'udp'.

should be: default = 'http://localhost:24265/'
It's probably a typo/left-over, but is the first user's experience.

Add Sandbox Support

Create a SandboxAdapter that enables developers to connect to remote nodes safely.

class SandboxAdapter(HttpAdapter):
  def configure(uri, token):
    # type: (Text, Text) -> SandboxAdapter
    ...

  def __init__(token, host, port=DEFAULT_PORT, path='/commands', poll_interval=15, sandbox_commands={'attachToTangle'}):
    # type: (Text, int, Text, int, Iterable[Text]) -> None
    ...

For non-sandbox commands:

  1. Add header: Authorization: token {self.token}
  2. Append the command name to the URI (e.g., https://sandbox.iotatoken.com/api/v1/commands/attachToTangle).
  3. Return node response like normal.

For sandbox commands:

  1. Add header: Authorization: token {self.token}
  2. Append the command name to the URI (e.g., https://sandbox.iotatoken.com/api/v1/commands/attachToTangle).
  3. Response will contain job info.
    https://github.com/iotaledger/documentation/blob/sandbox/source/index.html.md#attachtotangle
  4. Poll every {self.interval} to see if the job has completed.
    https://github.com/iotaledger/documentation/blob/sandbox/source/index.html.md#jobs

Documentation

PyOTA needs documentation badly 😭

Outline

  • Getting Started
    • Sandbox
  • Basic Concepts (link to IOTA core documentation)
  • Types Reference
    • TryteString
    • Transaction Types
    • Bundle Types
  • Generating Addresses
    • Using the API
    • Using AddressGenerator
    • Caches
  • Adapters and Wrappers
  • API Command Reference
    • Core
    • Extended
  • Command Objects (Iota.custom_command, Iota.__getattr__)
  • Crypto
    • Curl
    • Keys

Method to check to see if a transaction can be reattached to the Tangle

From https://github.com/iotaledger/iota.lib.js#isreattachable (with a few modifications):

isReattachable

This API function helps you to determine whether you should replay a transaction or make a completely new transaction with a different seed. What this function does, is it takes one or more input addresses (i.e. from spent transactions) as input and then checks whether any transactions with a value transferred are confirmed. If yes, it means that this input address has already been successfully used in a different transaction and as such you should no longer replay the transaction.

Input

api = Iota(...)
ir_result = api.is_reattachable(addresses)
  • addresses: Iterable[Address] input addresses from the transaction(s).

Returns

{'reattachable': List[bool]} — similar to getBalances, the result contains a list of booleans corresponding to the addresses that were provided in the request.

Python 2.7 does not install typing package

When installing PyOTA on a Python 2.7 virtualenv, the typing package does not get installed:

(test) [499][~] python --version
Python 2.7.13
(test) [500][~] pip install --pre pyota
...
Installing collected packages: six, python-dateutil, regex, pytz, filters, requests, pyota
Successfully installed filters-1.1.4 pyota-1.0.0b3 python-dateutil-2.6.0 pytz-2016.10 regex-2016.12.27 requests-2.12.4 six-1.10.0

Incorrect type for `milestone` in `getBalances` response

In the response from getBalances, milestone is a string, but it should be a TransactionHash:

{u'balances': [u'0'],
 u'duration': 367,
 u'milestone': u'JAJPSCFT9JP9JXJLKNTZDJXTYOCGJJBBVUYSZB9XLIBNXCUNK9UDHFJEBVHLNZR9ZPYVZXJCWZA999999',
 u'milestoneIndex': 28050}

Seed.random should not generate seeds longer than 81 trytes

Seed.random generates 82-tryte seeds by default. However, beyond 81 trytes, you can't increase the security of your seed — not even against brute force attacks (see Why aren't seeds longer than 81 trytes more secure? for more info).

Using urandom to generate random bytes is a clever approach, but because we have to translate bytes into trytes, we are limited to generating even numbers of trytes. An alternate approach is needed.

Modify Seed.random so that it generates exactly 81 trytes each time:

  • Remove the length argument.
  • Use a different method of generating random trytes (see http://stackoverflow.com/a/2257449/ for some ideas — note that using a CSPRNG is mandatory!).

`BaseAddressCache._gen_cache_key` is too fast

BaseAddressCache._gen_cache_key uses a single iteration of SHA-256, which is too fast to be secure against brute-force / rainbow table attacks.

An algo like PBKDF2 or bcrypt would be far more secure (although the salt would need to be constant, since the resulting hashes need to function as lookup keys).

See https://docs.python.org/3/library/hashlib.html#hashlib.pbkdf2_hmac for more info.

Interestingly, Python 3.6 introduces an scrypt implementation into stdlib; might be interesting to allow the user to specify which algo they want to use when initializing the cache.

Set up private Tangle for functional testing

Many of PyOTA's unit test rely on heavy use of mocks, which reduces the value of the test coverage significantly.

A more robust approach would be to set up automated functional tests, on a private Tangle. Per conversation with Paul H on Slack, we should be able to set this up without too much difficulty:

  1. Clone the repo.
  2. Check out the latest public-testnet-* branch.
  3. Modify the snapshot file.
  4. Disable snapshot signature validation.
  5. mvn clean compile package
  6. Run the node with --testnet flag.
  7. ???
  8. Profit!!!

Set up a proof of concept with a private Tangle and a script that transfers IOTAs between two addresses successfully. We will iterate on it from there and create a comprehensive functional test suite 😺

Wrapper to route commands to different nodes

Add a RouterWrapper that can route specific commands to different nodes.

For example, this could be used to route attachToTangle to a local node, but all other commands go to a remote node.

Example:

iota = Iota(RouterWrapper(
  default_adapter = 'http://light-wallet.iota:14265',
  routes = {
    'http://localhost:14265': ['attachToTangle'],
  },
))

Bonus Points

  • Add a --pow-uri option to examples/shell.py.

Curl squeeze should match absorb

Currently, squeeze only processes a single hash worth of trits. However, this is incorrect; it should process each hash from the input (with a transform in between each hash), just like absorb.

Also, the "make sure the input can hold at least 1 hash worth of trits" is incorrect; the caller is responsible for ensuring that the input has the correct length.

This isn't technically a bug (yet), but it will cause problems down the road.

Support https node URIs

Although IRI only listens for API requests on the loopback interface, some developers opt to set up a reverse proxy.

Add support for connecting to a node via HTTPS.

Convert PyCurl into a wrapper for CCurl

I think by this point we've squeezed about as much performance as we can out of PyCurl (which unfortunately is not very much). In the long run, the only way PyOTA is going to achieve a competitive level of performance is if we offload curl onto a C extension — i.e., something similar to pyota-ccurl.

Replace the pure-Python curl implementation with a wrapper for a C extension based on / wrapper for ccurl.

ccurl is compatible with lots of OS/architecture combinations, and it should be possible to write a little bit of glue code that works in both Python 2 and 3.

Kerl Integration

With the latest snapshot, IOTA switched to a new hashing algorithm, named Kerl:

Integrate this new hashing algorithm into PyOTA:

Functionality Curl-P-27 Curl-P-81 Kerl
Address generation V^
Signature generation V
Signature verification V
Essence calculation (bundleHash) V
Proof of Work V
Transaction Hash V
Milestone verification V

Curl-P-N: N number of rounds

^ CheckSums are calculated using the last 9 trytes.

todo

  • Address generation
    • Implementation
    • Rewrite unit tests
  • Signature generation
    • Implementation
    • Rewrite unit tests
  • Signature verification (new)
    • Implementation
    • Rewrite unit tests
  • Bundle hash
    • Implementation
    • Rewrite unit tests
  • N/A Proof of work
  • Transaction hash
    • Implementation
    • Rewrite unit tests
  • N/A Milestone verification

Additional issues:

  • Incorrect private keys when seed is longer than 81 trytes
  • Multisig integration
  • Refactor unit tests for private key digests
  • Remove legacy bundle validation
  • Replace Curl-P-27 with Curl-P-81

getNewAddresses generates incorrect addresses

Using PyOTA:

In [1]: import iota

In [2]: iota.__version__
Out[2]: '1.0.0b4'

In [3]: api = iota.Iota('http://localhost:14265', b'TESTVALUE9DONTUSEINPRODUCTION99999QANDEFBGD9SHSHDBWCDFT9B9YDMAABCCXBXHAFUEPEIBAHW')

In [4]: api.get_new_addresses(index=0, count=1)
Out[4]: [Address(b'ASBXGZKCSBKKLGYSRAILPVJZOMRFYZWBCYJRIVNWKRPAMEVSVANUVZS9J9CMTXVWTVNAYDRBKVXLAISYK')]

Using JS lib:

> var IOTA = require('iota.lib.js');
undefined
> var iota = new IOTA();
undefined
> iota.api.getNewAddress('TESTVALUE9DONTUSEINPRODUCTION99999QANDEFBGD9SHSHDBWCDFT9B9YDMAABCCXBXHAFUEPEIBAHW', {'index':0, 'total':1}, function(error, addresses) { if(error){ console.error(error); } else { console.log(addresses); }});
[ 'NRQOZF9LIKZUZNJWPFLVDULBEJEX9CPSWMFHJFJIYCEQORTERJLEACIIYKZWJJVQXETK9UDFY99SCF9XL' ]
undefined

Add support for configurable address security level

Add an optional security parameter to Iota.__init__ which sets the number of iterations to use when generating new addresses.

This value effectively overrides iota.crypto.addresses.AddressGenerator.DIGEST_ITERATIONS.

Add unit converter for transaction values

IOTA utilizes the Standard system of Units. See below for all available units:

'i'   :   1,
'Ki'  :   1000,
'Mi'  :   1000000,
'Gi'  :   1000000000,
'Ti'  :   1000000000000,
'Pi'  :   1000000000000000

Add support for specifying units in transactions. E.g.:

iota.send_transfer(
  transactions = [
    ProposedTransaction(
      value = '86.2 Mi',
      ...
    ),
    ...
  ],
  ...
)

Add `hash` argument to `Transaction.from_tryte_string`

The testnet IRI provides an --export setting which enables users to download raw trytes along with the corresponding transaction hashes.

When loading these values into PyOTA using Transaction.from_tryte_string, it is not necessary for PyOTA to recompute the transaction hash, since the user will be able to provide the corresponding hash.

Modify the signature of Transaction.from_tryte_string to include an optional hash argument:

  • If null, compute the transaction hash like normal.
  • If not null, use that as the transaction hash and skip curl.

IRI version compatibility check at startup

Add a method to StrictIota that will perform a compatibility check (i.e., verify IRI version >= 1.1.2.4 (see https://github.com/iotaledger/iota.lib.py/releases/tag/1.1.0 for more info)).

If the compatibility check fails, raise an exception. If the user wants to connect to a node running an old version of the software, they can specify it in the __init__ method (see note below).

Notes:

  • Add an optional parameter to __init__ to enable/configure the automatic compat check.
    • By default, this is set to a constant.
    • Set to None to disable the check.
    • Set to a version string to specify the version number to use for comparison.
  • Defer this check until the first time the code initiates a request, and piggyback if the request is getNodeInfo.

Examples:

>>> iota = Iota(...)
>>> iota.get_transfers(...)
# Issue `getNodeInfo` command here and perform compatibility check.
>>> iota = Iota(...)
>>> iota.get_node_info()
# Execute `getNodeInfo` as normal, but perform compatibility check before returning result.
>>> iota = Iota(..., require_node_version=None)
>>> iota.get_transfers(...)
# No compatibility check performed.
>>> iota = Iota(..., require_node_version='1.2.1')
>>> iota.get_transfers(...)
# Issue `getNodeInfo` and check for IRI version >= 1.2.1 before continuing.

Balances in `getBalances` response are strings, s/b integers

Balances in getBalances response are strings, but they should be integers:

{u'balances': [u'0'], # D'oh!
 u'duration': 367,
 u'milestone': u'JAJPSCFT9JP9JXJLKNTZDJXTYOCGJJBBVUYSZB9XLIBNXCUNK9UDHFJEBVHLNZR9ZPYVZXJCWZA999999',
 u'milestoneIndex': 28050}

`get_transfers` should identify "my" transactions

get_transfers returns all of the bundles that include transactions that reference one of my addresses, but there's no (efficient) way to scan the bundles to find just the transactions that impact my wallet balance.

Idea: Add list of matched addresses to get_transfers output.

TryteString.as_bytes() does not work as expected

Expected result (or similar):

>>> iota.TryteString(b'ABABZZDD99').as_bytes()
(30, [55,178,248,107,12,0])

Actual result:

>>> iota.TryteString(b'ABABZZDD99').as_bytes()
Traceback (most recent call last):
  File "iota.lib.py/iota/codecs.py", line 147, in decode
    + (self.index[second] * len(self.index))
ValueError: byte must be in range(0, 256)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "iota.lib.py/iota/types.py", line 421, in as_bytes
    return decode(self._trytes, 'trytes', errors)
  File "iota.lib.py/iota/codecs.py", line 165, in decode
    'input': input,
iota.codecs.TrytesDecodeError: 'trytes' codec can't decode trytes ZZ at position 4-5: ordinal not in range(255)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.