commit d85d96b32549ecf24f9a8f8034f8127cb7643644
parent 4788326c4e7348da27c945a5c576582eeacfc14b
Author: nolash <dev@holbrook.no>
Date:   Mon,  8 Feb 2021 11:23:07 +0100
Decode
Diffstat:
7 files changed, 164 insertions(+), 30 deletions(-)
diff --git a/cic_tools/eth/address.py b/cic_tools/eth/address.py
@@ -0,0 +1,27 @@
+# third-party imports
+import sha3
+from hexathon import (
+        strip_0x,
+        uniform,
+    )
+
+
+def to_checksum(address_hex):
+        address_hex = strip_0x(address_hex)
+        address_hex = uniform(address_hex)
+        h = sha3.keccak_256()
+        h.update(address_hex.encode('utf-8'))
+        z = h.digest()
+
+        checksum_address_hex = '0x'
+
+        for (i, c) in enumerate(address_hex):
+            if c in '1234567890':
+                checksum_address_hex += c
+            elif c in 'abcdef':
+                if z[int(i / 2)] & (0x80 >> ((i % 2) * 4)) > 1:
+                    checksum_address_hex += c.upper()
+                else:
+                    checksum_address_hex += c
+
+        return checksum_address_hex
diff --git a/cic_tools/eth/checksum.py b/cic_tools/eth/checksum.py
@@ -1,28 +0,0 @@
-# third-party imports
-import sha3
-from hexathon import (
-        strip_0x,
-        uniform,
-    )
-
-
-def to_checksum(address_hex):
-    
-        address_hex = strip_0x(address_hex)
-        address_hex = uniform(address_hex)
-        h = sha3.keccak_256()
-        h.update(address_hex.encode('utf-8'))
-        z = h.digest()
-
-        checksum_address_hex = '0x'
-
-        for (i, c) in enumerate(address_hex):
-            if c in '1234567890':
-                checksum_address_hex += c
-            elif c in 'abcdef':
-                if z[int(i / 2)] & (0x80 >> ((i % 2) * 4)) > 1:
-                    checksum_address_hex += c.upper()
-                else:
-                    checksum_address_hex += c
-
-        return checksum_address_hex
diff --git a/cic_tools/eth/runnable/balance.py b/cic_tools/eth/runnable/balance.py
@@ -25,7 +25,7 @@ import sha3
 from eth_abi import encode_single
 
 # local imports
