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

Commit ff5e944

Browse files
authored
Merge pull request #102 from QuantumDamage/develop
Ported docs from md to rst #78
2 parents 92b6c35 + b46b441 commit ff5e944

File tree

5 files changed

+991
-225
lines changed

5 files changed

+991
-225
lines changed

docs/adapters.rst

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
Adapters and Wrappers
2+
=====================
3+
4+
The ``Iota`` class defines the API methods that are available for
5+
interacting with the node, but it delegates the actual interaction to
6+
another set of classes: Adapters and Wrappers.
7+
8+
AdapterSpec
9+
-----------
10+
11+
In a few places in the PyOTA codebase, you may see references to a
12+
meta-type called ``AdapterSpec``.
13+
14+
``AdapterSpec`` is a placeholder that means "URI or adapter instance".
15+
16+
For example, the first argument of ``Iota.__init__`` is an
17+
``AdapterSpec``. This means that you can initialize an ``Iota`` object
18+
using either a node URI, or an adapter instance:
19+
20+
- Node URI: ``Iota('http://localhost:14265')``
21+
- Adapter instance: ``Iota(HttpAdapter('http://localhost:14265'))``
22+
23+
Adapters
24+
--------
25+
26+
Adapters are responsible for sending requests to the node and returning
27+
the response.
28+
29+
PyOTA ships with a few adapters:
30+
31+
HttpAdapter
32+
~~~~~~~~~~~
33+
34+
.. code:: python
35+
36+
from iota import Iota
37+
from iota.adapter import HttpAdapter
38+
39+
# Use HTTP:
40+
api = Iota('http://localhost:14265')
41+
api = Iota(HttpAdapter('http://localhost:14265'))
42+
43+
# Use HTTPS:
44+
api = Iota('https://service.iotasupport.com:14265')
45+
api = Iota(HttpAdapter('https://service.iotasupport.com:14265'))
46+
47+
``HttpAdapter`` uses the HTTP protocol to send requests to the node.
48+
49+
To configure an ``Iota`` instance to use ``HttpAdapter``, specify an
50+
``http://`` or ``https://`` URI, or provide an ``HttpAdapter`` instance.
51+
52+
The ``HttpAdapter`` raises a ``BadApiResponse`` exception if the server
53+
sends back an error response (due to invalid request parameters, for
54+
example).
55+
56+
Debugging HTTP Requests
57+
^^^^^^^^^^^^^^^^^^^^^^^
58+
59+
.. code:: python
60+
61+
from logging import getLogger
62+
63+
from iota import Iota
64+
65+
api = Iota('http://localhost:14265')
66+
api.adapter.set_logger(getLogger(__name__))
67+
68+
To see all HTTP requests and responses as they happen, attach a
69+
``logging.Logger`` instance to the adapter via its ``set_logger``
70+
method.
71+
72+
Any time the ``HttpAdapter`` sends a request or receives a response, it
73+
will first generate a log message. Note: if the response is an error
74+
response (e.g., due to invalid request parameters), the ``HttpAdapter``
75+
will log the request before raising ``BadApiResponse``.
76+
77+
.. note::
78+
79+
``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!
80+
81+
SandboxAdapter
82+
~~~~~~~~~~~~~~
83+
84+
.. code:: python
85+
86+
from iota import Iota
87+
from iota.adapter.sandbox import SandboxAdapter
88+
89+
api =\
90+
Iota(
91+
SandboxAdapter(
92+
uri = 'https://sandbox.iotatoken.com/api/v1/',
93+
auth_token = 'demo7982-be4a-4afa-830e-7859929d892c',
94+
),
95+
)
96+
97+
The ``SandboxAdapter`` is a specialized ``HttpAdapter`` that sends
98+
authenticated requests to sandbox nodes.
99+
100+
.. note::
101+
102+
See `Sandbox <https://dev.iota.org/sandbox/>`_ Documentation for more information about sandbox nodes.
103+
104+
Sandbox nodes process certain commands asynchronously. When
105+
``SandboxAdapter`` determines that a request is processed
106+
asynchronously, it will block, then poll the node periodically until it
107+
receives a response.
108+
109+
The result is that ``SandboxAdapter`` abstracts away the sandbox node's
110+
asynchronous functionality so that your API client behaves exactly the
111+
same as if it were connecting to a non-sandbox node.
112+
113+
To create a ``SandboxAdapter``, you must provide the URI of the sandbox
114+
node and the auth token that you received from the node maintainer. Note
115+
that ``SandboxAdapter`` only works with ``http://`` and ``https://``
116+
URIs.
117+
118+
You may also specify the polling interval (defaults to 15 seconds) and
119+
the number of polls before giving up on an asynchronous job (defaults to
120+
8 times).
121+
122+
.. note::
123+
124+
For parity with the other adapters, ``SandboxAdapter`` blocks until it receives a response from the node.
125+
126+
If you do not want ``SandboxAdapter`` to block the main thread, it is recommended that you execute it in a separate thread or process.
127+
128+
129+
MockAdapter
130+
~~~~~~~~~~~
131+
132+
.. code:: python
133+
134+
from iota import Iota
135+
from iota.adapter import MockAdapter
136+
137+
# Inject a mock adapter.
138+
api = Iota('mock://')
139+
api = Iota(MockAdapter())
140+
141+
# Seed responses from the node.
142+
api.adapter.seed_response('getNodeInfo', {'message': 'Hello, world!'})
143+
api.adapter.seed_response('getNodeInfo', {'message': 'Hello, IOTA!'})
144+
145+
# Invoke API commands, using the adapter.
146+
print(api.get_node_info()) # {'message': 'Hello, world!'}
147+
print(api.get_node_info()) # {'message': 'Hello, IOTA!'}
148+
print(api.get_node_info()) # raises BadApiResponse exception
149+
150+
``MockAdapter`` is used to simulate the behavior of an adapter without
151+
actually sending any requests to the node.
152+
153+
This is particularly useful in unit and functional tests where you want
154+
to verify that your code works correctly in specific scenarios, without
155+
having to engineer your own subtangle.
156+
157+
To configure an ``Iota`` instance to use ``MockAdapter``, specify
158+
``mock://`` as the node URI, or provide a ``MockAdapter`` instance.
159+
160+
To use ``MockAdapter``, you must first seed the responses that you want
161+
it to return by calling its ``seed_response`` method.
162+
163+
``seed_response`` takes two parameters:
164+
165+
- ``command: Text``: The name of the command. Note that this is the
166+
camelCase version of the command name (e.g., ``getNodeInfo``, not
167+
``get_node_info``).
168+
- ``response: dict``: The response that the adapter will return.
169+
170+
You can seed multiple responses for the same command; the
171+
``MockAdapter`` maintains a queue for each command internally, and it
172+
will pop a response off of the corresponding queue each time it
173+
processes a request.
174+
175+
Note that you have to call ``seed_response`` once for each request you
176+
expect it to process. If ``MockAdapter`` does not have a seeded response
177+
for a particular command, it will raise a ``BadApiResponse`` exception
178+
(simulates a 404 response).
179+
180+
Wrappers
181+
--------
182+
183+
Wrappers act like decorators for adapters; they are used to enhance or
184+
otherwise modify the behavior of adapters.
185+
186+
RoutingWrapper
187+
~~~~~~~~~~~~~~
188+
189+
.. code:: python
190+
191+
from iota import Iota
192+
from iota.adapter.wrappers import RoutingWrapper
193+
194+
api =\
195+
Iota(
196+
# Send PoW requests to local node.
197+
# All other requests go to light wallet node.
198+
RoutingWrapper('https://service.iotasupport.com:14265')
199+
.add_route('attachToTangle', 'http://localhost:14265')
200+
.add_route('interruptAttachingToTangle', 'http://localhost:14265')
201+
)
202+
203+
``RoutingWrapper`` allows you to route API requests to different nodes
204+
depending on the command name.
205+
206+
For example, you could use this wrapper to direct all PoW requests to a
207+
local node, while sending the other requests to a light wallet node.
208+
209+
``RoutingWrapper`` must be initialized with a default URI/adapter. This
210+
is the adapter that will be used for any command that doesn't have a
211+
route associated with it.
212+
213+
Once you've initialized the ``RoutingWrapper``, invoke its ``add_route``
214+
method to specify a different adapter to use for a particular command.
215+
216+
``add_route`` requires two arguments:
217+
218+
- ``command: Text``: The name of the command. Note that this is the
219+
camelCase version of the command name (e.g., ``getNodeInfo``, not
220+
``get_node_info``).
221+
- ``adapter: AdapterSpec``: The adapter or URI to send this request to.

