Skip to content
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

New eth.sign and recovery hash generator #301

Merged
merged 10 commits into from
Sep 17, 2017
41 changes: 41 additions & 0 deletions tests/core/eth-module/test_eth_signing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# coding=utf-8

import pytest
import sys


@pytest.mark.skipif(sys.version_info.major < 3, reason="requires python 3")
@pytest.mark.parametrize(
'message, expected',
[
(
'Message tö sign. Longer than hash!',
'0x10c7cb57942998ab214c062e7a57220a174aacd80418cead9f90ec410eacada1',
),
(
# Intentionally sneaky: message is a hexstr interpreted as text
'0x4d6573736167652074c3b6207369676e2e204c6f6e676572207468616e206861736821',
'0x6192785e9ad00100e7332ff585824b65eafa30bc8f1265cf86b5368aa3ab5d56',
),
]
)
def test_recovery_message_text_hash(web3, message, expected):
assert web3.eth._recoveryMessageHash(text=message) == expected


@pytest.mark.skipif(sys.version_info.major < 3, reason="requires python 3")
@pytest.mark.parametrize(
'message, expected',
[
(
'0x4d6573736167652074c3b6207369676e2e204c6f6e676572207468616e206861736821',
'0x10c7cb57942998ab214c062e7a57220a174aacd80418cead9f90ec410eacada1',
),
(
'0x29d9f7d6a1d1e62152f314f04e6bd4300ad56fd72102b6b83702869a089f470c',
'0xe709159ef0e6323c705786fc50e47a8143812e9f82f429e585034777c7bf530b',
),
]
)
def test_recovery_message_hexstr_hash(web3, message, expected):
assert web3.eth._recoveryMessageHash(hexstr=message) == expected
13 changes: 7 additions & 6 deletions tests/core/shh-module/test_shh_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,25 @@
def test_shh_filter(web3, skip_if_testrpc):
skip_if_testrpc(web3)
recieved_messages = []
shh_filter = web3.shh.filter({"topics": [web3.fromAscii("test")]})
topic = web3.toHex(text="test")
shh_filter = web3.shh.filter({"topics": [topic]})
shh_filter.watch(recieved_messages.append)

payloads = []
payloads.append(str.encode("payload1"))
web3.shh.post({
"topics": [web3.fromAscii("test")],
"payload": web3.fromAscii(payloads[len(payloads) - 1]),
"topics": [topic],
"payload": web3.toHex(text=payloads[-1]),
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't need to be cleaned up here, but it might be wise for us to remove the use of web3.toHex here in favor of using the eth_utils.encode_hex function so as to not make our tests dependent on this API.

})
sleep(1)

payloads.append(str.encode("payload2"))
web3.shh.post({
"topics": [web3.fromAscii("test")],
"payload": web3.fromAscii(payloads[len(payloads) - 1]),
"topics": [topic],
"payload": web3.toHex(text=payloads[-1]),
})
sleep(1)
assert len(recieved_messages) > 1

for message in recieved_messages:
assert web3.toAscii(message["payload"]) in payloads
assert web3.toBytes(message["payload"]) in payloads
4 changes: 2 additions & 2 deletions tests/core/shh-module/test_shh_post.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ 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"),
"topics": [web3.toHex(text=random_topic)],
"payload": web3.toHex(text="testing shh on web3.py"),
})
20 changes: 5 additions & 15 deletions tests/core/utilities/test_encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
)

from web3.utils.encoding import (
from_decimal,
hex_encode_abi_type,
to_decimal,
to_hex,
Expand All @@ -20,30 +19,21 @@
"value,expected",
[
(1, '0x1'),
('1', '0x1'),
(15, '0xf'),
('15', '0xf'),
(-1, '-0x1'),
('-1', '-0x1'),
(-15, '-0xf'),
('-15', '-0xf'),
(0, '0x0'),
('0', '0x0'),
(-0, '0x0'),
('-0', '0x0'),
("0x0", "0x0"),
("-0x0", "0x0"),
("0x5", "0x5"),
]
)
def test_from_decimal(value, expected):
assert from_decimal(value) == expected
def test_to_hex(value, expected):
assert to_hex(value) == expected


