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