chainlib

Generic blockchain access library and tooling
Log | Files | Refs | README | LICENSE

commit d85d96b32549ecf24f9a8f8034f8127cb7643644
parent 4788326c4e7348da27c945a5c576582eeacfc14b
Author: nolash <dev@holbrook.no>
Date:   Mon,  8 Feb 2021 11:23:07 +0100

Decode

Diffstat:
Acic_tools/eth/address.py | 27+++++++++++++++++++++++++++
Dcic_tools/eth/checksum.py | 28----------------------------
Mcic_tools/eth/runnable/balance.py | 2+-
Mcic_tools/eth/runnable/checksum.py | 2+-
Acic_tools/eth/runnable/decode.py | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Acic_tools/eth/tx.py | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mrequirements.txt | 1+
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