-from cic_tools.eth.checksum import to_checksum
+from cic_tools.eth.address import to_checksum
 from cic_tools.eth.method import (
         jsonrpc_template,
         erc20_balance,
diff --git a/cic_tools/eth/runnable/checksum.py b/cic_tools/eth/runnable/checksum.py
@@ -2,7 +2,7 @@
 import sys
 
 # local imports
-from cic_tools.eth.checksum import to_checksum
+from cic_tools.eth.address import to_checksum
 
 
 print(to_checksum(sys.argv[1]))
diff --git a/cic_tools/eth/runnable/decode.py b/cic_tools/eth/runnable/decode.py
@@ -0,0 +1,51 @@
+#!python3
+
+"""Decode raw transaction
+
+.. moduleauthor:: Louis Holbrook <dev@holbrook.no>
+.. pgp:: 0826EDA1702D1E87C6E2875121D2E7BB88C2A746 
+
+"""
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# standard imports
+import os
+import json
+import argparse
+import logging
+
+# third-party imports
+from cic_tools.eth.tx import unpack_signed
+
+
+logging.basicConfig(level=logging.WARNING)
+logg = logging.getLogger()
+
+default_abi_dir = os.environ.get('ETH_ABI_DIR', '/usr/share/local/cic/solidity/abi')
+default_eth_provider = os.environ.get('ETH_PROVIDER', 'http://localhost:8545')
+
+argparser = argparse.ArgumentParser()
+argparser.add_argument('-v', action='store_true', help='Be verbose')
+argparser.add_argument('-i', '--chain-id', dest='i', type=str, help='Numeric network id')
+argparser.add_argument('tx', type=str, help='hex-encoded signed raw transaction')
+args = argparser.parse_args()
+
+if args.v:
+    logg.setLevel(logging.DEBUG)
+
+(chain_name, chain_id) = args.i.split(':')
+
+
+def main():
+    tx_raw = args.tx
+    if tx_raw[:2] == '0x':
+        tx_raw = tx_raw[2:]
+    tx_raw_bytes = bytes.fromhex(tx_raw)
+    tx = unpack_signed(tx_raw_bytes, int(chain_id))
+    for k in tx.keys():
+        print('{}: {}'.format(k, tx[k]))
+
+
+if __name__ == '__main__':
+    main()
diff --git a/cic_tools/eth/tx.py b/cic_tools/eth/tx.py
@@ -0,0 +1,83 @@
+# standard imports
+import logging
+
+# third-party imports
+import sha3
+from eth_keys import KeyAPI
+from eth_keys.backends import NativeECCBackend
+from rlp import decode as rlp_decode
+from rlp import encode as rlp_encode
+
+# local imports
+from .address import to_checksum
+
+logg = logging.getLogger(__name__)
+
+
+field_debugs = [
+        'nonce',
+        'gasPrice',
+        'gas',
+        'to',
+        'value',
+        'data',
+        'v',
+        'r',
+        's',
+        ]
+
+def unpack_signed(tx_raw_bytes, chain_id=1):
+    d = rlp_decode(tx_raw_bytes)
+
+    logg.debug('decoding using chain id {}'.format(chain_id))
+    j = 0
+    for i in d:
+        logg.debug('decoded {}: {}'.format(field_debugs[j], i.hex()))
+        j += 1
+    vb = chain_id
+    if chain_id != 0:
+        v = int.from_bytes(d[6], 'big')
+        vb = v - (chain_id * 2) - 35
+    s = b''.join([d[7], d[8], bytes([vb])])
+    so = KeyAPI.Signature(signature_bytes=s)
+
+    h = sha3.keccak_256()
+    h.update(rlp_encode(d))
+    signed_hash = h.digest()
+
+    d[6] = chain_id
+    d[7] = b''
+    d[8] = b''
+
+    h = sha3.keccak_256()
+    h.update(rlp_encode(d))
+    unsigned_hash = h.digest()
+    
+    p = so.recover_public_key_from_msg_hash(unsigned_hash)
+    a = p.to_checksum_address()
+    logg.debug('decoded recovery byte {}'.format(vb))
+    logg.debug('decoded address {}'.format(a))
+    logg.debug('decoded signed hash {}'.format(signed_hash.hex()))
+    logg.debug('decoded unsigned hash {}'.format(unsigned_hash.hex()))
+
+    to = d[3].hex() or None
+    if to != None:
+        to = to_checksum(to)
+
+    return {
+        'from': a,
+        'nonce': int.from_bytes(d[0], 'big'),
+        'gasPrice': int.from_bytes(d[1], 'big'),
+        'gas': int.from_bytes(d[2], 'big'),
+        'to': to, 
+        'value': int.from_bytes(d[4], 'big'),
+        'data': '0x' + d[5].hex(),
+        'v': chain_id,
+        'r': '0x' + s[:32].hex(),
+        's': '0x' + s[32:64].hex(),
+        'chainId': chain_id,
+        'hash': '0x' + signed_hash.hex(),
+        'hash_unsigned': '0x' + unsigned_hash.hex(),
+            }
+
+
diff --git a/requirements.txt b/requirements.txt
@@ -11,3 +11,4 @@ crypto-dev-signer==0.4.13rc2
 pysha3==1.0.2
 hexathon==0.0.1a2
 eth-abi==2.1.1
+eth-keys==0.3.3