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

Add support for performing attachToTangle PoW locally (without relying on IRI node) #139

Closed
todofixthis opened this issue Jan 15, 2018 · 11 comments

Comments

@todofixthis
Copy link
Contributor

todofixthis commented Jan 15, 2018

The PoW process can be done 100% offline, so the library should provide a mechanism for doing this locally, without having to send an attachToTangle request to a node.

Requirements not 100% nailed down yet, but here are some thoughts:

  • Probably easiest for developers if we add e.g., a local_pow argument to Iota.__init__() (maybe StrictIota.__init__()?).
    • An alternative approach would be to use an adapter for this (a la https://pyota.readthedocs.io/en/develop/adapters.html#routingwrapper), but that would make it harder for developers to discover this feature.
    • Definitely open to other approaches, post a comment if you think there's a more intuitive/usable way to integrate this into the API (:
  • Here are some existing implementations:

Also, don't forget to update documentation and example scripts (:

@plenarius
Copy link
Contributor

plenarius commented Jan 15, 2018

For reference here's how the js promoter creates a localAttachToTangle - might be helpful.

@scottbelden
Copy link
Contributor

I don't really have experience with c extensions in python, but it seems like it would be more robust and faster if the c version could be wrapped and called via a c extension rather than porting to pure python.

@todofixthis
Copy link
Contributor Author

Aye, I agree. Based on my experiences porting Curl-P to Python, I am not optimistic about how a pure-Python PearlDiver will perform.

We already have a C extension for Curl-P, and with a little bit of work, we could probably turn it into a wrapper for the ccurl library (which itself includes a PearlDiver implementation).

I think that would be a pretty sweet approach (:

@chrisoro
Copy link

chrisoro commented Jan 16, 2018

I wouldn't port it to python but rather use the existing one. Could even use it directly by going the cython route..

For the overall feature itself I would like it to be very easy to use, like you said. I would recommend the RoutingWrapper though. Just add the possibility to 'route' that call locally to a different function.

Doing that, basically every existing function that calls (directly or indirectly) attachToTangle (like promote, replay, ..) can stay the same.

@olymk2
Copy link

olymk2 commented Jan 16, 2018

The C extension would be nice to have, but a pure python implementation may be good for embedded devices running micro python it will be more portable as well this way.

Some libraries let you switch out between the pure python and the optimized version so that would be nice to have.

@mlouielu
Copy link
Contributor

I have a Python version of pearldiver (PoW) here: https://github.com/mlouielu/iota-pearldiver

but CPython got poor performance, even with pypy still get bad performance...

@miili
Copy link

miili commented Jan 18, 2018

@mlouielu excellent! Do have the time to implement your Python solution into a RoutingWrapper for PyOTA?

@danielfaust
Copy link

What would you think of this: one place to specify where PoW is computed is globally in the Iota() constructor, and the other one is in each function which actually makes use of PoW.

from iota import Iota
from iota.adapter.pow import PoW

# Remote PoW for all functions that don't explicitly specify where it is computed
# api = Iota('https://service.iotasupport.com:14265')
# which equals to
# api = Iota('https://service.iotasupport.com:14265', pow=PoW('server'))

# Local PoW with C extension for all functions that don't explicitly specify where it is computed
api = Iota('https://service.iotasupport.com:14265', pow=PoW('ccurl'))

# Use a pure Python implementation of PoW only for the next function call
result = api.send_transfer(... , pow=PoW('python'))

# Use a remote server for PoW computation, where RoutingWrapper (if used)
# could help selecting the server.
# This would be helpful if the `Iota(...)` call specifies a local PoW but for this
# function call the PoW should be computed on the server
result = api.send_transfer(... , pow=PoW('server'))

# This would compute the PoW as selected in `Iota(...)` call, `ccurl` in this case
result = api.send_transfer(...)

Possibly the keyword argument could just take a string instead of a PoW() class.

I know that this approach would require a tedious modification of all the functions.

Else you would either end up with things like RoutingWrapper('https://service.iotasupport.com:14265', pow='server')
or

api =\
  Iota(
    PoWRoutingWrapper('https://service.iotasupport.com:14265', 'ccurl')
      .add_route('attachToTangle', 'http://localhost:14265', 'python')
      .add_route('interruptAttachingToTangle', 'http://localhost:14265', 'server')
  )

, since there might be a valid reason to use a attachToTangle routed to http://localhost:14265 without performing the PoW on the localhost server, maybe because it is a server in development which does not yet have the PoW computation implemented.

@ghost
Copy link

ghost commented Oct 9, 2018

@todofixthis Any update about the local execution of the PoW ?

@imtypist
Copy link

I have a Python version of pearldiver (PoW) here: https://github.com/mlouielu/iota-pearldiver

but CPython got poor performance, even with pypy still get bad performance...

I tried to use this package, but I found that the running time changing trend is so strange when I increase mwm step by step...
comparing to the JavaScript implement, the running time is changing relatively more smoothly.
So I don't know if there is some implement difference?

@lzpap
Copy link
Member

lzpap commented Oct 21, 2019

Local PoW is supported from PyOTA 2.1.0 .
If you intend to to use the feature, all you have to do is install the PyOTA-PoW extension together with PyOTA:

pip install pyota[pow]

Or only the pow extension:

pip install pyota-pow

Essentially, this lets you to perform pow calculation on your device by redirecting all calls (direct or indirect) to attach_to_tangle to the extension interface, that will return the formally same response as a node API would.

To enable/disable local_pow, you have two options:

  1. Specify at API instantiation what pow you would like to use. Example:
api = Iota(<whatever-adapter-you-would-like>, local_pow=True)

Note, that omitting the local_pow parameter results in "original" behavior, which means that all calls to attach_to_tangle will be forwarded to the adapter that you specified.

  1. Change the behavior of the api instance dynamically:
# Enable local_pow
api.set_local_pow(local_pow=True)
# Disable local_pow
api.set_local_pow(local_pow=False)

@lzpap lzpap closed this as completed Oct 21, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

10 participants