From b9788adb1855a21f50bbfd4ac90693aca96533fe Mon Sep 17 00:00:00 2001 From: nolash Date: Sat, 12 Jun 2021 21:42:04 +0200 Subject: [PATCH] Add tx reverse re-pack --- chainlib/eth/tx.py | 29 +++++++++++++++++++++++-- requirements.txt | 2 +- setup.cfg | 2 +- tests/test_tx.py | 53 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 80 insertions(+), 6 deletions(-) diff --git a/chainlib/eth/tx.py b/chainlib/eth/tx.py index f347028..edcc546 100644 --- a/chainlib/eth/tx.py +++ b/chainlib/eth/tx.py @@ -14,6 +14,7 @@ from rlp import decode as rlp_decode from rlp import encode as rlp_encode from crypto_dev_signer.eth.transaction import EIP155Transaction from crypto_dev_signer.encoding import public_key_to_address +from crypto_dev_signer.eth.encoding import chain_id_to_v from potaahto.symbols import snake_and_camel @@ -71,6 +72,25 @@ def count_confirmed(address): return count(address, True) +def pack(tx_src, chain_spec): + if isinstance(tx_src, Tx): + tx_src = tx_src.as_dict() + tx = EIP155Transaction(tx_src, tx_src['nonce'], chain_spec.chain_id()) + + signature = bytearray(65) + cursor = 0 + for a in [ + tx_src['r'], + tx_src['s'], + ]: + for b in bytes.fromhex(strip_0x(a)): + signature[cursor] = b + cursor += 1 + signature[cursor] = tx_src['v'] + tx.apply_signature(chain_spec.chain_id(), signature, literal_v=True) + return tx.rlp_serialize() + + def unpack(tx_raw_bytes, chain_spec): chain_id = chain_spec.chain_id() tx = __unpack_raw(tx_raw_bytes, chain_id) @@ -154,10 +174,11 @@ def __unpack_raw(tx_raw_bytes, chain_id=1): 'gas': d[2], 'value': d[4], 'data': data, - 'v': chain_id, + 'v': v, + 'recovery_byte': vb, 'r': add_0x(sig[:32].hex()), 's': add_0x(sig[32:64].hex()), - 'chainId': chain_id, + 'chainId': vb, #chain_id, 'hash': add_0x(signed_hash.hex()), 'hash_unsigned': add_0x(unsigned_hash.hex()), } @@ -377,6 +398,10 @@ class Tx: return snake_and_camel(src) + def as_dict(self): + return self.src + + def apply_receipt(self, rcpt): rcpt = self.src_normalize(rcpt) logg.debug('rcpt {}'.format(rcpt)) diff --git a/requirements.txt b/requirements.txt index ae265d8..3480daa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -crypto-dev-signer~=0.4.14b3 +crypto-dev-signer~=0.4.14b5 pysha3==1.0.2 hexathon~=0.0.1a7 websocket-client==0.57.0 diff --git a/setup.cfg b/setup.cfg index 5e8f3bf..5c079ed 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = chainlib -version = 0.0.3rc3 +version = 0.0.3rc4 description = Generic blockchain access library and tooling author = Louis Holbrook author_email = dev@holbrook.no diff --git a/tests/test_tx.py b/tests/test_tx.py index 548472d..ca976b9 100644 --- a/tests/test_tx.py +++ b/tests/test_tx.py @@ -1,5 +1,7 @@ # standard imports -import unittest +import os +import unittest +import logging # local imports from chainlib.eth.unittest.ethtester import EthTesterCase @@ -10,9 +12,26 @@ from chainlib.eth.gas import ( ) from chainlib.eth.tx import ( unpack, + pack, + raw, + transaction, TxFormat, + TxFactory, + Tx, ) -from hexathon import strip_0x +from chainlib.eth.contract import ( + ABIContractEncoder, + ABIContractType, + ) +from chainlib.eth.address import to_checksum_address +from hexathon import ( + strip_0x, + add_0x, + ) + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + class TxTestCase(EthTesterCase): @@ -26,5 +45,35 @@ class TxTestCase(EthTesterCase): self.assertEqual(tx['to'], self.accounts[1]) + def test_tx_pack(self): + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + gas_oracle = RPCGasOracle(self.rpc) + + mock_contract = to_checksum_address(add_0x(os.urandom(20).hex())) + + f = TxFactory(self.chain_spec, signer=self.rpc) + enc = ABIContractEncoder() + enc.method('fooMethod') + enc.typ(ABIContractType.UINT256) + enc.uint256(13) + data = enc.get() + tx = f.template(self.accounts[0], mock_contract, use_nonce=True) + tx = f.set_code(tx, data) + (tx_hash, tx_signed_raw_hex) = f.finalize(tx, TxFormat.RLP_SIGNED) + logg.debug('tx result {}'.format(tx)) + o = raw(tx_signed_raw_hex) + r = self.rpc.do(o) + o = transaction(tx_hash) + tx_rpc_src = self.rpc.do(o) + logg.debug('rpc src {}'.format(tx_rpc_src)) + + tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex)) + tx_src = unpack(tx_signed_raw_bytes, self.chain_spec) + txo = Tx(tx_src) + tx_signed_raw_bytes_recovered = pack(txo, self.chain_spec) + logg.debug('o {}'.format(tx_signed_raw_bytes.hex())) + logg.debug('r {}'.format(tx_signed_raw_bytes_recovered.hex())) + self.assertEqual(tx_signed_raw_bytes, tx_signed_raw_bytes_recovered) + if __name__ == '__main__': unittest.main()