docs/addresses.rst

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
Generating Addresses
2+
====================
3+
4+
In IOTA, addresses are generated deterministically from seeds. This
5+
ensures that your account can be accessed from any location, as long as
6+
you have the seed.
7+
8+
Note that this also means that anyone with access to your seed can spend
9+
your IOTAs! Treat your seed(s) the same as you would the password for
10+
any other financial service.
11+
12+
.. note::
13+
14+
PyOTA's crytpo functionality is currently very slow; on average it takes
15+
8-10 seconds to generate each address.
16+
17+
These performance issues will be fixed in a future version of the library;
18+
please bear with us!
19+
20+
In the meantime, if you are using Python 3, you can install a C extension
21+
that boosts PyOTA's performance significantly (speedups of 60x are common!).
22+
23+
To install the extension, run ``pip install pyota[ccurl]``.
24+
25+
**Important:** The extension is not yet compatible with Python 2.
26+
27+
If you are familiar with Python 2's C API, we'd love to hear from you!
28+
Check the `GitHub issue <https://github.com/todofixthis/pyota-ccurl/issues/4>`_
29+
for more information.
30+
31+
PyOTA provides two methods for generating addresses:
32+
33+
Using the API
34+
-------------
35+
36+
.. code:: python
37+
38+
from iota import Iota
39+
40+
api = Iota('http://localhost:14265', b'SEED9GOES9HERE')
41+
42+
# Generate 5 addresses, starting with index 0.
43+
gna_result = api.get_new_addresses(count=5)
44+
addresses = gna_result['addresses']
45+
46+
# Generate 1 address, starting with index 42:
47+
gna_result = api.get_new_addresses(start=42)
48+
addresses = gna_result['addresses']
49+
50+
# Find the first unused address, starting with index 86:
51+
gna_result = api.get_new_addresses(start=86, count=None)
52+
addresses = gna_result['addresses']
53+
54+
To generate addresses using the API, invoke its ``get_new_addresses``
55+
method, using the following parameters:
56+
57+
- ``start: int``: The starting index (defaults to 0). This can be used
58+
to skip over addresses that have already been generated.
59+
- ``count: Optional[int]``: The number of addresses to generate
60+
(defaults to 1).
61+
- If ``None``, the API will generate addresses until it finds one that
62+
has not been used (has no transactions associated with it on the
63+
Tangle). It will then return the unused address and discard the rest.
64+
- ``security_level: int``: Determines the security level of the
65+
generated addresses. See `Security Levels <#security-levels>`__
66+
below.
67+
68+
``get_new_addresses`` returns a dict with the following items:
69+
70+
- ``addresses: List[Address]``: The generated address(es). Note that
71+
this value is always a list, even if only one address was generated.
72+
73+
Using AddressGenerator
74+
----------------------
75+
76+
.. code:: python
77+
78+
from iota.crypto.addresses import AddressGenerator
79+
80+
generator = AddressGenerator(b'SEED9GOES9HERE')
81+
82+
# Generate a list of addresses:
83+
addresses = generator.get_addresses(start=0, count=5)
84+
85+
# Generate a list of addresses in reverse order:
86+
addresses = generator.get_addresses(start=42, count=10, step=-1)
87+
88+
# Create an iterator, advancing 5 indices each iteration.
89+
iterator = generator.create_iterator(start=86, step=5)
90+
for address in iterator:
91+
...
92+
93+
If you want more control over how addresses are generated, you can use
94+
the ``AddressGenerator`` class.
95+
96+
``AddressGenerator`` can create iterators, allowing your application to
97+
generate addresses as needed, instead of having to generate lots of
98+
addresses up front.
99+
100+
You can also specify an optional ``step`` parameter, which allows you to
101+
skip over multiple addresses between iterations... or even iterate over
102+
addresses in reverse order!
103+
104+
``AddressGenerator`` provides two methods:
105+
106+
- ``get_addresses: (int, int, int) -> List[Address]``: Returns a list
107+
of addresses. This is the same method that the ``get_new_addresses``
108+
API command uses internally.
109+
- ``create_iterator: (int, int) -> Generator[Address]``: Returns an
110+
iterator that will create addresses endlessly. Use this if you have a
111+
feature that needs to generate addresses "on demand".
112+
113+
Security Levels
114+
===============
115+
116+
.. code:: python
117+
118+
gna_result = api.get_new_addresses(security_level=3)
119+
120+
generator =\
121+
AddressGenerator(
122+
seed = b'SEED9GOES9HERE',
123+
security_level = 3,
124+
)
125+
126+
If desired, you may change the number of iterations that
127+
``AddressGenerator`` uses internally when generating new addresses, by
128+
specifying a different ``security_level`` when creating a new instance.
129+
130+
``security_level`` should be between 1 and 3, inclusive. Values outside
131+
this range are not supported by the IOTA protocol.
132+
133+
Use the following guide when deciding which security level to use:
134+
135+
- ``security_level=1``: Least secure, but generates addresses the
136+
fastest.
137+
- ``security_level=2``: Default; good compromise between speed and
138+
security.
139+
- ``security_level=3``: Most secure; results in longer signatures in
140+
transactions.

0 commit comments

Comments
 (0)