This repository has been archived by the owner on Jan 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #102 from QuantumDamage/develop
Ported docs from md to rst #78
- Loading branch information
Showing
5 changed files
with
991 additions
and
225 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
Adapters and Wrappers | ||
===================== | ||
|
||
The ``Iota`` class defines the API methods that are available for | ||
interacting with the node, but it delegates the actual interaction to | ||
another set of classes: Adapters and Wrappers. | ||
|
||
AdapterSpec | ||
----------- | ||
|
||
In a few places in the PyOTA codebase, you may see references to a | ||
meta-type called ``AdapterSpec``. | ||
|
||
``AdapterSpec`` is a placeholder that means "URI or adapter instance". | ||
|
||
For example, the first argument of ``Iota.__init__`` is an | ||
``AdapterSpec``. This means that you can initialize an ``Iota`` object | ||
using either a node URI, or an adapter instance: | ||
|
||
- Node URI: ``Iota('http://localhost:14265')`` | ||
- Adapter instance: ``Iota(HttpAdapter('http://localhost:14265'))`` | ||
|
||
Adapters | ||
-------- | ||
|
||
Adapters are responsible for sending requests to the node and returning | ||
the response. | ||
|
||
PyOTA ships with a few adapters: | ||
|
||
HttpAdapter | ||
~~~~~~~~~~~ | ||
|
||
.. code:: python | ||
from iota import Iota | ||
from iota.adapter import HttpAdapter | ||
# Use HTTP: | ||
api = Iota('http://localhost:14265') | ||
api = Iota(HttpAdapter('http://localhost:14265')) | ||
# Use HTTPS: | ||
api = Iota('https://service.iotasupport.com:14265') | ||
api = Iota(HttpAdapter('https://service.iotasupport.com:14265')) | ||
``HttpAdapter`` uses the HTTP protocol to send requests to the node. | ||
|
||
To configure an ``Iota`` instance to use ``HttpAdapter``, specify an | ||
``http://`` or ``https://`` URI, or provide an ``HttpAdapter`` instance. | ||
|
||
The ``HttpAdapter`` raises a ``BadApiResponse`` exception if the server | ||
sends back an error response (due to invalid request parameters, for | ||
example). | ||
|
||
Debugging HTTP Requests | ||
^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
.. code:: python | ||
from logging import getLogger | ||
from iota import Iota | ||
api = Iota('http://localhost:14265') | ||
api.adapter.set_logger(getLogger(__name__)) | ||
To see all HTTP requests and responses as they happen, attach a | ||
``logging.Logger`` instance to the adapter via its ``set_logger`` | ||
method. | ||
|
||
Any time the ``HttpAdapter`` sends a request or receives a response, it | ||
will first generate a log message. Note: if the response is an error | ||
response (e.g., due to invalid request parameters), the ``HttpAdapter`` | ||
will log the request before raising ``BadApiResponse``. | ||
|
||
.. note:: | ||
|
||
``HttpAdapter`` generates log messages with ``DEBUG`` level, so make sure that your logger's ``level`` attribute is set low enough that it doesn't filter these messages! | ||
|
||
SandboxAdapter | ||
~~~~~~~~~~~~~~ | ||
|
||
.. code:: python | ||
from iota import Iota | ||
from iota.adapter.sandbox import SandboxAdapter | ||
api =\ | ||
Iota( | ||
SandboxAdapter( | ||
uri = 'https://sandbox.iotatoken.com/api/v1/', | ||
auth_token = 'demo7982-be4a-4afa-830e-7859929d892c', | ||
), | ||
) | ||
The ``SandboxAdapter`` is a specialized ``HttpAdapter`` that sends | ||
authenticated requests to sandbox nodes. | ||
|
||
.. note:: | ||
|
||
See `Sandbox <https://dev.iota.org/sandbox/>`_ Documentation for more information about sandbox nodes. | ||
|
||
Sandbox nodes process certain commands asynchronously. When | ||
``SandboxAdapter`` determines that a request is processed | ||
asynchronously, it will block, then poll the node periodically until it | ||
receives a response. | ||
|
||
The result is that ``SandboxAdapter`` abstracts away the sandbox node's | ||
asynchronous functionality so that your API client behaves exactly the | ||
same as if it were connecting to a non-sandbox node. | ||
|
||
To create a ``SandboxAdapter``, you must provide the URI of the sandbox | ||
node and the auth token that you received from the node maintainer. Note | ||
that ``SandboxAdapter`` only works with ``http://`` and ``https://`` | ||
URIs. | ||
|
||
You may also specify the polling interval (defaults to 15 seconds) and | ||
the number of polls before giving up on an asynchronous job (defaults to | ||
8 times). | ||
|
||
.. note:: | ||
|
||
For parity with the other adapters, ``SandboxAdapter`` blocks until it receives a response from the node. | ||
|
||
If you do not want ``SandboxAdapter`` to block the main thread, it is recommended that you execute it in a separate thread or process. | ||
|
||
|
||
MockAdapter | ||
~~~~~~~~~~~ | ||
|
||
.. code:: python | ||
from iota import Iota | ||
from iota.adapter import MockAdapter | ||
# Inject a mock adapter. | ||
api = Iota('mock://') | ||
api = Iota(MockAdapter()) | ||
# Seed responses from the node. | ||
api.adapter.seed_response('getNodeInfo', {'message': 'Hello, world!'}) | ||
api.adapter.seed_response('getNodeInfo', {'message': 'Hello, IOTA!'}) | ||
# Invoke API commands, using the adapter. | ||
print(api.get_node_info()) # {'message': 'Hello, world!'} | ||
print(api.get_node_info()) # {'message': 'Hello, IOTA!'} | ||
print(api.get_node_info()) # raises BadApiResponse exception | ||
``MockAdapter`` is used to simulate the behavior of an adapter without | ||
actually sending any requests to the node. | ||
|
||
This is particularly useful in unit and functional tests where you want | ||
to verify that your code works correctly in specific scenarios, without | ||
having to engineer your own subtangle. | ||
|
||
To configure an ``Iota`` instance to use ``MockAdapter``, specify | ||
``mock://`` as the node URI, or provide a ``MockAdapter`` instance. | ||
|
||
To use ``MockAdapter``, you must first seed the responses that you want | ||
it to return by calling its ``seed_response`` method. | ||
|
||
``seed_response`` takes two parameters: | ||
|
||
- ``command: Text``: The name of the command. Note that this is the | ||
camelCase version of the command name (e.g., ``getNodeInfo``, not | ||
``get_node_info``). | ||
- ``response: dict``: The response that the adapter will return. | ||
|
||
You can seed multiple responses for the same command; the | ||
``MockAdapter`` maintains a queue for each command internally, and it | ||
will pop a response off of the corresponding queue each time it | ||
processes a request. | ||
|
||
Note that you have to call ``seed_response`` once for each request you | ||
expect it to process. If ``MockAdapter`` does not have a seeded response | ||
for a particular command, it will raise a ``BadApiResponse`` exception | ||
(simulates a 404 response). | ||
|
||
Wrappers | ||
-------- | ||
|
||
Wrappers act like decorators for adapters; they are used to enhance or | ||
otherwise modify the behavior of adapters. | ||
|
||
RoutingWrapper | ||
~~~~~~~~~~~~~~ | ||
|
||
.. code:: python | ||
from iota import Iota | ||
from iota.adapter.wrappers import RoutingWrapper | ||
api =\ | ||
Iota( | ||
# Send PoW requests to local node. | ||
# All other requests go to light wallet node. | ||
RoutingWrapper('https://service.iotasupport.com:14265') | ||
.add_route('attachToTangle', 'http://localhost:14265') | ||
.add_route('interruptAttachingToTangle', 'http://localhost:14265') | ||
) | ||
``RoutingWrapper`` allows you to route API requests to different nodes | ||
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. | ||
|
||
``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. | ||
|
||
Once you've initialized the ``RoutingWrapper``, invoke its ``add_route`` | ||
method to specify a different adapter to use for a particular command. | ||
|
||
``add_route`` requires two arguments: | ||
|
||
- ``command: Text``: The name of the command. Note that this is the | ||
camelCase version of the command name (e.g., ``getNodeInfo``, not | ||
``get_node_info``). | ||
- ``adapter: AdapterSpec``: The adapter or URI to send this request to. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
Generating Addresses | ||
==================== | ||
|
||
In IOTA, addresses are generated deterministically from seeds. This | ||
ensures that your account can be accessed from any location, as long as | ||
you have the seed. | ||
|
||
Note that this also means that anyone with access to your seed can spend | ||
your IOTAs! Treat your seed(s) the same as you would the password for | ||
any other financial service. | ||
|
||
.. note:: | ||
|
||
PyOTA's crytpo functionality is currently very slow; on average it takes | ||
8-10 seconds to generate each address. | ||
|
||
These performance issues will be fixed in a future version of the library; | ||
please bear with us! | ||
|
||
In the meantime, if you are using Python 3, you can install a C extension | ||
that boosts PyOTA's performance significantly (speedups of 60x are common!). | ||
|
||
To install the extension, run ``pip install pyota[ccurl]``. | ||
|
||
**Important:** The extension is not yet compatible with Python 2. | ||
|
||
If you are familiar with Python 2's C API, we'd love to hear from you! | ||
Check the `GitHub issue <https://github.com/todofixthis/pyota-ccurl/issues/4>`_ | ||
for more information. | ||
|
||
PyOTA provides two methods for generating addresses: | ||
|
||
Using the API | ||
------------- | ||
|
||
.. code:: python | ||
from iota import Iota | ||
api = Iota('http://localhost:14265', b'SEED9GOES9HERE') | ||
# Generate 5 addresses, starting with index 0. | ||
gna_result = api.get_new_addresses(count=5) | ||
addresses = gna_result['addresses'] | ||
# Generate 1 address, starting with index 42: | ||
gna_result = api.get_new_addresses(start=42) | ||
addresses = gna_result['addresses'] | ||
# Find the first unused address, starting with index 86: | ||
gna_result = api.get_new_addresses(start=86, count=None) | ||
addresses = gna_result['addresses'] | ||
To generate addresses using the API, invoke its ``get_new_addresses`` | ||
method, using the following parameters: | ||
|
||
- ``start: int``: The starting index (defaults to 0). This can be used | ||
to skip over addresses that have already been generated. | ||
- ``count: Optional[int]``: The number of addresses to generate | ||
(defaults to 1). | ||
- If ``None``, the API will generate addresses until it finds one that | ||
has not been used (has no transactions associated with it on the | ||
Tangle). It will then return the unused address and discard the rest. | ||
- ``security_level: int``: Determines the security level of the | ||
generated addresses. See `Security Levels <#security-levels>`__ | ||
below. | ||
|
||
``get_new_addresses`` 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. | ||
|
||
Using AddressGenerator | ||
---------------------- | ||
|
||
.. code:: python | ||
from iota.crypto.addresses import AddressGenerator | ||
generator = AddressGenerator(b'SEED9GOES9HERE') | ||
# Generate a list of addresses: | ||
addresses = generator.get_addresses(start=0, count=5) | ||
# Generate a list of addresses in reverse order: | ||
addresses = generator.get_addresses(start=42, count=10, step=-1) | ||
# Create an iterator, advancing 5 indices each iteration. | ||
iterator = generator.create_iterator(start=86, step=5) | ||
for address in iterator: | ||
... | ||
If you want more control over how addresses are generated, you can use | ||
the ``AddressGenerator`` class. | ||
|
||
``AddressGenerator`` can create iterators, allowing your application to | ||
generate addresses as needed, instead of having to generate lots of | ||
addresses up front. | ||
|
||
You can also specify an optional ``step`` parameter, which allows you to | ||
skip over multiple addresses between iterations... or even iterate over | ||
addresses in reverse order! | ||
|
||
``AddressGenerator`` provides two methods: | ||
|
||
- ``get_addresses: (int, int, int) -> List[Address]``: Returns a list | ||
of addresses. This is the same method that the ``get_new_addresses`` | ||
API command uses internally. | ||
- ``create_iterator: (int, int) -> Generator[Address]``: Returns an | ||
iterator that will create addresses endlessly. Use this if you have a | ||
feature that needs to generate addresses "on demand". | ||
|
||
Security Levels | ||
=============== | ||
|
||
.. code:: python | ||
gna_result = api.get_new_addresses(security_level=3) | ||
generator =\ | ||
AddressGenerator( | ||
seed = b'SEED9GOES9HERE', | ||
security_level = 3, | ||
) | ||
If desired, you may change the number of iterations that | ||
``AddressGenerator`` uses internally when generating new addresses, by | ||
specifying a different ``security_level`` when creating a new instance. | ||
|
||
``security_level`` should be between 1 and 3, inclusive. Values outside | ||
this range are not supported by the IOTA protocol. | ||
|
||
Use the following guide when deciding which security level to use: | ||
|
||
- ``security_level=1``: Least secure, but generates addresses the | ||
fastest. | ||
- ``security_level=2``: Default; good compromise between speed and | ||
security. | ||
- ``security_level=3``: Most secure; results in longer signatures in | ||
transactions. |
Oops, something went wrong.