commit 6e44b903edf1a58c15f2f5719bf01d20b344e948
parent a7ed9e9ad3b0eb4f6e0c2aac6fc03cdea51f06d4
Author: nolash <dev@holbrook.no>
Date: Fri, 12 Feb 2021 00:24:10 +0100
Add tx get script
Diffstat:
7 files changed, 159 insertions(+), 24 deletions(-)
diff --git a/chainlib/eth/block.py b/chainlib/eth/block.py
@@ -7,7 +7,7 @@ from hexathon import (
even,
)
-def block():
+def block_latest():
o = jsonrpc_template()
o['method'] = 'eth_blockNumber'
return o
diff --git a/chainlib/eth/erc20.py b/chainlib/eth/erc20.py
@@ -22,19 +22,7 @@ erc20_transfer_signature = keccak256_string_to_hex('transfer(address,uint256)')[
class ERC20TxFactory(TxFactory):
- def build(self, tx):
- txe = EIP155Transaction(tx, tx['nonce'], tx['chainId'])
- self.signer.signTransaction(txe)
- tx_raw = txe.rlp_serialize()
- tx_raw_hex = add_0x(tx_raw.hex())
- tx_hash_hex = add_0x(keccak256_hex_to_hex(tx_raw_hex))
-
- o = jsonrpc_template()
- o['method'] = 'eth_sendRawTransaction'
- o['params'].append(tx_raw_hex)
-
- return (tx_hash_hex, o)
-
+
def erc20_balance(self, contract_address, address, sender_address=ZERO_ADDRESS):
o = jsonrpc_template()
diff --git a/chainlib/eth/nonce.py b/chainlib/eth/nonce.py
@@ -21,10 +21,17 @@ class DefaultNonceOracle:
def __init__(self, address, conn):
self.address = address
self.conn = conn
+ self.nonce = self.get()
- def next(self):
+ def get(self):
o = nonce(self.address)
r = self.conn.do(o)
n = strip_0x(r)
return int(n, 16)
+
+
+ def next(self):
+ n = self.nonce
+ self.nonce += 1
+ return n
diff --git a/chainlib/eth/runnable/get.py b/chainlib/eth/runnable/get.py
@@ -0,0 +1,101 @@
+#!python3
+
+"""Token balance query script
+
+.. 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
+import enum
+
+# third-party imports
+from hexathon import (
+ add_0x,
+ strip_0x,
+ even,
+ )
+import sha3
+from eth_abi import encode_single
+
+# local imports
+from chainlib.eth.address import to_checksum
+from chainlib.eth.rpc import (
+ jsonrpc_template,
+ jsonrpc_result,
+ )
+from chainlib.eth.connection import HTTPConnection
+from chainlib.eth.tx import Tx
+from chainlib.eth.block import Block
+
+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('-p', '--provider', dest='p', default=default_eth_provider, type=str, help='Web3 provider url (http only)')
+argparser.add_argument('-t', '--token-address', dest='t', type=str, help='Token address. If not set, will return gas balance')
+argparser.add_argument('-u', '--unsafe', dest='u', action='store_true', help='Auto-convert address to checksum adddress')
+argparser.add_argument('--abi-dir', dest='abi_dir', type=str, default=default_abi_dir, help='Directory containing bytecode and abi (default {})'.format(default_abi_dir))
+argparser.add_argument('-v', action='store_true', help='Be verbose')
+argparser.add_argument('tx_hash', type=str, help='Transaction hash')
+args = argparser.parse_args()
+
+
+if args.v:
+ logg.setLevel(logging.DEBUG)
+
+conn = HTTPConnection(args.p)
+
+tx_hash = args.tx_hash
+
+
+class Status(enum.Enum):
+ UNCONFIRMED = -1
+ REVERTED = 0
+ SUCCESS = 1
+
+
+def main():
+ o = jsonrpc_template()
+ o['method'] = 'eth_getTransactionByHash'
+ o['params'].append(tx_hash)
+ tx_src = conn.do(o)
+
+ tx = None
+ status = -1
+ if tx_src['blockHash'] != None:
+ o = jsonrpc_template()
+ o['method'] = 'eth_getBlockByHash'
+ o['params'].append(tx_src['blockHash'])
+ o['params'].append(True)
+ block_src = conn.do(o)
+ block = Block(block_src)
+ for t in block.txs:
+ if t['hash'] == tx_hash:
+ tx = Tx(t, block)
+ break
+ o = jsonrpc_template()
+ o['method'] = 'eth_getTransactionReceipt'
+ o['params'].append(tx_hash)
+ rcpt = conn.do(o)
+ status = int(strip_0x(rcpt['status']), 16)
+
+ if tx == None:
+ tx = Tx(tx_src)
+ print(tx)
+ status_name = Status(status).name
+ print('status {}'.format(status_name))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/chainlib/eth/runnable/transfer.py b/chainlib/eth/runnable/transfer.py
@@ -18,7 +18,6 @@ import logging
# third-party imports
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
from crypto_dev_signer.keystore import DictKeystore
-from crypto_dev_signer.eth.helper import EthTxExecutor
from hexathon import (
add_0x,
strip_0x,
diff --git a/chainlib/eth/tx.py b/chainlib/eth/tx.py
@@ -3,20 +3,26 @@ import logging
# third-party imports
import sha3
-from hexathon import strip_0x
+from hexathon import (
+ strip_0x,
+ add_0x,
+ )
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
from crypto_dev_signer.eth.transaction import EIP155Transaction
+
# local imports
+from chainlib.hash import keccak256_hex_to_hex
from .address import to_checksum
from .constant import (
MINIMUM_FEE_UNITS,
MINIMUM_FEE_PRICE,
ZERO_ADDRESS,
)
+from .rpc import jsonrpc_template
logg = logging.getLogger(__name__)
@@ -97,6 +103,20 @@ class TxFactory:
self.signer = signer
+ def build(self, tx):
+ txe = EIP155Transaction(tx, tx['nonce'], tx['chainId'])
+ self.signer.signTransaction(txe)
+ tx_raw = txe.rlp_serialize()
+ tx_raw_hex = add_0x(tx_raw.hex())
+ tx_hash_hex = add_0x(keccak256_hex_to_hex(tx_raw_hex))
+
+ o = jsonrpc_template()
+ o['method'] = 'eth_sendRawTransaction'
+ o['params'].append(tx_raw_hex)
+
+ return (tx_hash_hex, o)
+
+
def template(self, sender, recipient):
gas_price = MINIMUM_FEE_PRICE
if self.gas_oracle != None:
@@ -121,7 +141,6 @@ class TxFactory:
def normalize(self, tx):
txe = EIP155Transaction(tx, tx['nonce'], tx['chainId'])
txes = txe.serialize()
- print(txes)
return {
'from': tx['from'],
'to': txes['to'],
@@ -141,12 +160,18 @@ class TxFactory:
class Tx:
- def __init__(self, src, block):
- self.index = int(strip_0x(src['transactionIndex']), 16)
+ def __init__(self, src, block=None):
+ self.index = -1
+ self.status = -1
+ if block != None:
+ self.index = int(strip_0x(src['transactionIndex']), 16)
self.value = int(strip_0x(src['value']), 16)
self.nonce = int(strip_0x(src['nonce']), 16)
self.hash = strip_0x(src['hash'])
- self.outputs = [strip_0x(src['from'])]
+ address_from = strip_0x(src['from'])
+ self.gasPrice = int(strip_0x(src['gasPrice']), 16)
+ self.gasLimit = int(strip_0x(src['gas']), 16)
+ self.outputs = [to_checksum(address_from)]
inpt = src['input']
if inpt != '0x':
@@ -158,7 +183,7 @@ class Tx:
to = src['to']
if to == None:
to = ZERO_ADDRESS
- self.inputs = [strip_0x(to)]
+ self.inputs = [to_checksum(strip_0x(to))]
self.block = block
self.wire = src['raw']
@@ -170,4 +195,18 @@ class Tx:
def __str__(self):
- return 'from {} to {} value {} input {}'.format(self.outputs[0], self.inputs[0], self.value, self.payload)
+ return """from {}
+to {}
+value {}
+nonce {}
+gasPrice {}
+gasLimit {}
+input {}""".format(
+ self.outputs[0],
+ self.inputs[0],
+ self.value,
+ self.nonce,
+ self.gasPrice,
+ self.gasLimit,
+ self.payload,
+ )
diff --git a/setup.cfg b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = chainlib
-version = 0.0.1a6
+version = 0.0.1a7
description = Generic blockchain access library and tooling
author = Louis Holbrook
author_email = dev@holbrook.no
@@ -37,3 +37,4 @@ console_scripts =
eth-checksum = chainlib.eth.runnable.checksum:main
eth-gas = chainlib.eth.runnable.gas:main
eth-transfer = chainlib.eth.runnable.transfer:main
+ eth-get = chainlib.eth.runnable.get:main