Skip to content

Whisper support #117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Oct 21, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ env:
- TOX_ENV=py27-net
- TOX_ENV=py34-net
- TOX_ENV=py35-net
# shh
- TOX_ENV=py27-shh
- TOX_ENV=py34-shh
- TOX_ENV=py35-shh
# txpool
- TOX_ENV=py27-txpool
- TOX_ENV=py34-txpool
Expand Down
2 changes: 1 addition & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def setup_testing_geth():
geth_process = GethProcess(
'testing',
base_dir=base_dir,
overrides={'verbosity': '3'},
overrides={'verbosity': '3','shh': True},
)
with geth_process as running_geth_process:
running_geth_process.wait_for_ipc(60)
Expand Down
22 changes: 21 additions & 1 deletion docs/filters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ will return a new :py:class::`BlockFilter` object.
... sys.stdout.write("New Block: {0}".format(transaction_hash))
...
>>> new_transaction_filter = web3.eth.filter('pending')
>>> new_transaction_filter.watch(new_transaction_filter)
>>> new_transaction_filter.watch(new_transaction_callback)
# each time the client receieves a unmined transaction the
# `new_transaction_filter` function will be called with the transaction
# hash.
Expand Down Expand Up @@ -143,3 +143,23 @@ event data from the event logs.
The :py:class::`PastLogFilter` is a subclass of :py:class::`LogFilter` that is
configured specially to return historical event logs. It conforms to the same
API as the ``LogFilter`` class.


Shh Filter
----------

.. py:class:: ShhFilter(web3, filter_id)

The :py:class:: `ShhFilter` class is used for filtering Shh messages.
You can setup a callback function for Whipser messages matching the topics subscribed using ``web3.shh.filter(filter_params)``,which
will return a :py:class::`ShhFilter` object

.. code-block:: python

>>>def filter_callback(new_message):
... sys.stdout.write("New Shh Message: {0}".format(new_message))
...
>>>shh_filter = web3.shh.filter({"topics":[web3.fromAscii("topic_to_subscribe")]})
>>>shh_filter.watch(filter_callback)
#each time client recieves a Shh messages matching the topics subscibed,
#filter_callback is called
110 changes: 99 additions & 11 deletions docs/web3.shh.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,120 @@ SHH API
The ``web3.shh`` object exposes methods to interact with the RPC APIs under the
``shh_`` namespace.

Properties
----------

The following properties are available on the ``web.shh`` namespace.

.. py:attribute:: Shh.version

The version of Whisper protocol used by client

.. code-block:: python

>>>web3.shh.version
2

Methods
-------

The following methods are available on the ``web3.personal`` namespace.
The following methods are available on the ``web3.shh`` namespace.


.. py:method:: Shh.post(self, params)

* Delegates to ``shh_post`` RPC method

* ``params`` cannot be ``None`` and should contain ``topics`` and ``payload``

* Returns ``True`` if the message was succesfully sent,otherwise ``False``

.. code-block:: python

>>>web3.shh.post({"topics":[web3.fromAscii("test_topic")],"payload":web3.fromAscii("test_payload")})
True

.. py:method:: Shh.newIdentity(self)

* Delegates to ``shh_newIdentity`` RPC method

* Returns ``address`` of newly created identity.

.. code-block:: python

>>>web3.shh.newIdentity()
u'0x045ed8042f436e1b546afd16e1f803888b896962484c0154fcc7c5fc43e276972af85f29a995a3beb232a4e9a0648858c0c8c0639d709f5d3230807d084b2d5030'

.. py:method:: Shh.hasIdentity(self, identity)

* Delegates to ``shh_hasIdentity`` RPC method

* Returns ``True`` if the client holds the private key for the given identity,otherwise ``False``

.. code-block:: python

>>>web3.shh.hasIdentity(u'0x045ed8042f436e1b546afd16e1f803888b896962484c0154fcc7c5fc43e276972af85f29a995a3beb232a4e9a0648858c0c8c0639d709f5d3230807d084b2d5030')
True

.. py:method:: Shh.newGroup(self)

* Delegates to ``shh_newGroup`` RPC method

* Returns ``address`` of newly created group.

.. note:: This method is not implemented yet in ``Geth``. `Open Issue <https://github.com/ethereum/go-ethereum/issues/310>`_

.. py:method:: Shh.addToGroup(self, identity)

* Delegates to ``shh_addToGroup`` RPC Method

* Returns ``True`` if the identity was succesfully added to the group,otherwise ``False``