@given(value=st.integers(min_value=-1 * 2**255 + 1, max_value=2**256 - 1))
def test_conversion_rount_trip(value):
intermediate_value = from_decimal(value)
result_value = to_decimal(intermediate_value)
def test_conversion_round_trip(value):
intermediate_value = to_hex(value)
result_value = to_decimal(hexstr=intermediate_value)
error_msg = "Expected: {0!r}, Result: {1!r}, Intermediate: {2!r}".format(
value,
result_value,
Expand Down
196 changes: 196 additions & 0 deletions tests/core/web3-module/test_conversions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# coding=utf-8

from __future__ import unicode_literals

import pytest
import sys

from web3 import Web3


@pytest.mark.parametrize(
'val, expected',
(
(b'\x01', b'\x01'),
(b'\xff', b'\xff'),
(b'\x00', b'\x00'),
(0x01, b'\x01'),
(0xFF, b'\xff'),
(0, b'\x00'),
(256, b'\x01\x00'),
(True, b'\x01'),
(False, b'\x00'),
)
)
def test_to_bytes_primitive(val, expected):
assert Web3.toBytes(val) == expected


@pytest.mark.parametrize(
'val, expected',
(
('0x', b''),
('0x0', b'\x00'),
('0x1', b'\x01'),
('0', b'\x00'),
('1', b'\x01'),
('0xFF', b'\xff'),
('0x100', b'\x01\x00'),
('0x0000', b'\x00\x00'),
)
)
def test_to_bytes_hexstr(val, expected):
assert Web3.toBytes(hexstr=val) == expected


@pytest.mark.parametrize(
'val, expected',
(
('cowmö', b'cowm\xc3\xb6'),
('', b''),
)
)
def test_to_bytes_text(val, expected):
assert Web3.toBytes(text=val) == expected


def test_to_text_identity():
if sys.version_info.major < 3:
with pytest.raises(NotImplementedError):
Web3.toText(text='')
else:
assert Web3.toText(text='pass-through') == 'pass-through'


@pytest.mark.parametrize(
'val, expected',
(
(b'', ''),
('0x', ''),
(b'cowm\xc3\xb6', 'cowmö'),
('0x636f776dc3b6', 'cowmö'),
(0x636f776dc3b6, 'cowmö'),
('0xa', '\n'),
)
)
def test_to_text(val, expected):
if sys.version_info.major < 3:
with pytest.raises(NotImplementedError):
Web3.toText(val)
else:
assert Web3.toText(val) == expected


@pytest.mark.parametrize(
'val, expected',
(
('0x', ''),
('0xa', '\n'),
('0x636f776dc3b6', 'cowmö'),
)
)
def test_to_text_hexstr(val, expected):
if sys.version_info.major < 3:
with pytest.raises(NotImplementedError):
Web3.toText(hexstr=val)
else:
assert Web3.toText(hexstr=val) == expected


@pytest.mark.parametrize(
'val, expected',
(
(b'\x00', 0),
(b'\x01', 1),
(b'\x00\x01', 1),
(b'\x01\x00', 256),
('255', 255),
('-1', -1),
(True, 1),
(False, 0),
# Deprecated:
('0x0', 0),
('0x1', 1),
('0x01', 1),
('0x10', 16),
)
)
def test_to_decimal(val, expected):
if isinstance(val, bytes) and bytes == str:
pytest.skip("Python 3 is required to pass in bytes")
assert Web3.toDecimal(val) == expected


@pytest.mark.parametrize(
'val, expected',
(
('0', 0),
('-1', -1),
('255', 255),
)
)
def test_to_decimal_text(val, expected):
if isinstance(val, bytes) and bytes == str:
pytest.skip("Python 3 is required to pass in bytes")
assert Web3.toDecimal(text=val) == expected


@pytest.mark.parametrize(
'val, expected',
(
('0x0', 0),
('0x1', 1),
('0x01', 1),
('0x10', 16),
('0', 0),
('1', 1),
('01', 1),
('10', 16),
)
)
def test_to_decimal_hexstr(val, expected):
assert Web3.toDecimal(hexstr=val) == expected


@pytest.mark.parametrize(
'val, expected',
(
(b'\x00', '0x0'),
(b'\x01', '0x1'),
(b'\x10', '0x10'),
(b'\x01\x00', '0x100'),
(b'', '0x'),
(0, '0x0'),
(1, '0x1'),
(16, '0x10'),
(256, '0x100'),
(False, '0x0'),
(True, '0x1'),
)
)
def test_to_hex(val, expected):
assert Web3.toHex(val) == expected


@pytest.mark.parametrize(
'val, expected',
(
('', '0x'),
('cowmö', '0x636f776dc3b6'),
)
)
def test_to_hex_text(val, expected):
assert Web3.toHex(text=val) == expected


@pytest.mark.parametrize(
'val, expected',
(
('0x0', '0x0'),
('0x1', '0x1'),
('0x01', '0x1'),
('0x10', '0x10'),
)
)
def test_to_hex_cleanup_only(val, expected):
assert Web3.toHex(hexstr=val) == expected
23 changes: 18 additions & 5 deletions web3/eth.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from __future__ import unicode_literals

from cytoolz import compose
from cytoolz.dicttoolz import (
assoc,
)

from eth_utils import (
is_address,
is_string,
encode_hex,
coerce_return_to_text,
keccak,
)

from web3.iban import Iban
Expand All @@ -23,9 +23,16 @@
from web3.utils.blocks import (
select_method_for_block_identifier,
)
from web3.utils.signing import (
signature_wrapper,
)
from web3.utils.empty import (
empty,
)
from web3.utils.encoding import (
to_bytes,
to_hex,
)
from web3.utils.filters import (
BlockFilter,
TransactionFilter,
Expand Down Expand Up @@ -220,12 +227,18 @@ def sendRawTransaction(self, raw_transaction):
[raw_transaction],
)

@coerce_return_to_text
def sign(self, account, data):
def sign(self, account, data=None, hexstr=None, text=None):
message_hex = to_hex(data, hexstr=hexstr, text=text)
return self.web3.manager.request_blocking(
"eth_sign", [account, encode_hex(data)],
"eth_sign", [account, message_hex],
)

@staticmethod
def _recoveryMessageHash(data=None, hexstr=None, text=None):
message_bytes = to_bytes(data, hexstr=hexstr, text=text)
recovery_hasher = compose(to_hex, keccak, signature_wrapper)
return recovery_hasher(message_bytes)

def call(self, transaction, block_identifier=None):
# TODO: move to middleware
if 'from' not in transaction and is_address(self.defaultAccount):
Expand Down
Loading