Skip to content
This repository has been archived by the owner on May 23, 2023. It is now read-only.

Commit

Permalink
Add more tests #417
Browse files Browse the repository at this point in the history
  • Loading branch information
konradkonrad committed Nov 2, 2016
1 parent a32bd45 commit 5aa977d
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 13 deletions.
49 changes: 43 additions & 6 deletions ethereum/tests/test_transactions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from operator import attrgetter
import ethereum.transactions as transactions
import ethereum.utils as utils
import rlp
Expand All @@ -14,8 +15,6 @@
# hint: use 'py.test' with the '-s' option to dump logs to the console
# configure_logging(':trace')

encode_hex('')


def test_eip155_transaction():
"""Replicate the example from https://github.com/ethereum/eips/issues/155
Expand All @@ -28,6 +27,7 @@ def test_eip155_transaction():
value = 10 ** 18
data = ''
private_key = "4646464646464646464646464646464646464646464646464646464646464646"
sender = utils.privtoaddr(private_key)
old_style = transactions.Transaction(nonce, gasprice, startgas, to, value, data)
new_style = transactions.EIP155Transaction(nonce, gasprice, startgas, to, value, data)

Expand All @@ -45,7 +45,7 @@ def test_eip155_transaction():
0
)

assert rlp.encode(new_signing_data_sedes, transactions.Transaction) == decode_hex(new_signing_data)
assert rlp.encode(new_signing_data_sedes, transactions.EIP155Transaction) == decode_hex(new_signing_data)

new_signing_hash = "ac9813f00ec955e65a50cc778243f6c22dcfe9d64253462b16187f1c99e0a8fa"

Expand All @@ -58,16 +58,53 @@ def test_eip155_transaction():
)

new_style_signed = "f86e098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a7640000801ca1a019ae791bb8378a38bb83f5b930fe78a0320cec27d86e5e258c69f0fa9541eb8da1a02bd8e0c5bde4c0800238ce5a59d2f3ce723f1e84a62cab53d961fe3b019d19fc"
new_deserialized = rlp.decode(decode_hex(new_style_signed), transactions.EIP155Transaction)

old_style = old_style.sign(private_key)
new_style = new_style.sign(private_key)

old_style.sign(private_key)
assert not encode_hex(rlp.encode(old_style, transactions.Transaction)) == new_style_signed

new_style.sign(private_key)
# Check roundtrip serialization
roundtrip = rlp.decode(
decode_hex(
encode_hex(
rlp.encode(new_style, transactions.EIP155Transaction)
)
), transactions.EIP155Transaction)
for field, _ in transactions.EIP155Transaction.fields:
getter = attrgetter(field)
assert getter(new_style) == getter(roundtrip), field

# Check object values
assert new_style.v == new_v
assert new_style.r == new_r
assert new_style.s == new_s

assert encode_hex(rlp.encode(new_style)) == new_style_signed
# Check hex rlp against provided hex
assert encode_hex(rlp.encode(new_style, transactions.EIP155Transaction)) == new_style_signed

# Check against deserialized values
assert new_deserialized.v == new_style.v
assert new_deserialized.r == new_style.r
assert new_deserialized.s == new_style.s

# Test sender recovery
assert old_style.sender == sender
assert new_style.sender == sender
assert new_deserialized.sender == sender

# Check rlp against deserialized
new_rlp = rlp.decode(rlp.encode(new_style, transactions.EIP155Transaction))
deserialized_rlp = rlp.decode(decode_hex(new_style_signed))
assert len(new_rlp) == len(deserialized_rlp)

for num, assert_ in enumerate(
[new_rlp[i] == deserialized_rlp[i] for i in range(len(new_rlp))]):
assert assert_, (new_rlp[num], deserialized_rlp[num], num)

# Check hex rlp against provided hex
assert encode_hex(rlp.encode(new_style, transactions.EIP155Transaction)) == new_style_signed

# TODO: test deserialize new style rlp fails with old_style Transaction class

Expand Down
34 changes: 27 additions & 7 deletions ethereum/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import rlp
from bitcoin import encode_pubkey, N, encode_privkey
from rlp.sedes import big_endian_int, binary
from rlp.utils import encode_hex, str_to_bytes, ascii_chr, int_to_big_endian
from rlp.utils import encode_hex, str_to_bytes, ascii_chr
from secp256k1 import PublicKey, ALL_FLAGS, PrivateKey

from ethereum.exceptions import InvalidTransaction
Expand Down Expand Up @@ -90,7 +90,10 @@ def sender(self):
pk.public_key = pk.ecdsa_recover(
rawhash,
pk.ecdsa_recoverable_deserialize(
zpad(utils.bytearray_to_bytestr(int_to_32bytearray(self.r)), 32) + zpad(utils.bytearray_to_bytestr(int_to_32bytearray(self.s)), 32),
zpad(utils.bytearray_to_bytestr(
int_to_32bytearray(self.r)), 32) +
zpad(utils.bytearray_to_bytestr(
int_to_32bytearray(self.s)), 32),
self.normalized_v
),
raw=True
Expand All @@ -112,7 +115,9 @@ def sender(self):
def sender(self, value):
self._sender = value

def sign(self, key, backwards_compatible=True):
def sign(self, key,
backwards_compatible=True,
):
"""Sign this transaction with a private key.
A potentially already existing signature would be overridden.
Expand All @@ -132,7 +137,7 @@ def sign(self, key, backwards_compatible=True):
self.to,
self.value,
self.data,
18,
self.__class__.chain_id(),
0,
0), Transaction))

Expand All @@ -148,7 +153,7 @@ def sign(self, key, backwards_compatible=True):
if backwards_compatible:
self.v = utils.safe_ord(signature[64]) + 27
else:
self.v = utils.safe_ord(signature[64]) + (self.__class__._chain_id * 2 + 1)
self.v = utils.safe_ord(signature[64]) + (self.__class__.chain_id() * 2 + 1)
self.r = big_endian_to_int(signature[0:32])
self.s = big_endian_to_int(signature[32:64])

Expand All @@ -166,7 +171,7 @@ def normalized_v(self):
if self.v in (27, 28):
return self.v - 27
else:
return self.v - (self.__class__._chain_id * 2 + 1)
return self.v - (self.__class__.chain_id() * 2 + 1)

def log_bloom(self):
"returns int"
Expand Down Expand Up @@ -228,6 +233,10 @@ def check_low_s(self):
if self.s > N // 2 or self.s == 0:
raise InvalidTransaction("Invalid signature S value!")

@classmethod
def chain_id(cls):
return cls._chain_id


class EIP155Transaction(Transaction):
# TODO: ensure EIP155Transaction is used after SPURIOUS_DRAGON_FORK_NUMBER
Expand All @@ -237,7 +246,18 @@ def __init__(self, *args, **kwargs):
super(EIP155Transaction, self).__init__(*args, **kwargs)

def sign(self, key, backwards_compatible=False):
return super(self.__class__, self).sign(key, backwards_compatible)
return super(self.__class__, self).sign(
key,
backwards_compatible=backwards_compatible,
)

@classmethod
def chain_id(cls):
assert cls._chain_id == EIP155Transaction._chain_id
return cls._chain_id

def __repr__(self):
return '<EIP155Transaction(%s)>' % encode_hex(self.hash)[:4]


UnsignedTransaction = Transaction.exclude(['v', 'r', 's'])
Expand Down

0 comments on commit 5aa977d

Please sign in to comment.