.. note:: This method is not implemented yet in ``Geth``. `Open Issue <https://github.com/ethereum/go-ethereum/issues/310>`_

.. py:method:: Shh.filter(self, filter_params)

* Delegates to ``shh_newFilter`` RPC Method

* ``filter_params`` should contain the ``topics`` to subscribe

* Returns an instance of ``ShhFilter`` on succesful creation of filter,otherwise raises ``ValueError`` exception

.. py:method:: Shh.post(self, *args, **kwargs)
.. code-block:: python

.. note:: Not Implemented
>>>shh_filter = shh.filter({"topics":[web.fromAscii("topic_to_subscribe")]})
>>>shh_filter.filter_id
u'0x0'

.. py:method:: Shh.uninstallFilter(self, filter_id)

.. py:method:: Shh.newIdentity(self, *args, **kwargs)
* Delegates to ``shh_uninstallFilter`` RPC Method

.. note:: Not Implemented
* Returns ``True`` if the filter was sucesfully uninstalled ,otherwise ``False``

.. code-block:: python

.. py:method:: Shh.hasIdentity(self, *args, **kwargs)
>>>web3.shh.uninstallFilter("0x2")
True

.. note:: Not Implemented
.. py:method:: Shh.getFilterChanges(self, filter_id)

* Delegates to ``shh_getFilterChanges`` RPC Method

.. py:method:: Shh.newGroup(self, *args, **kwargs)
* Returns list of messages recieved since last poll

.. code-block:: python

>>>web3.shh.getFilterChanges(self,"0x2")
[{u'from': u'0x0', u'to': u'0x0', u'ttl': 50, u'hash': u'0xf84900b57d856a6ab1b41afc9784c31be48e841b9bcfc6accac14d05d7189f2f', u'payload': u'0x746573696e67', u'sent': 1476625149}]

.. note:: Not Implemented
.. py:method:: Shh.getMessages(self, filter_id)

* Delegates to ``shh_getMessages`` RPC Method

.. py:method:: Shh.addToGroup(self, *args, **kwargs)
* Returns a list of all messages

.. note:: Not Implemented
.. code-block:: python

