From f8f168bc35858894ba4385700c5abd6aa83c1dde Mon Sep 17 00:00:00 2001 From: qcdll <40378568+qcdll@users.noreply.github.com> Date: Thu, 11 Oct 2018 17:08:40 -0700 Subject: [PATCH] use pyrlp>=1.0.0 (#153) * bump rlp>=1.0.0; move utils to tools/rlp_utils.py * fix all unittests because of pyrlp>=1.0.0 * move rlp_utils to quarkchain/rlp/ --- .circleci/config.yml | 10 +-- devp2p/app.py | 2 +- devp2p/app_helper.py | 2 +- devp2p/crypto.py | 2 +- devp2p/discovery.py | 2 +- devp2p/examples/full_app.py | 2 +- devp2p/kademlia.py | 2 +- devp2p/multiplexer.py | 2 +- devp2p/peer.py | 2 +- devp2p/peermanager.py | 2 +- devp2p/rlpxcipher.py | 2 +- devp2p/tests/test_crypto.py | 2 +- devp2p/tests/test_discovery.py | 2 +- devp2p/tests/test_ecies.py | 2 +- devp2p/tests/test_go_handshake.py | 2 +- devp2p/tests/test_go_signature.py | 2 +- devp2p/tests/test_p2pprotocol.py | 2 +- devp2p/tests/test_peer.py | 2 +- devp2p/tests/test_peermanager.py | 2 +- devp2p/tests/test_rlpxsession.py | 2 +- devp2p/utils.py | 4 +- ...essary-changes-to-let-evm-tests-pass.patch | 50 ++++++++++--- quarkchain/evm/config.py | 2 +- quarkchain/evm/messages.py | 36 +++------ quarkchain/evm/specials.py | 2 +- quarkchain/evm/state.py | 32 ++++++-- quarkchain/evm/tests/new_statetest_utils.py | 2 + quarkchain/evm/tests/test_solidity_abi.py | 2 + .../evm/tests/test_transaction_queue.py | 10 +-- quarkchain/evm/transactions.py | 29 ++++++-- quarkchain/evm/utils.py | 2 +- quarkchain/evm/vm.py | 2 +- quarkchain/p2p/p2p_network.py | 2 +- quarkchain/p2p/poc/peermgr_app.py | 2 +- quarkchain/p2p/poc/poc_app.py | 2 +- quarkchain/rlp/utils.py | 73 +++++++++++++++++++ requirements.txt | 2 +- 37 files changed, 213 insertions(+), 89 deletions(-) create mode 100644 quarkchain/rlp/utils.py diff --git a/.circleci/config.yml b/.circleci/config.yml index 81d4cd0c0..c7977930e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -60,15 +60,15 @@ jobs: pypy3 -m unittest - run: - name: Run EVM Tests + name: Run P2P Tests command: | - git apply fixtures/0001-Necessary-changes-to-let-evm-tests-pass.patch - pypy3 quarkchain/evm/tests/test_state.py fixtures/GeneralStateTests/ + pypy3 -m pytest quarkchain/p2p - run: - name: Run P2P Tests + name: Run EVM Tests command: | - pypy3 -m pytest quarkchain/p2p + git apply fixtures/0001-Necessary-changes-to-let-evm-tests-pass.patch + pypy3 quarkchain/evm/tests/test_state.py fixtures/GeneralStateTests/ - store_artifacts: path: test-reports diff --git a/devp2p/app.py b/devp2p/app.py index 9ea1b4dac..a27edb291 100644 --- a/devp2p/app.py +++ b/devp2p/app.py @@ -6,7 +6,7 @@ from .slogging import get_logger from devp2p import utils from devp2p import crypto -from rlp.utils import decode_hex +from quarkchain.rlp.utils import decode_hex from devp2p import __version__ log = get_logger('app') diff --git a/devp2p/app_helper.py b/devp2p/app_helper.py index 35c188c44..aa013d501 100644 --- a/devp2p/app_helper.py +++ b/devp2p/app_helper.py @@ -5,7 +5,7 @@ from devp2p.discovery import NodeDiscovery from devp2p.crypto import privtopub as privtopub_raw, sha3 from devp2p.utils import host_port_pubkey_to_uri, update_config_with_defaults -from rlp.utils import encode_hex +from quarkchain.rlp.utils import encode_hex import gevent import copy from .slogging import get_logger diff --git a/devp2p/crypto.py b/devp2p/crypto.py index f44145d11..e4f54df3b 100644 --- a/devp2p/crypto.py +++ b/devp2p/crypto.py @@ -5,7 +5,7 @@ import pyelliptic import bitcoin -from rlp.utils import str_to_bytes, safe_ord, ascii_chr +from quarkchain.rlp.utils import str_to_bytes, safe_ord, ascii_chr from hashlib import sha256 import struct from coincurve import PrivateKey, PublicKey diff --git a/devp2p/discovery.py b/devp2p/discovery.py index 7c571c2bc..85b45dc99 100644 --- a/devp2p/discovery.py +++ b/devp2p/discovery.py @@ -8,7 +8,7 @@ import gevent.socket import ipaddress import rlp -from rlp.utils import decode_hex, is_integer, str_to_bytes, bytes_to_str, safe_ord +from quarkchain.rlp.utils import decode_hex, is_integer, str_to_bytes, bytes_to_str, safe_ord from gevent.server import DatagramServer from devp2p import slogging diff --git a/devp2p/examples/full_app.py b/devp2p/examples/full_app.py index cf235b6f1..aa2e3684d 100644 --- a/devp2p/examples/full_app.py +++ b/devp2p/examples/full_app.py @@ -7,7 +7,7 @@ from devp2p.utils import colors, COLOR_END from devp2p import app_helper import rlp -from rlp.utils import encode_hex, decode_hex, is_integer +from quarkchain.rlp.utils import encode_hex, decode_hex, is_integer import gevent try: import ethereum.slogging as slogging diff --git a/devp2p/kademlia.py b/devp2p/kademlia.py index 48fde9e1b..ed37ae0cc 100644 --- a/devp2p/kademlia.py +++ b/devp2p/kademlia.py @@ -23,7 +23,7 @@ import logging from .crypto import sha3 from .utils import big_endian_to_int -from rlp.utils import encode_hex, is_integer, str_to_bytes +from quarkchain.rlp.utils import encode_hex, is_integer, str_to_bytes log = slogging.get_logger('p2p.discovery.kademlia') diff --git a/devp2p/multiplexer.py b/devp2p/multiplexer.py index c65770d19..b4def24a9 100644 --- a/devp2p/multiplexer.py +++ b/devp2p/multiplexer.py @@ -1,7 +1,7 @@ from gevent.queue import Queue from collections import OrderedDict import rlp -from rlp.utils import str_to_bytes, is_integer +from quarkchain.rlp.utils import str_to_bytes, is_integer import struct import sys diff --git a/devp2p/peer.py b/devp2p/peer.py index a7fca5f4f..e5059ad2b 100644 --- a/devp2p/peer.py +++ b/devp2p/peer.py @@ -12,7 +12,7 @@ from devp2p import slogging import gevent.socket from devp2p import rlpxcipher -from rlp.utils import decode_hex +from quarkchain.rlp.utils import decode_hex log = slogging.get_logger('p2p.peer') diff --git a/devp2p/peermanager.py b/devp2p/peermanager.py index f214dafca..7c92a9089 100644 --- a/devp2p/peermanager.py +++ b/devp2p/peermanager.py @@ -14,7 +14,7 @@ from .peer import Peer from devp2p import crypto from devp2p import utils -from rlp.utils import decode_hex +from quarkchain.rlp.utils import decode_hex from devp2p import slogging log = slogging.get_logger('p2p.peermgr') diff --git a/devp2p/rlpxcipher.py b/devp2p/rlpxcipher.py index adafff316..a94dd6d06 100644 --- a/devp2p/rlpxcipher.py +++ b/devp2p/rlpxcipher.py @@ -4,7 +4,7 @@ import os import rlp from rlp import sedes -from rlp.utils import safe_ord, str_to_bytes, ascii_chr +from quarkchain.rlp.utils import safe_ord, str_to_bytes, ascii_chr from devp2p.crypto import sha3 from Crypto.Hash import keccak from devp2p.crypto import ECCx diff --git a/devp2p/tests/test_crypto.py b/devp2p/tests/test_crypto.py index 21a87cab6..7908cff36 100644 --- a/devp2p/tests/test_crypto.py +++ b/devp2p/tests/test_crypto.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from devp2p import crypto -from rlp.utils import decode_hex +from quarkchain.rlp.utils import decode_hex import random import pytest diff --git a/devp2p/tests/test_discovery.py b/devp2p/tests/test_discovery.py index 168117a49..be8cbfa76 100644 --- a/devp2p/tests/test_discovery.py +++ b/devp2p/tests/test_discovery.py @@ -2,7 +2,7 @@ from devp2p import kademlia from devp2p import crypto from devp2p.app import BaseApp -from rlp.utils import decode_hex, encode_hex +from quarkchain.rlp.utils import decode_hex, encode_hex from devp2p.utils import remove_chars import pytest import gevent diff --git a/devp2p/tests/test_ecies.py b/devp2p/tests/test_ecies.py index 1bd988a53..8e41e80dc 100644 --- a/devp2p/tests/test_ecies.py +++ b/devp2p/tests/test_ecies.py @@ -1,5 +1,5 @@ import devp2p.crypto as crypto -from rlp.utils import decode_hex +from quarkchain.rlp.utils import decode_hex def test_ecies_enc(): diff --git a/devp2p/tests/test_go_handshake.py b/devp2p/tests/test_go_handshake.py index 1b8c8a46e..bb5a40512 100644 --- a/devp2p/tests/test_go_handshake.py +++ b/devp2p/tests/test_go_handshake.py @@ -4,7 +4,7 @@ from devp2p.rlpxcipher import RLPxSession from devp2p.crypto import ECCx, privtopub -from rlp.utils import decode_hex +from quarkchain.rlp.utils import decode_hex test_values = \ { "initiator_private_key": "5e173f6ac3c669587538e7727cf19b782a4f2fda07c1eaa662c593e5e85e3051", diff --git a/devp2p/tests/test_go_signature.py b/devp2p/tests/test_go_signature.py index 46148fb1f..02f2a012f 100644 --- a/devp2p/tests/test_go_signature.py +++ b/devp2p/tests/test_go_signature.py @@ -1,5 +1,5 @@ from devp2p.crypto import ecdsa_sign, mk_privkey, privtopub, ecdsa_recover, ECCx -from rlp.utils import decode_hex +from quarkchain.rlp.utils import decode_hex import pyelliptic diff --git a/devp2p/tests/test_p2pprotocol.py b/devp2p/tests/test_p2pprotocol.py index eaf0a8a71..1b1c6e104 100644 --- a/devp2p/tests/test_p2pprotocol.py +++ b/devp2p/tests/test_p2pprotocol.py @@ -4,7 +4,7 @@ from devp2p.multiplexer import Packet from devp2p.utils import remove_chars import pytest -from rlp.utils import decode_hex +from quarkchain.rlp.utils import decode_hex # notify peer of successfulll handshake! # so other protocols get registered # so other protocols can do their handshake diff --git a/devp2p/tests/test_peer.py b/devp2p/tests/test_peer.py index 922adcb2a..a89bccacc 100644 --- a/devp2p/tests/test_peer.py +++ b/devp2p/tests/test_peer.py @@ -11,7 +11,7 @@ import time import gevent import copy -from rlp.utils import encode_hex, decode_hex, str_to_bytes +from quarkchain.rlp.utils import encode_hex, decode_hex, str_to_bytes def get_connected_apps(): diff --git a/devp2p/tests/test_peermanager.py b/devp2p/tests/test_peermanager.py index 26efb62bf..a973df06b 100644 --- a/devp2p/tests/test_peermanager.py +++ b/devp2p/tests/test_peermanager.py @@ -1,7 +1,7 @@ from devp2p import peermanager from devp2p import crypto from devp2p.app import BaseApp -from rlp.utils import encode_hex +from quarkchain.rlp.utils import encode_hex import devp2p.muxsession import rlp import devp2p.p2p_protocol diff --git a/devp2p/tests/test_rlpxsession.py b/devp2p/tests/test_rlpxsession.py index 7e117521c..e17835f7d 100644 --- a/devp2p/tests/test_rlpxsession.py +++ b/devp2p/tests/test_rlpxsession.py @@ -2,7 +2,7 @@ from devp2p.crypto import mk_privkey, ECCx, sha3 from devp2p.multiplexer import Multiplexer, Packet from devp2p.utils import remove_chars -from rlp.utils import decode_hex, str_to_bytes +from quarkchain.rlp.utils import decode_hex, str_to_bytes import struct diff --git a/devp2p/utils.py b/devp2p/utils.py index 9cc458b8b..c930fa4ab 100644 --- a/devp2p/utils.py +++ b/devp2p/utils.py @@ -1,8 +1,8 @@ from __future__ import print_function import struct import rlp -from rlp.utils import encode_hex, decode_hex, str_to_bytes, bytes_to_str -from rlp.utils import safe_ord +from quarkchain.rlp.utils import encode_hex, decode_hex, str_to_bytes, bytes_to_str +from quarkchain.rlp.utils import safe_ord import collections import sys diff --git a/fixtures/0001-Necessary-changes-to-let-evm-tests-pass.patch b/fixtures/0001-Necessary-changes-to-let-evm-tests-pass.patch index 177c7dc50..853582605 100644 --- a/fixtures/0001-Necessary-changes-to-let-evm-tests-pass.patch +++ b/fixtures/0001-Necessary-changes-to-let-evm-tests-pass.patch @@ -14,10 +14,10 @@ python3 quarkchain/evm/tests/test_state.py fixtures/GeneralStateTests/ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/quarkchain/evm/messages.py b/quarkchain/evm/messages.py -index e59be92..7af6160 100644 +index 0a32dd3..f043e1f 100644 --- a/quarkchain/evm/messages.py +++ b/quarkchain/evm/messages.py -@@ -154,8 +154,8 @@ def validate_transaction(state, tx): +@@ -136,8 +136,8 @@ def validate_transaction(state, tx): if not tx.sender: # sender is set and validated on Transaction initialization raise UnsignedTransaction(tx) @@ -28,7 +28,7 @@ index e59be92..7af6160 100644 # (2) the transaction nonce is valid (equivalent to the # sender account's current nonce); -@@ -201,7 +201,7 @@ def apply_message(state, msg=None, **kwargs): +@@ -183,7 +183,7 @@ def apply_message(state, msg=None, **kwargs): return bytearray_to_bytestr(data) if result else None @@ -37,7 +37,7 @@ index e59be92..7af6160 100644 """tx_wrapper_hash is the hash for quarkchain.core.Transaction TODO: remove quarkchain.core.Transaction wrapper and use evm.Transaction directly """ -@@ -442,9 +442,7 @@ def _apply_msg(ext, msg, code): +@@ -424,9 +424,7 @@ def _apply_msg(ext, msg, code): def mk_contract_address(sender, full_shard_id, nonce): @@ -49,36 +49,62 @@ index e59be92..7af6160 100644 def create_contract(ext, msg): diff --git a/quarkchain/evm/state.py b/quarkchain/evm/state.py -index 600f091..4a47b2c 100644 +index ca4094b..0541f25 100644 --- a/quarkchain/evm/state.py +++ b/quarkchain/evm/state.py -@@ -56,15 +56,15 @@ class Account(rlp.Serializable): +@@ -55,24 +55,23 @@ class _Account(rlp.Serializable): ('balance', big_endian_int), ('storage', trie_root), ('code_hash', hash32), - ('full_shard_id', BigEndianInt(4)), ] + + class Account(rlp.Serializable): + - def __init__(self, nonce, balance, storage, code_hash, full_shard_id, env, address, db=None): + def __init__(self, nonce, balance, storage, code_hash, full_shard_id=0, env=None, address=None, db=None): self.db = env.db if db is None else db assert isinstance(db, Db) self.env = env self.address = address -- super(Account, self).__init__(nonce, balance, storage, code_hash, full_shard_id) + +- acc = _Account(nonce, balance, storage, code_hash, full_shard_id) ++ acc = _Account(nonce, balance, storage, code_hash) + self.nonce = acc.nonce + self.balance = acc.balance + self.storage = acc.storage + self.code_hash = acc.code_hash +- self.full_shard_id = acc.full_shard_id + self.full_shard_id = full_shard_id -+ super(Account, self).__init__(nonce, balance, storage, code_hash) + self.storage_cache = {} self.storage_trie = SecureTrie(Trie(self.db)) - self.storage_trie.root_hash = self.storage +@@ -194,7 +193,6 @@ class State: + balance=o.balance, + storage=o.storage, + code_hash=o.code_hash, +- full_shard_id=o.full_shard_id, + env=self.env, + address=address, + db=self.db, +@@ -399,7 +397,7 @@ class State: + self.deletes.extend(acct.storage_trie.deletes) + self.changed[addr] = True + if self.account_exists(addr) or allow_empties: +- _acct = _Account(acct.nonce, acct.balance, acct.storage, acct.code_hash, acct.full_shard_id) ++ _acct = _Account(acct.nonce, acct.balance, acct.storage, acct.code_hash) + self.trie.update(addr, rlp.encode(_acct)) + if self.executing_on_head: + self.db.put(b'address:' + addr, rlp.encode(_acct)) diff --git a/quarkchain/evm/transactions.py b/quarkchain/evm/transactions.py -index 7ee7221..6836d93 100644 +index c4758ec..02be464 100644 --- a/quarkchain/evm/transactions.py +++ b/quarkchain/evm/transactions.py -@@ -72,7 +72,7 @@ class Transaction(rlp.Serializable): +@@ -71,7 +71,7 @@ class Transaction(rlp.Serializable): + def __init__(self, nonce, gasprice, startgas, to, value, data, v=0, r=0, s=0, from_full_shard_id=0, to_full_shard_id=0, network_id=1, version=0): - self.data = None - self.shard_size = 0 + self.shard_size = 1 diff --git a/quarkchain/evm/config.py b/quarkchain/evm/config.py index c37b1cc8b..8f8f232e6 100644 --- a/quarkchain/evm/config.py +++ b/quarkchain/evm/config.py @@ -1,4 +1,4 @@ -from rlp.utils import decode_hex +from quarkchain.rlp.utils import decode_hex from quarkchain.evm import utils from quarkchain.db import InMemoryDb, Db diff --git a/quarkchain/evm/messages.py b/quarkchain/evm/messages.py index e59be921b..04213c946 100644 --- a/quarkchain/evm/messages.py +++ b/quarkchain/evm/messages.py @@ -7,7 +7,7 @@ from quarkchain.evm.utils import int256, safe_ord, bytearray_to_bytestr from rlp.sedes import big_endian_int, binary, CountableList, BigEndianInt from rlp.sedes.binary import Binary -from rlp.utils import decode_hex, encode_hex +from quarkchain.rlp.utils import decode_hex, encode_hex from quarkchain.evm import utils # FIXME: use eth_utils from quarkchain.evm import bloom # FIXME: use eth_bloom from quarkchain.evm import transactions @@ -92,27 +92,6 @@ class Receipt(rlp.Serializable): ("contract_full_shard_id", BigEndianInt(4)), ] - def __init__( - self, - state_root, - gas_used, - logs, - contract_address, - contract_full_shard_id, - bloom=None, - ): - # does not call super.__init__ as bloom should not be an attribute but - # a property - self.state_root = state_root - self.gas_used = gas_used - self.logs = logs - if bloom is not None and bloom != self.bloom: - raise ValueError("Invalid bloom filter") - self.contract_address = contract_address - self.contract_full_shard_id = contract_full_shard_id - self._cached_rlp = None - self._mutable = True - @property def bloom(self): bloomables = [x.bloomables() for x in self.logs] @@ -120,12 +99,15 @@ def bloom(self): def mk_receipt(state, success, logs, contract_address, contract_full_shard_id): + bloomables = [x.bloomables() for x in logs] + ret_bloom = bloom.bloom_from_list(utils.flatten(bloomables)) o = Receipt( - b"\x01" if success else b"", - state.gas_used, - logs, - contract_address, - contract_full_shard_id, + state_root=b"\x01" if success else b"", + gas_used=state.gas_used, + bloom=ret_bloom, + logs=logs, + contract_address=contract_address, + contract_full_shard_id=contract_full_shard_id, ) return o diff --git a/quarkchain/evm/specials.py b/quarkchain/evm/specials.py index 43f3f381f..0f38d72e3 100644 --- a/quarkchain/evm/specials.py +++ b/quarkchain/evm/specials.py @@ -1,7 +1,7 @@ # -*- coding: utf8 -*- from py_ecc.secp256k1 import privtopub, ecdsa_raw_recover, N as secp256k1n import hashlib -from rlp.utils import ascii_chr +from quarkchain.rlp.utils import ascii_chr from quarkchain.evm import utils, opcodes from quarkchain.evm.utils import safe_ord, decode_hex, encode_int32 diff --git a/quarkchain/evm/state.py b/quarkchain/evm/state.py index 600f09117..ca4094b24 100644 --- a/quarkchain/evm/state.py +++ b/quarkchain/evm/state.py @@ -49,8 +49,7 @@ def snapshot_form(val): } -class Account(rlp.Serializable): - +class _Account(rlp.Serializable): fields = [ ('nonce', big_endian_int), ('balance', big_endian_int), @@ -59,12 +58,22 @@ class Account(rlp.Serializable): ('full_shard_id', BigEndianInt(4)), ] + +class Account(rlp.Serializable): + def __init__(self, nonce, balance, storage, code_hash, full_shard_id, env, address, db=None): self.db = env.db if db is None else db assert isinstance(db, Db) self.env = env self.address = address - super(Account, self).__init__(nonce, balance, storage, code_hash, full_shard_id) + + acc = _Account(nonce, balance, storage, code_hash, full_shard_id) + self.nonce = acc.nonce + self.balance = acc.balance + self.storage = acc.storage + self.code_hash = acc.code_hash + self.full_shard_id = acc.full_shard_id + self.storage_cache = {} self.storage_trie = SecureTrie(Trie(self.db)) self.storage_trie.root_hash = self.storage @@ -179,7 +188,17 @@ def get_and_cache_account(self, address): else: rlpdata = self.trie.get(address) if rlpdata != trie.BLANK_NODE: - o = rlp.decode(rlpdata, Account, env=self.env, address=address, db=self.db) + o = rlp.decode(rlpdata, _Account) + o = Account( + nonce=o.nonce, + balance=o.balance, + storage=o.storage, + code_hash=o.code_hash, + full_shard_id=o.full_shard_id, + env=self.env, + address=address, + db=self.db, + ) else: o = Account.blank_account( self.env, address, self.full_shard_id, self.config['ACCOUNT_INITIAL_NONCE'], db=self.db) @@ -380,9 +399,10 @@ def commit(self, allow_empties=False): self.deletes.extend(acct.storage_trie.deletes) self.changed[addr] = True if self.account_exists(addr) or allow_empties: - self.trie.update(addr, rlp.encode(acct)) + _acct = _Account(acct.nonce, acct.balance, acct.storage, acct.code_hash, acct.full_shard_id) + self.trie.update(addr, rlp.encode(_acct)) if self.executing_on_head: - self.db.put(b'address:' + addr, rlp.encode(acct)) + self.db.put(b'address:' + addr, rlp.encode(_acct)) else: self.trie.delete(addr) if self.executing_on_head: diff --git a/quarkchain/evm/tests/new_statetest_utils.py b/quarkchain/evm/tests/new_statetest_utils.py index 3e5d4ca99..f9a2b57f0 100644 --- a/quarkchain/evm/tests/new_statetest_utils.py +++ b/quarkchain/evm/tests/new_statetest_utils.py @@ -95,7 +95,9 @@ def compute_state_test_unit(state, txdata, indices, konfig): if 'secretKey' in txdata: tx.sign(decode_hex(remove_0x_head(txdata['secretKey']))) else: + tx._in_mutable_context = True tx.v = parse_int_or_hex(txdata['v']) + tx._in_mutable_context = False # Run it prev = state.to_dict() success, output = apply_transaction(state, tx) diff --git a/quarkchain/evm/tests/test_solidity_abi.py b/quarkchain/evm/tests/test_solidity_abi.py index 8532ad708..81cd3186a 100644 --- a/quarkchain/evm/tests/test_solidity_abi.py +++ b/quarkchain/evm/tests/test_solidity_abi.py @@ -93,8 +93,10 @@ def test_typed_signature_hash(self): def test_recover(self): """ """ + self.raw_tx._in_mutable_context = True self.raw_tx.version = 1 self.raw_tx.r = 0xb5145678e43df2b7ea8e0e969e51dbf72c956dd52e234c95393ad68744394855 self.raw_tx.s = 0x44515b465dbbf746a484239c11adb98f967e35347e17e71b84d850d8e5c38a6a self.raw_tx.v = 0x1b + self.raw_tx._in_mutable_context = False assert self.raw_tx.sender == bytes.fromhex('8b74a79290a437aa9589be3227d9bb81b22beff1') diff --git a/quarkchain/evm/tests/test_transaction_queue.py b/quarkchain/evm/tests/test_transaction_queue.py index e183bad07..23dbb5475 100644 --- a/quarkchain/evm/tests/test_transaction_queue.py +++ b/quarkchain/evm/tests/test_transaction_queue.py @@ -4,7 +4,7 @@ from quarkchain.evm.transaction_queue import OrderableTx, TransactionQueue -def make_test_tx(s=100000, g=50, data='', nonce=0): +def make_test_tx(s=100000, g=50, data=b'', nonce=0): return Transaction(nonce=nonce, startgas=s, gasprice=g, value=0, data=data, to=b'\x35' * 20) @@ -38,10 +38,10 @@ def test(self): print('Test successful') def test_diff(self): - tx1 = make_test_tx(data='foo') - tx2 = make_test_tx(data='bar') - tx3 = make_test_tx(data='baz') - tx4 = make_test_tx(data='foobar') + tx1 = make_test_tx(data=b'foo') + tx2 = make_test_tx(data=b'bar') + tx3 = make_test_tx(data=b'baz') + tx4 = make_test_tx(data=b'foobar') q1 = TransactionQueue() for tx in [tx1, tx2, tx3, tx4]: q1.add_transaction(tx) diff --git a/quarkchain/evm/transactions.py b/quarkchain/evm/transactions.py index 7ee722189..acbccecc2 100644 --- a/quarkchain/evm/transactions.py +++ b/quarkchain/evm/transactions.py @@ -6,7 +6,7 @@ from quarkchain.evm.utils import TT256, mk_contract_address, ecsign, ecrecover_to_pub, normalize_key from quarkchain.evm.utils import encode_hex from rlp.sedes import big_endian_int, binary, BigEndianInt -from rlp.utils import str_to_bytes, ascii_chr +from quarkchain.rlp.utils import str_to_bytes, ascii_chr from quarkchain.evm import opcodes from quarkchain.utils import sha3_256, is_p2, check @@ -71,7 +71,6 @@ class Transaction(rlp.Serializable): def __init__(self, nonce, gasprice, startgas, to, value, data, v=0, r=0, s=0, from_full_shard_id=0, to_full_shard_id=0, network_id=1, version=0): - self.data = None self.shard_size = 0 to = utils.normalize_address(to, allow_blank=True) @@ -129,7 +128,10 @@ def sign(self, key, network_id=None): self.network_id = network_id key = normalize_key(key) + self._in_mutable_context = True self.v, self.r, self.s = ecsign(self.hash_unsigned, key) + self.version = 0 + self._in_mutable_context = False self._sender = utils.privtoaddr(key) return self @@ -140,7 +142,7 @@ def hash(self): @property def hash_unsigned(self): - return sha3_256(rlp.encode(self, UnsignedTransaction)) + return sha3_256(rlp.encode(unsigned_tx_from_tx(self), UnsignedTransaction)) @property def hash_typed(self): @@ -148,7 +150,7 @@ def hash_typed(self): def to_dict(self): d = {} - for name, _ in self.__class__.fields: + for name, _ in self.__class__._meta.fields: d[name] = getattr(self, name) if name in ('to', 'data'): d[name] = '0x' + encode_hex(d[name]) @@ -223,4 +225,21 @@ def check_low_s_homestead(self): raise InvalidTransaction("Invalid signature S value!") -UnsignedTransaction = Transaction.exclude(['v', 'r', 's', 'version']) +class UnsignedTransaction(rlp.Serializable): + fields = [ + (field, sedes) for field, sedes in Transaction._meta.fields + if field not in ['v', 'r', 's', 'version'] + ] + +def unsigned_tx_from_tx(tx): + return UnsignedTransaction( + nonce=tx.nonce, + gasprice=tx.gasprice, + startgas=tx.startgas, + to=tx.to, + value=tx.value, + data=tx.data, + from_full_shard_id=tx.from_full_shard_id, + to_full_shard_id=tx.to_full_shard_id, + network_id=tx.network_id, + ) diff --git a/quarkchain/evm/utils.py b/quarkchain/evm/utils.py index c2c4b178b..680046333 100644 --- a/quarkchain/evm/utils.py +++ b/quarkchain/evm/utils.py @@ -2,7 +2,7 @@ import sys import rlp from rlp.sedes import big_endian_int, BigEndianInt, Binary -from rlp.utils import decode_hex, encode_hex, ascii_chr, str_to_bytes +from quarkchain.rlp.utils import decode_hex, encode_hex, ascii_chr, str_to_bytes import random from quarkchain.utils import sha3_256 as sha3 diff --git a/quarkchain/evm/vm.py b/quarkchain/evm/vm.py index c2b35f156..aea23036d 100644 --- a/quarkchain/evm/vm.py +++ b/quarkchain/evm/vm.py @@ -1,7 +1,7 @@ # Modified based on pyethereum under MIT license import sys import copy -from rlp.utils import encode_hex, ascii_chr +from quarkchain.rlp.utils import encode_hex, ascii_chr from quarkchain.evm import utils from quarkchain.evm import opcodes from quarkchain.evm.slogging import get_logger diff --git a/quarkchain/p2p/p2p_network.py b/quarkchain/p2p/p2p_network.py index 2f98bcd98..aa06228fd 100644 --- a/quarkchain/p2p/p2p_network.py +++ b/quarkchain/p2p/p2p_network.py @@ -13,7 +13,7 @@ from devp2p.service import BaseService, WiredService from devp2p.crypto import privtopub as privtopub_raw, sha3 from devp2p.utils import host_port_pubkey_to_uri, update_config_with_defaults -from rlp.utils import decode_hex, encode_hex +from quarkchain.rlp.utils import decode_hex, encode_hex from quarkchain.core import random_bytes from quarkchain.cluster.protocol import P2PConnection, ROOT_SHARD_ID diff --git a/quarkchain/p2p/poc/peermgr_app.py b/quarkchain/p2p/poc/peermgr_app.py index 47eff0c2b..5eb536025 100644 --- a/quarkchain/p2p/poc/peermgr_app.py +++ b/quarkchain/p2p/poc/peermgr_app.py @@ -6,7 +6,7 @@ from devp2p.utils import colors, COLOR_END from devp2p import app_helper import rlp -from rlp.utils import encode_hex, decode_hex, is_integer +from quarkchain.rlp.utils import encode_hex, decode_hex, is_integer import gevent try: diff --git a/quarkchain/p2p/poc/poc_app.py b/quarkchain/p2p/poc/poc_app.py index ca498f88f..ba3b727c4 100644 --- a/quarkchain/p2p/poc/poc_app.py +++ b/quarkchain/p2p/poc/poc_app.py @@ -15,7 +15,7 @@ ) from devp2p import app_helper import rlp -from rlp.utils import encode_hex, decode_hex, is_integer +from quarkchain.rlp.utils import encode_hex, decode_hex, is_integer import gevent try: diff --git a/quarkchain/rlp/utils.py b/quarkchain/rlp/utils.py new file mode 100644 index 000000000..1dca8ea8b --- /dev/null +++ b/quarkchain/rlp/utils.py @@ -0,0 +1,73 @@ +import abc +import binascii +from math import ceil + + +class Atomic(type.__new__(abc.ABCMeta, "metaclass", (), {})): + """ABC for objects that can be RLP encoded as is.""" + + pass + + +Atomic.register(str) +Atomic.register(bytes) + + +""" +from pyrlp<1.0.0 +""" + + +def str_to_bytes(value): + if isinstance(value, bytearray): + value = bytes(value) + if isinstance(value, bytes): + return value + return bytes(value, "utf-8") + + +def bytes_to_str(value): + if isinstance(value, str): + return value + return value.decode("utf-8") + + +def ascii_chr(value): + return bytes([value]) + + +def int_to_big_endian(value): + byte_length = max(ceil(value.bit_length() / 8), 1) + return (value).to_bytes(byte_length, byteorder="big") + + +def big_endian_to_int(value): + return int.from_bytes(value, byteorder="big") + + +def is_integer(value): + return isinstance(value, int) + + +def decode_hex(s): + if isinstance(s, str): + return bytes.fromhex(s) + if isinstance(s, (bytes, bytearray)): + return binascii.unhexlify(s) + raise TypeError("Value must be an instance of str or bytes") + + +def encode_hex(b): + if isinstance(b, str): + b = bytes(b, "utf-8") + if isinstance(b, (bytes, bytearray)): + return str(binascii.hexlify(b), "utf-8") + raise TypeError("Value must be an instance of str or bytes") + + +def safe_ord(c): + try: + return ord(c) + except TypeError: + assert isinstance(c, int) + return c diff --git a/requirements.txt b/requirements.txt index 4bd976954..9a0a81e7a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,6 +25,7 @@ pytest-asyncio==0.9.0 cryptography==2.3.1 upnpclient==0.0.8 netifaces==0.10.7 +rlp>=1.0.0,<2.0.0 # pyethapp/accounts.py dependency pbkdf2 @@ -37,6 +38,5 @@ gevent==1.3.4 bitcoin ipaddress coverage -rlp>=0.6.0,<0.7.0 miniupnpc repoze.lru==0.7