>>>web3.shh.getMessages("0x2")
[{u'from': u'0x0', u'to': u'0x0', u'ttl': 50, u'hash': u'0x808d74d003d1dcbed546cca29d7a4e839794c226296b613b0fa7a8c670f84146', u'payload': u'0x746573696e67617364', u'sent': 1476625342}, {u'from': u'0x0', u'to': u'0x0', u'ttl': 50, u'hash': u'0x62a2eb9a19968d59d8a85e6dc8d73deb9b4cd40c83d95b796262d6affe6397c6', u'payload': u'0x746573696e67617364617364', u'sent': 1476625369}]
3 changes: 2 additions & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ pytest-pythonpath>=0.3
tox>=1.8.0
eth-testrpc>=0.8.6
ethereum-tester-client>=1.2.3
py-geth>=1.2.0
py-geth>=1.4.0
ethereum>=1.5.2
secp256k1>=0.13.1
rlp>=0.4.6
hypothesis>=3.4.2
flaky>=3.3.0
flake8==3.0.4
2 changes: 1 addition & 1 deletion requirements-docs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ contextlib2>=0.5.4
#eth-testrpc>=0.8.0
#ethereum-tester-client>=1.1.0
gevent>=1.1.2
py-geth>=1.1.0
py-geth>=1.4.0
py-solc>=0.4.0
#pysha3>=0.3
pytest>=2.7.2
Expand Down
14 changes: 7 additions & 7 deletions tests/filtering/test_contract_on_event_filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def test_on_filter_using_get_interface(web3_empty,
txn_hash = emitter.transact().logNoArgs(emitter_event_ids.LogNoArguments)
txn_receipt = wait_for_transaction(web3, txn_hash)

with gevent.Timeout(10):
with gevent.Timeout(30):
while not filter.get(False):
gevent.sleep(random.random())

Expand Down Expand Up @@ -54,11 +54,11 @@ def test_on_filter_with_only_event_name(web3_empty,
txn_hash = emitter.transact().logNoArgs(emitter_event_ids.LogNoArguments)
txn_receipt = wait_for_transaction(web3, txn_hash)

with gevent.Timeout(5):
with gevent.Timeout(30):
while not seen_logs:
gevent.sleep(random.random())

filter.stop_watching(10)
filter.stop_watching(30)

assert len(seen_logs) == 1
assert seen_logs[0]['transactionHash'] == txn_hash
Expand Down Expand Up @@ -99,11 +99,11 @@ def test_on_filter_with_event_name_and_single_argument(web3_empty,
for txn_hash in txn_hashes:
wait_for_transaction(web3, txn_hash)

with gevent.Timeout(5):
with gevent.Timeout(30):
while len(seen_logs) < 2:
gevent.sleep(random.random())

filter.stop_watching(10)
filter.stop_watching(30)

assert len(seen_logs) == 2
assert {l['transactionHash'] for l in seen_logs} == set(txn_hashes[1:])
Expand Down Expand Up @@ -144,11 +144,11 @@ def test_on_filter_with_event_name_and_non_indexed_argument(web3_empty,
for txn_hash in txn_hashes:
wait_for_transaction(web3, txn_hash)

with gevent.Timeout(5):
with gevent.Timeout(30):
while not seen_logs:
gevent.sleep(random.random())

filter.stop_watching(10)
filter.stop_watching(30)

assert len(seen_logs) == 1
assert seen_logs[0]['transactionHash'] == txn_hashes[1]
6 changes: 3 additions & 3 deletions tests/filtering/test_contract_past_event_filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ def test_past_events_filter_with_callback(web3_empty,
else:
filter = Emitter.pastEvents('LogNoArguments', {}, seen_logs.append)

with gevent.Timeout(5):
with gevent.Timeout(30):
while not seen_logs:
gevent.sleep(random.random())

filter.stop_watching(10)
filter.stop_watching(30)

assert len(seen_logs) == 1
event_data = seen_logs[0]
Expand Down Expand Up @@ -62,7 +62,7 @@ def test_past_events_filter_using_get_api(web3_empty,
else:
filter = Emitter.pastEvents('LogNoArguments')

with gevent.Timeout(10):
with gevent.Timeout(30):
while not filter.get(False):
gevent.sleep(random.random())

Expand Down
22 changes: 22 additions & 0 deletions tests/shh-module/test_shh_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import gevent

def test_shh_filter(web3, skip_if_testrpc):
skip_if_testrpc(web3)
recieved_messages = []
shh_filter = web3.shh.filter({"topics":[web3.fromAscii("test")]})
shh_filter.watch(recieved_messages.append)
gevent.sleep(1)

payloads = []
payloads.append(str.encode("payload1"))
web3.shh.post({"topics":[web3.fromAscii("test")], "payload":web3.fromAscii(payloads[len(payloads)-1])})
gevent.sleep(1)

payloads.append(str.encode("payload2"))
web3.shh.post({"topics":[web3.fromAscii("test")], "payload":web3.fromAscii(payloads[len(payloads)-1])})
gevent.sleep(1)

assert len(recieved_messages) > 1

for message in recieved_messages:
assert web3.toAscii(message["payload"]) in payloads
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this will pass silently if there are zero received messages. I think you need to add another assertion that ensures that at least some messages were received.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea.How did I miss that? Will add one more assert.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what code review is for 😄

5 changes: 5 additions & 0 deletions tests/shh-module/test_shh_has_identity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def test_shh_has_identity(web3, skip_if_testrpc):
skip_if_testrpc(web3)
new_identity = web3.shh.newIdentity()
assert len(new_identity) == 132
assert web3.shh.hasIdentity(new_identity)
4 changes: 4 additions & 0 deletions tests/shh-module/test_shh_new_identity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def test_shh_new_identity(web3, skip_if_testrpc):
skip_if_testrpc(web3)
new_identity = web3.shh.newIdentity()
assert len(new_identity) == 132
4 changes: 4 additions & 0 deletions tests/shh-module/test_shh_post.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def test_shh_post(web3, skip_if_testrpc):
skip_if_testrpc(web3)
random_topic = "testing"
assert web3.shh.post({"topics":[web3.fromAscii(random_topic)], "payload":web3.fromAscii("testing shh on web3.py")})
3 changes: 3 additions & 0 deletions tests/shh-module/test_shh_properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def test_shh_version(web3, skip_if_testrpc):
skip_if_testrpc(web3)
assert web3.shh.version == 2
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ commands=
contracts: py.test {posargs:tests/contracts}
filtering: py.test {posargs:tests/filtering}
net: py.test {posargs:tests/net-module}
shh: py.test {posargs:tests/shh-module}
txpool: py.test {posargs:tests/txpool-module}
db: py.test {posargs:tests/db-module}
managers: py.test {posargs:tests/managers}
Expand Down
Loading