Compare commits
3 Commits
v0.3.0
...
lash/args-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
050b6a9aeb | ||
|
|
9018aefcbe
|
||
|
|
dee523bada
|
34
CHANGELOG
34
CHANGELOG
@@ -1,35 +1,3 @@
|
||||
- 0.3.0
|
||||
* Implement chainlib with new arg and config handling
|
||||
* Implement cli tools on settings module
|
||||
- 0.2.0
|
||||
* Implement chainlib generic tx, block and tx result objects
|
||||
- 0.1.3
|
||||
* Add block author field
|
||||
- 0.1.2
|
||||
* Upgrade chainlib dep
|
||||
- 0.1.1
|
||||
* Add fee_limit, fee_price alias to Tx object
|
||||
- 0.1.0:
|
||||
* Allow nonce ommission in encode when not tx mode
|
||||
* Add rcpt src to tx object
|
||||
- 0.0.27:
|
||||
* Add man pages with chainlib man page generator helper
|
||||
* Remove redundant arg flags from runnables: get
|
||||
- 0.0.26:
|
||||
* Remove manual 0x handling bug in tx
|
||||
- 0.0.25:
|
||||
* Upgrade chainlib to get passphrase file for wallet keyfile
|
||||
- 0.0.24:
|
||||
* Upgrade from hexathon bug breaking compact hex function
|
||||
- 0.0.23:
|
||||
* Make get block args and responses compatible with picky golang marhaling in geth
|
||||
- 0.0.22:
|
||||
* Enable unpack of pre EIP-155 transactions
|
||||
* Allow missing status property of receipts in non-strict modes
|
||||
- 0.0.21:
|
||||
* Remove warnings from cytoolz/rlp in funga-eth
|
||||
- 0.0.15:
|
||||
* Correct inverted addess checksum check for gas cli
|
||||
- 0.0.5-unreleased:
|
||||
- 0.0.5-pending
|
||||
* Receive all ethereum components from chainlib package
|
||||
* Make settings configurable
|
||||
|
||||
16
Makefile
16
Makefile
@@ -1,16 +0,0 @@
|
||||
PREFIX ?= /usr/local
|
||||
BUILD_DIR = build/$(PREFIX)/share/man
|
||||
|
||||
man:
|
||||
mkdir -vp $(BUILD_DIR)
|
||||
chainlib-man.py -b `PYTHONPATH=. python chainlib/eth/runnable/flags.py gas` -v -n eth-gas -d $(BUILD_DIR)/ man
|
||||
chainlib-man.py -b `PYTHONPATH=. python chainlib/eth/runnable/flags.py info` -v -n eth-info -d $(BUILD_DIR)/ man
|
||||
chainlib-man.py -b `PYTHONPATH=. python chainlib/eth/runnable/flags.py get` -v -n eth-get -d $(BUILD_DIR)/ man
|
||||
chainlib-man.py -b `PYTHONPATH=. python chainlib/eth/runnable/flags.py decode` -v -n eth-decode -d $(BUILD_DIR)/ man
|
||||
chainlib-man.py -b `PYTHONPATH=. python chainlib/eth/runnable/flags.py encode` -v -n eth-encode -d $(BUILD_DIR)/ man
|
||||
chainlib-man.py -b `PYTHONPATH=. python chainlib/eth/runnable/flags.py count` -v -n eth-count -d $(BUILD_DIR)/ man
|
||||
chainlib-man.py -b `PYTHONPATH=. python chainlib/eth/runnable/flags.py raw` -v -n eth-raw -d $(BUILD_DIR)/ man
|
||||
chainlib-man.py -b `PYTHONPATH=. python chainlib/eth/runnable/flags.py wait` -v -n eth-wait -d $(BUILD_DIR)/ man
|
||||
chainlib-man.py -b `PYTHONPATH=. python chainlib/eth/runnable/flags.py balance` -v -n eth-balance -d $(BUILD_DIR)/ man
|
||||
|
||||
.PHONY: man
|
||||
@@ -4,7 +4,7 @@ from hexathon import (
|
||||
strip_0x,
|
||||
uniform,
|
||||
)
|
||||
from funga.eth.encoding import (
|
||||
from crypto_dev_signer.encoding import (
|
||||
is_address,
|
||||
is_checksum_address,
|
||||
to_checksum_address,
|
||||
@@ -42,7 +42,3 @@ class AddressChecksum:
|
||||
:returns: Checksum address
|
||||
"""
|
||||
return to_checksum_address(v)
|
||||
|
||||
|
||||
def is_same_address(a, b):
|
||||
return uniform(strip_0x(a)) == uniform(strip_0x(b))
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
# standard imports
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
# external imports
|
||||
from chainlib.jsonrpc import JSONRPCRequest
|
||||
from chainlib.block import Block as BaseBlock
|
||||
from hexathon import (
|
||||
add_0x,
|
||||
strip_0x,
|
||||
compact,
|
||||
to_int as hex_to_int,
|
||||
even,
|
||||
)
|
||||
|
||||
# local imports
|
||||
from chainlib.eth.tx import Tx
|
||||
from .src import Src
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def block_latest(id_generator=None):
|
||||
@@ -42,8 +34,7 @@ def block_by_hash(hsh, include_tx=True, id_generator=None):
|
||||
def block_by_number(n, include_tx=True, id_generator=None):
|
||||
"""Implements chainlib.interface.ChainInterface method
|
||||
"""
|
||||
hx = strip_0x(hex(n))
|
||||
nhx = add_0x(compact(hx), compact_value=True)
|
||||
nhx = add_0x(even(hex(n)[2:]))
|
||||
j = JSONRPCRequest(id_generator)
|
||||
o = j.template()
|
||||
o['method'] = 'eth_getBlockByNumber'
|
||||
@@ -69,21 +60,7 @@ def transaction_count(block_hash, id_generator=None):
|
||||
return j.finalize(o)
|
||||
|
||||
|
||||
def syncing(id_generator=None):
|
||||
"""Request the syncing state of the node
|
||||
|
||||
:param id_generator: JSONRPC id generator
|
||||
:type id_generator: JSONRPCIdGenerator
|
||||
:rtype: dict
|
||||
:returns: rpc query object
|
||||
"""
|
||||
j = JSONRPCRequest(id_generator)
|
||||
o = j.template()
|
||||
o['method'] = 'eth_syncing'
|
||||
return j.finalize(o)
|
||||
|
||||
|
||||
class Block(BaseBlock, Src):
|
||||
class Block(BaseBlock):
|
||||
"""Encapsulates an Ethereum block
|
||||
|
||||
:param src: Block representation data
|
||||
@@ -93,32 +70,21 @@ class Block(BaseBlock, Src):
|
||||
|
||||
tx_generator = Tx
|
||||
|
||||
def __init__(self, src=None):
|
||||
super(Block, self).__init__(src=src)
|
||||
|
||||
self.set_hash(self.src['hash'])
|
||||
def __init__(self, src):
|
||||
self.hash = src['hash']
|
||||
try:
|
||||
self.number = int(strip_0x(self.src['number']), 16)
|
||||
self.number = int(strip_0x(src['number']), 16)
|
||||
except TypeError:
|
||||
self.number = int(self.src['number'])
|
||||
self.txs = self.src['transactions']
|
||||
self.block_src = self.src
|
||||
self.number = int(src['number'])
|
||||
self.txs = src['transactions']
|
||||
self.block_src = src
|
||||
try:
|
||||
self.timestamp = int(strip_0x(self.src['timestamp']), 16)
|
||||
self.timestamp = int(strip_0x(src['timestamp']), 16)
|
||||
except TypeError:
|
||||
self.timestamp = int(self.src['timestamp'])
|
||||
|
||||
try:
|
||||
self.author = self.src['author']
|
||||
except KeyError:
|
||||
self.author = self.src['miner']
|
||||
|
||||
self.fee_limit = self.src['gas_limit']
|
||||
self.fee_cost = self.src['gas_used']
|
||||
self.parent_hash = self.src['parent_hash']
|
||||
self.timestamp = int(src['timestamp'])
|
||||
|
||||
|
||||
def tx_index_by_hash(self, tx_hash):
|
||||
def get_tx(self, tx_hash):
|
||||
i = 0
|
||||
idx = -1
|
||||
tx_hash = add_0x(tx_hash)
|
||||
@@ -136,28 +102,3 @@ class Block(BaseBlock, Src):
|
||||
raise AttributeError('tx {} not found in block {}'.format(tx_hash, self.hash))
|
||||
return idx
|
||||
|
||||
|
||||
def to_human(self):
|
||||
s = """hash: {}
|
||||
number: {}
|
||||
parent: {}
|
||||
timestamp: {}
|
||||
time: {}
|
||||
author: {}
|
||||
gas_limit: {}
|
||||
gas_used: {}
|
||||
txs: {}
|
||||
""".format(
|
||||
self.hash,
|
||||
self.number,
|
||||
self.parent_hash,
|
||||
self.timestamp,
|
||||
datetime.datetime.fromtimestamp(self.timestamp),
|
||||
self.author,
|
||||
hex_to_int(self.fee_limit),
|
||||
hex_to_int(self.fee_cost),
|
||||
len(self.txs),
|
||||
)
|
||||
|
||||
return s
|
||||
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
# standard imports
|
||||
import os
|
||||
import logging
|
||||
|
||||
# external imports
|
||||
from chainlib.cli import Rpc as BaseRpc
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
from chainlib.cli import (
|
||||
ArgumentParser,
|
||||
argflag_std_read,
|
||||
argflag_std_write,
|
||||
argflag_std_base,
|
||||
Config as BaseConfig,
|
||||
Wallet as BaseWallet,
|
||||
Rpc as BaseRpc, Flag,
|
||||
)
|
||||
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
||||
|
||||
# local imports
|
||||
from chainlib.eth.address import AddressChecksum
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
from chainlib.eth.gas import (
|
||||
OverrideGasOracle,
|
||||
RPCGasOracle,
|
||||
@@ -12,6 +26,20 @@ from chainlib.eth.nonce import (
|
||||
RPCNonceOracle,
|
||||
)
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
class Wallet(BaseWallet):
|
||||
"""Convenience constructor to set Ethereum defaults for chainlib cli Wallet object
|
||||
|
||||
:param checksummer: Address checksummer object
|
||||
:type checksummer: Implementation of chainlib.eth.address.AddressChecksum
|
||||
"""
|
||||
def __init__(self, checksummer=AddressChecksum):
|
||||
super(Wallet, self).__init__(EIP155Signer, checksummer=checksummer)
|
||||
|
||||
|
||||
# TODO: how is the keystore implemented in rpc here?
|
||||
class Rpc(BaseRpc):
|
||||
@@ -69,3 +97,27 @@ class Rpc(BaseRpc):
|
||||
|
||||
def get_gas_oracle(self):
|
||||
return self.get_fee_oracle()
|
||||
|
||||
|
||||
class Config(BaseConfig):
|
||||
"""Convenience constructor to set Ethereum defaults for the chainlib cli config object
|
||||
"""
|
||||
default_base_config_dir = os.path.join(script_dir, 'data', 'config')
|
||||
default_fee_limit = 21000
|
||||
|
||||
@classmethod
|
||||
def from_args(cls, args, arg_flags=0x0f, env=os.environ, extra_args={}, base_config_dir=None, default_config_dir=None, user_config_dir=None, default_fee_limit=None, logger=None, load_callback=None):
|
||||
super(Config, cls).override_defaults(base_dir=cls.default_base_config_dir)
|
||||
if default_fee_limit == None:
|
||||
default_fee_limit = cls.default_fee_limit
|
||||
config = BaseConfig.from_args(args, arg_flags=arg_flags, env=env, extra_args=extra_args, base_config_dir=base_config_dir, default_config_dir=default_config_dir, user_config_dir=user_config_dir, default_fee_limit=default_fee_limit, logger=logger, load_callback=load_callback)
|
||||
|
||||
if not config.get('RPC_DIALECT'):
|
||||
config.add('default', 'RPC_DIALECT', exists_ok=True)
|
||||
elif config.get('RPC_DIALECT') not in [
|
||||
'openethereum',
|
||||
'default',
|
||||
]:
|
||||
raise ValueError('unknown rpc dialect {}'.format(config.get('RPC_DIALECT')))
|
||||
|
||||
return config
|
||||
@@ -1,4 +0,0 @@
|
||||
from .arg import *
|
||||
from .config import Config
|
||||
from .rpc import Rpc
|
||||
from .wallet import Wallet
|
||||
@@ -1,6 +0,0 @@
|
||||
from chainlib.cli.arg import (
|
||||
ArgumentParser,
|
||||
Arg,
|
||||
ArgFlag,
|
||||
process_args,
|
||||
)
|
||||
@@ -1,34 +0,0 @@
|
||||
# standard imports
|
||||
import os
|
||||
|
||||
# external imports
|
||||
from chainlib.cli.config import (
|
||||
Config as BaseConfig,
|
||||
process_config as base_process_config,
|
||||
)
|
||||
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
data_dir = os.path.join(script_dir, '..')
|
||||
|
||||
|
||||
class Config(BaseConfig):
|
||||
"""Convenience constructor to set Ethereum defaults for the chainlib cli config object
|
||||
"""
|
||||
default_base_config_dir = os.path.join(data_dir, 'data', 'config')
|
||||
default_fee_limit = 21000
|
||||
|
||||
|
||||
def process_config(config, arg, args, flags):
|
||||
config = base_process_config(config, arg, args, flags)
|
||||
if arg.match('provider', flags):
|
||||
|
||||
if not bool(config.get('RPC_DIALECT')):
|
||||
config.add('default', 'RPC_DIALECT', exists_ok=True)
|
||||
elif config.get('RPC_DIALECT') not in [
|
||||
'openethereum',
|
||||
'default',
|
||||
]:
|
||||
raise ValueError('unknown rpc dialect {}'.format(config.get('RPC_DIALECT')))
|
||||
|
||||
return config
|
||||
@@ -1,103 +0,0 @@
|
||||
# standard imports
|
||||
import re
|
||||
import logging
|
||||
|
||||
# external imports
|
||||
from chainlib.eth.contract import (
|
||||
ABIContractType,
|
||||
ABIContractEncoder,
|
||||
)
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CLIEncoder(ABIContractEncoder):
|
||||
|
||||
__re_uint = r'^([uU])[int]*([0-9]+)?$'
|
||||
__re_bytes = r'^([bB])[ytes]*([0-9]+)?$'
|
||||
__re_string = r'^([sS])[tring]*$'
|
||||
__re_address = r'^([aA])[ddress]*?$'
|
||||
__translations = [
|
||||
'to_uint',
|
||||
'to_bytes',
|
||||
'to_string',
|
||||
'to_address',
|
||||
]
|
||||
|
||||
def __init__(self, signature=None):
|
||||
super(CLIEncoder, self).__init__()
|
||||
self.signature = signature
|
||||
if signature != None:
|
||||
self.method(signature)
|
||||
|
||||
def to_uint(self, typ):
|
||||
s = None
|
||||
a = None
|
||||
m = re.match(self.__re_uint, typ)
|
||||
if m == None:
|
||||
return None
|
||||
|
||||
n = m.group(2)
|
||||
if m.group(2) == None:
|
||||
n = 256
|
||||
s = 'UINT256'.format(m.group(2))
|
||||
a = getattr(ABIContractType, s)
|
||||
return (s, a)
|
||||
|
||||
|
||||
def to_bytes(self, typ):
|
||||
s = None
|
||||
a = None
|
||||
m = re.match(self.__re_bytes, typ)
|
||||
if m == None:
|
||||
return None
|
||||
|
||||
n = m.group(2)
|
||||
if n == None:
|
||||
n = 32
|
||||
s = 'BYTES{}'.format(n)
|
||||
a = getattr(ABIContractType, s)
|
||||
return (s, a)
|
||||
|
||||
|
||||
def to_address(self, typ):
|
||||
s = None
|
||||
a = None
|
||||
m = re.match(self.__re_address, typ)
|
||||
if m == None:
|
||||
return None
|
||||
|
||||
s = 'ADDRESS'
|
||||
a = getattr(ABIContractType, s)
|
||||
return (s, a)
|
||||
|
||||
|
||||
def to_string(self, typ):
|
||||
m = re.match(self.__re_string, typ)
|
||||
if m == None:
|
||||
return None
|
||||
s = 'STRING'
|
||||
a = getattr(ABIContractType, s)
|
||||
return (s, a)
|
||||
|
||||
|
||||
def translate_type(self, typ):
|
||||
r = None
|
||||
for tr in self.__translations:
|
||||
r = getattr(self, tr)(typ)
|
||||
if r != None:
|
||||
break
|
||||
if r == None:
|
||||
raise ValueError('no translation for type {}'.format(typ))
|
||||
logg.debug('type {} translated to {}'.format(typ, r[0]))
|
||||
return r[1]
|
||||
|
||||
|
||||
def add_from(self, arg):
|
||||
logg.debug('arg {}'.format(arg))
|
||||
(typ, val) = arg.split(':', maxsplit=1)
|
||||
real_typ = self.translate_type(typ)
|
||||
if self.signature != None:
|
||||
self.typ(real_typ)
|
||||
fn = getattr(self, real_typ.value)
|
||||
fn(val)
|
||||
@@ -1 +0,0 @@
|
||||
from chainlib.cli.log import process_log
|
||||
@@ -1,17 +0,0 @@
|
||||
# external imports
|
||||
from funga.eth.signer import EIP155Signer
|
||||
from funga.eth.keystore.dict import DictKeystore
|
||||
from chainlib.cli import Wallet as BaseWallet
|
||||
|
||||
# local imports
|
||||
from chainlib.eth.address import AddressChecksum
|
||||
|
||||
|
||||
class Wallet(BaseWallet):
|
||||
"""Convenience constructor to set Ethereum defaults for chainlib cli Wallet object
|
||||
|
||||
:param checksummer: Address checksummer object
|
||||
:type checksummer: Implementation of chainlib.eth.address.AddressChecksum
|
||||
"""
|
||||
def __init__(self, checksummer=AddressChecksum):
|
||||
super(Wallet, self).__init__(EIP155Signer, checksummer=checksummer, keystore=DictKeystore())
|
||||
@@ -36,7 +36,6 @@ from chainlib.jsonrpc import (
|
||||
from chainlib.eth.tx import (
|
||||
unpack,
|
||||
)
|
||||
from potaahto.symbols import snake_and_camel
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
@@ -89,16 +88,11 @@ class EthHTTPConnection(JSONRPCHTTPConnection):
|
||||
|
||||
e = jsonrpc_result(r, error_parser)
|
||||
if e != None:
|
||||
e = snake_and_camel(e)
|
||||
# In openethereum we encounter receipts that have NONE block hashes and numbers. WTF...
|
||||
logg.debug('({}) poll receipt received {}'.format(str(self), r))
|
||||
if e['block_hash'] == None:
|
||||
logg.warning('poll receipt attempt {} returned receipt but with a null block hash value!'.format(i))
|
||||
else:
|
||||
logg.debug('e {}'.format(strip_0x(e['status'])))
|
||||
if strip_0x(e['status']) == '00':
|
||||
raise RevertEthException(tx_hash_hex)
|
||||
return e
|
||||
logg.debug('({}) poll receipt completed {}'.format(str(self), r))
|
||||
logg.debug('e {}'.format(strip_0x(e['status'])))
|
||||
if strip_0x(e['status']) == '00':
|
||||
raise RevertEthException(tx_hash_hex)
|
||||
return e
|
||||
|
||||
if timeout > 0.0:
|
||||
delta = (datetime.datetime.utcnow() - t) + datetime.timedelta(seconds=delay)
|
||||
|
||||
@@ -6,7 +6,6 @@ import logging
|
||||
# external imports
|
||||
from hexathon import (
|
||||
strip_0x,
|
||||
add_0x,
|
||||
pad,
|
||||
)
|
||||
|
||||
@@ -503,8 +502,6 @@ def code(address, block_spec=BlockSpec.LATEST, id_generator=None):
|
||||
block_height = 'pending'
|
||||
else:
|
||||
block_height = int(block_spec)
|
||||
block_height = block_height.to_bytes(8, byteorder='big')
|
||||
block_height = add_0x(block_height.hex())
|
||||
j = JSONRPCRequest(id_generator)
|
||||
o = j.template()
|
||||
o['method'] = 'eth_getCode'
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
[rpc]
|
||||
http_provider = http://localhost:8545
|
||||
provider = http://localhost:8545
|
||||
auth =
|
||||
credentials =
|
||||
dialect = default
|
||||
scheme = http
|
||||
verify = 1
|
||||
timeout = 10.0
|
||||
proxy =
|
||||
|
||||
[chain]
|
||||
spec = evm:berlin:1:ethereum
|
||||
min_fee = 21000
|
||||
max_fee = 8000000
|
||||
spec = evm:ethereum:1
|
||||
|
||||
[wallet]
|
||||
key_file =
|
||||
passphrase =
|
||||
|
||||
[state]
|
||||
path =
|
||||
runtime_path =
|
||||
backend =
|
||||
|
||||
2
chainlib/eth/data/env/env.ini
vendored
2
chainlib/eth/data/env/env.ini
vendored
@@ -1,2 +0,0 @@
|
||||
[rpc]
|
||||
provider = Fully-qualified URL to EVM node's RPC endpoint.
|
||||
@@ -6,7 +6,7 @@ from hexathon import (
|
||||
add_0x,
|
||||
strip_0x,
|
||||
)
|
||||
from funga.eth.transaction import EIP155Transaction
|
||||
from crypto_dev_signer.eth.transaction import EIP155Transaction
|
||||
|
||||
# local imports
|
||||
from chainlib.fee import FeeOracle
|
||||
@@ -55,7 +55,7 @@ def balance(address, id_generator=None, height=BlockSpec.LATEST):
|
||||
j = JSONRPCRequest(id_generator)
|
||||
o = j.template()
|
||||
o['method'] = 'eth_getBalance'
|
||||
o['params'].append(add_0x(address))
|
||||
o['params'].append(address)
|
||||
height = to_blockheight_param(height)
|
||||
o['params'].append(height)
|
||||
return j.finalize(o)
|
||||
|
||||
@@ -44,7 +44,7 @@ class NonceOracle(BaseNonceOracle):
|
||||
"""
|
||||
def __init__(self, address, id_generator=None):
|
||||
self.id_generator = id_generator
|
||||
super(NonceOracle, self).__init__(add_0x(address))
|
||||
super(NonceOracle, self).__init__(address)
|
||||
|
||||
|
||||
def get_nonce(self):
|
||||
|
||||
@@ -5,8 +5,8 @@ import logging
|
||||
# external imports
|
||||
import eth_tester
|
||||
import pytest
|
||||
from funga.eth.signer import EIP155Signer
|
||||
from funga.eth.keystore.dict import DictKeystore
|
||||
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
||||
from crypto_dev_signer.keystore.dict import DictKeystore
|
||||
|
||||
# local imports
|
||||
from chainlib.eth.unittest.base import *
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
# external imports
|
||||
import pytest
|
||||
#from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
|
||||
@@ -10,73 +10,51 @@ from hexathon import (
|
||||
strip_0x,
|
||||
even,
|
||||
)
|
||||
from chainlib.settings import ChainSettings
|
||||
from chainlib.chain import ChainSpec
|
||||
from funga.eth.signer import EIP155Signer
|
||||
|
||||
# local imports
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.address import AddressChecksum
|
||||
from chainlib.jsonrpc import (
|
||||
jsonrpc_result,
|
||||
IntSequenceGenerator,
|
||||
)
|
||||
|
||||
# local imports
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.cli.arg import (
|
||||
Arg,
|
||||
ArgFlag,
|
||||
process_args,
|
||||
)
|
||||
from chainlib.eth.cli.config import (
|
||||
Config,
|
||||
process_config,
|
||||
)
|
||||
from chainlib.eth.cli.log import process_log
|
||||
from chainlib.eth.address import AddressChecksum
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
from chainlib.eth.gas import (
|
||||
OverrideGasOracle,
|
||||
balance,
|
||||
)
|
||||
from chainlib.eth.settings import process_settings
|
||||
|
||||
from chainlib.chain import ChainSpec
|
||||
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
#config_dir = os.path.join(script_dir, '..', 'data', 'config')
|
||||
|
||||
|
||||
def process_config_local(config, arg, args, flags):
|
||||
config.add(args.address, '_RECIPIENT', False)
|
||||
return config
|
||||
|
||||
|
||||
arg_flags = ArgFlag()
|
||||
arg = Arg(arg_flags)
|
||||
flags = arg_flags.STD_READ
|
||||
|
||||
argparser = chainlib.eth.cli.ArgumentParser()
|
||||
argparser = process_args(argparser, arg, flags)
|
||||
|
||||
argparser.add_argument('address', type=str, help='Ethereum address of recipient')
|
||||
arg_flags = chainlib.eth.cli.argflag_std_read
|
||||
argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
|
||||
argparser.add_positional('address', type=str, help='Ethereum address of recipient')
|
||||
args = argparser.parse_args()
|
||||
config = chainlib.eth.cli.Config.from_args(args, arg_flags)
|
||||
|
||||
logg = process_log(args, logg)
|
||||
logg.debug('flags {} {} {}'.format(flags, arg_flags.SEQ, flags & arg_flags.SEQ))
|
||||
wallet = chainlib.eth.cli.Wallet()
|
||||
wallet.from_config(config)
|
||||
holder_address = args.address
|
||||
if wallet.get_signer_address() == None and holder_address != None:
|
||||
holder_address = wallet.from_address(holder_address)
|
||||
|
||||
config = Config()
|
||||
config = process_config(config, arg, args, flags)
|
||||
config = process_config_local(config, arg, args, flags)
|
||||
logg.debug('config loaded:\n{}'.format(config))
|
||||
|
||||
settings = ChainSettings()
|
||||
settings = process_settings(settings, config)
|
||||
rpc = chainlib.eth.cli.Rpc()
|
||||
conn = rpc.connect_by_config(config)
|
||||
|
||||
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
|
||||
|
||||
def main():
|
||||
r = None
|
||||
decimals = 18
|
||||
|
||||
o = balance(settings.get('RECIPIENT'), id_generator=settings.get('RPC_ID_GENERATOR'))
|
||||
r = settings.get('CONN').do(o)
|
||||
o = balance(holder_address, id_generator=rpc.id_generator)
|
||||
r = conn.do(o)
|
||||
|
||||
hx = strip_0x(r)
|
||||
balance_value = int(hx, 16)
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# standard imports
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import argparse
|
||||
import logging
|
||||
import enum
|
||||
import select
|
||||
|
||||
# external imports
|
||||
from potaahto.symbols import snake_and_camel
|
||||
from hexathon import (
|
||||
add_0x,
|
||||
strip_0x,
|
||||
)
|
||||
import sha3
|
||||
from chainlib.jsonrpc import (
|
||||
JSONRPCRequest,
|
||||
jsonrpc_result,
|
||||
IntSequenceGenerator,
|
||||
)
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.status import Status
|
||||
from chainlib.settings import ChainSettings
|
||||
|
||||
# local imports
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
from chainlib.eth.tx import (
|
||||
Tx,
|
||||
pack,
|
||||
)
|
||||
from chainlib.eth.address import (
|
||||
to_checksum_address,
|
||||
is_checksum_address,
|
||||
)
|
||||
from chainlib.eth.block import (
|
||||
Block,
|
||||
block_by_hash,
|
||||
block_by_number,
|
||||
)
|
||||
from chainlib.eth.runnable.util import decode_for_puny_humans
|
||||
from chainlib.eth.jsonrpc import to_blockheight_param
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.cli.arg import (
|
||||
Arg,
|
||||
ArgFlag,
|
||||
process_args,
|
||||
)
|
||||
from chainlib.eth.cli.config import (
|
||||
Config,
|
||||
process_config,
|
||||
)
|
||||
from chainlib.eth.cli.log import process_log
|
||||
from chainlib.eth.settings import process_settings
|
||||
|
||||
logg = logging.getLogger()
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
config_dir = os.path.join(script_dir, '..', 'data', 'config')
|
||||
|
||||
def process_config_local(config, arg, args, flags):
|
||||
config.add(args.block, '_BLOCK', False)
|
||||
return config
|
||||
|
||||
|
||||
def process_settings_local(settings, config):
|
||||
block_identifier = config.get('_BLOCK')
|
||||
maybe_hex = None
|
||||
is_number = False
|
||||
try:
|
||||
maybe_hex = strip_0x(block_identifier)
|
||||
except ValueError:
|
||||
is_number = True
|
||||
|
||||
if maybe_hex != None:
|
||||
if len(maybe_hex) != 64:
|
||||
is_number = True
|
||||
else:
|
||||
is_number = True
|
||||
|
||||
r = None
|
||||
if not is_number:
|
||||
config.add(block_identifier, '_HASH', False)
|
||||
else:
|
||||
settings.set('_BLOCK', int(block_identifier))
|
||||
|
||||
return process_settings(settings, config)
|
||||
|
||||
|
||||
argparser = chainlib.eth.cli.ArgumentParser()
|
||||
arg_flags = ArgFlag()
|
||||
arg = Arg(arg_flags)
|
||||
flags = arg_flags.STD_BASE_READ
|
||||
flags = arg_flags.less(flags, arg_flags.CHAIN_SPEC)
|
||||
argparser = process_args(argparser, arg, flags)
|
||||
argparser.add_argument('block', nargs='?', type=str, help='Block hash or number to retrieve')
|
||||
args = argparser.parse_args()
|
||||
|
||||
logg = process_log(args, logg)
|
||||
|
||||
config = Config()
|
||||
config = process_config(config, arg, args, flags)
|
||||
config = process_config_local(config, arg, args, flags)
|
||||
logg.debug('config loaded:\n{}'.format(config))
|
||||
|
||||
settings = ChainSettings()
|
||||
settings = process_settings_local(settings, config)
|
||||
logg.debug('settings loaded:\n{}'.format(settings))
|
||||
|
||||
|
||||
|
||||
def get_block(settings):
|
||||
hsh = settings.get('HASH')[0]
|
||||
r = None
|
||||
if hsh == None:
|
||||
r = get_block_number(
|
||||
settings.get('CONN'),
|
||||
settings.get('_BLOCK'),
|
||||
settings.get('RPC_ID_GENERATOR'),
|
||||
)
|
||||
else:
|
||||
r = get_block_hash(
|
||||
settings.get('CONN'),
|
||||
hsh,
|
||||
settings.get('RPC_ID_GENERATOR'),
|
||||
)
|
||||
|
||||
return block_process(r)
|
||||
|
||||
|
||||
def get_block_number(conn, block_number, id_generator):
|
||||
o = block_by_number(block_number, include_tx=False)
|
||||
block_src = conn.do(o)
|
||||
if block_src == None:
|
||||
logg.error('Block number {} not found'.format(block_number))
|
||||
sys.exit(1)
|
||||
return block_src
|
||||
|
||||
|
||||
def get_block_hash(conn, block_hash, id_generator):
|
||||
block_hash = add_0x(block_hash)
|
||||
o = block_by_hash(block_hash, include_tx=False)
|
||||
block_src = conn.do(o)
|
||||
if block_src == None:
|
||||
logg.error('Block hash {} not found'.format(block_hash))
|
||||
sys.exit(1)
|
||||
return block_src
|
||||
|
||||
|
||||
def block_process(block_src):
|
||||
return Block(block_src)
|
||||
|
||||
|
||||
def main():
|
||||
r = get_block(settings)
|
||||
|
||||
if not config.true('_RAW'):
|
||||
r = r.to_human()
|
||||
else:
|
||||
r = repr(r)
|
||||
if r != None:
|
||||
print(r)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -8,70 +8,43 @@ import json
|
||||
import logging
|
||||
import select
|
||||
|
||||
# external imports
|
||||
from chainlib.settings import ChainSettings
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.jsonrpc import IntSequenceGenerator
|
||||
from funga.eth.keystore.dict import DictKeystore
|
||||
from funga.eth.signer import EIP155Signer
|
||||
from hexathon import add_0x
|
||||
|
||||
# local imports
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.cli.arg import (
|
||||
Arg,
|
||||
ArgFlag,
|
||||
process_args,
|
||||
)
|
||||
from chainlib.eth.cli.config import (
|
||||
Config,
|
||||
process_config,
|
||||
)
|
||||
from chainlib.eth.cli.log import process_log
|
||||
from chainlib.eth.address import AddressChecksum
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
from chainlib.eth.tx import count
|
||||
from chainlib.eth.settings import process_settings
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.jsonrpc import IntSequenceGenerator
|
||||
from crypto_dev_signer.keystore.dict import DictKeystore
|
||||
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
||||
from hexathon import add_0x
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
config_dir = os.path.join(script_dir, '..', 'data', 'config')
|
||||
|
||||
|
||||
def process_config_local(config, arg, args, flags):
|
||||
config.add(args.address, '_RECIPIENT', False)
|
||||
return config
|
||||
|
||||
argparser = chainlib.eth.cli.ArgumentParser()
|
||||
arg_flags = ArgFlag()
|
||||
arg = Arg(arg_flags)
|
||||
flags = arg_flags.STD_BASE_READ | arg_flags.WALLET | arg_flags.UNSAFE
|
||||
argparser = process_args(argparser, arg, flags)
|
||||
|
||||
argparser.add_argument('address', type=str, help='Ethereum address of recipient')
|
||||
arg_flags = chainlib.eth.cli.argflag_std_read
|
||||
argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
|
||||
argparser.add_positional('address', type=str, help='Ethereum address of recipient')
|
||||
args = argparser.parse_args()
|
||||
config = chainlib.eth.cli.Config.from_args(args, arg_flags, default_config_dir=config_dir)
|
||||
|
||||
logg = process_log(args, logg)
|
||||
logg.debug('flags {} {} {}'.format(flags, arg_flags.SEQ, flags & arg_flags.SEQ))
|
||||
holder_address = args.address
|
||||
wallet = chainlib.eth.cli.Wallet()
|
||||
wallet.from_config(config)
|
||||
if wallet.get_signer_address() == None and holder_address != None:
|
||||
wallet.from_address(holder_address)
|
||||
|
||||
config = Config()
|
||||
config = process_config(config, arg, args, flags)
|
||||
config = process_config_local(config, arg, args, flags)
|
||||
logg.debug('config loaded:\n{}'.format(config))
|
||||
|
||||
settings = ChainSettings()
|
||||
settings = process_settings(settings, config)
|
||||
logg.debug('settings loaded:\n{}'.format(settings))
|
||||
rpc = chainlib.eth.cli.Rpc(wallet=wallet)
|
||||
conn = rpc.connect_by_config(config)
|
||||
|
||||
|
||||
def main():
|
||||
# TODO: should tolerate if address not prefixed with 0x
|
||||
o = count(
|
||||
settings.get('RECIPIENT'),
|
||||
id_generator=settings.get('RPC_ID_GENERATOR'),
|
||||
)
|
||||
r = settings.get('CONN').do(o)
|
||||
o = count(holder_address, id_generator=rpc.id_generator)
|
||||
r = conn.do(o)
|
||||
count_result = None
|
||||
try:
|
||||
count_result = int(r, 16)
|
||||
|
||||
@@ -11,24 +11,10 @@ import select
|
||||
# external imports
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.tx import unpack
|
||||
from chainlib.settings import ChainSettings
|
||||
from chainlib.chain import ChainSpec
|
||||
|
||||
# local imports
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.runnable.util import decode_for_puny_humans
|
||||
from chainlib.eth.cli.arg import (
|
||||
Arg,
|
||||
ArgFlag,
|
||||
process_args,
|
||||
)
|
||||
from chainlib.eth.cli.config import (
|
||||
Config,
|
||||
process_config,
|
||||
)
|
||||
from chainlib.eth.cli.log import process_log
|
||||
from chainlib.eth.settings import process_settings
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
@@ -36,39 +22,16 @@ logg = logging.getLogger()
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
config_dir = os.path.join(script_dir, '..', 'data', 'config')
|
||||
|
||||
|
||||
def process_config_local(config, arg, args, flags):
|
||||
config.add(args.tx_data, '_TX_DATA', False)
|
||||
return config
|
||||
|
||||
|
||||
arg_flags = ArgFlag()
|
||||
arg = Arg(arg_flags)
|
||||
flags = arg_flags.VERBOSE | arg_flags.CHAIN_SPEC | arg_flags.RAW | arg_flags.ENV | arg_flags.SEQ
|
||||
|
||||
argparser = chainlib.eth.cli.ArgumentParser()
|
||||
argparser = process_args(argparser, arg, flags)
|
||||
argparser.add_argument('tx_data', type=str, help='Transaction data to decode')
|
||||
arg_flags = chainlib.eth.cli.Flag.VERBOSE | chainlib.eth.cli.Flag.CHAIN_SPEC | chainlib.eth.cli.Flag.ENV_PREFIX | chainlib.eth.cli.Flag.RAW
|
||||
argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
|
||||
argparser.add_positional('tx_data', type=str, help='Transaction data to decode')
|
||||
args = argparser.parse_args()
|
||||
config = chainlib.eth.cli.Config.from_args(args, arg_flags, default_config_dir=config_dir)
|
||||
|
||||
logg = process_log(args, logg)
|
||||
|
||||
config = Config()
|
||||
config = process_config(config, arg, args, flags)
|
||||
config = process_config_local(config, arg, args, flags)
|
||||
logg.debug('config loaded:\n{}'.format(config))
|
||||
|
||||
settings = ChainSettings()
|
||||
settings = process_settings(settings, config)
|
||||
logg.debug('settings loaded:\n{}'.format(settings))
|
||||
|
||||
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
|
||||
|
||||
def main():
|
||||
decode_for_puny_humans(
|
||||
config.get('_TX_DATA'),
|
||||
settings.get('CHAIN_SPEC'),
|
||||
sys.stdout,
|
||||
)
|
||||
decode_for_puny_humans(args.tx_data, chain_spec, sys.stdout)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# standard imports
|
||||
import io
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import argparse
|
||||
import logging
|
||||
import urllib
|
||||
import sha3
|
||||
|
||||
# external imports
|
||||
from chainlib.cli import flag_reset
|
||||
from funga.eth.signer import EIP155Signer
|
||||
from funga.eth.keystore.dict import DictKeystore
|
||||
from hexathon import (
|
||||
add_0x,
|
||||
strip_0x,
|
||||
)
|
||||
|
||||
# local imports
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.cli.arg import (
|
||||
Arg,
|
||||
ArgFlag,
|
||||
process_args,
|
||||
)
|
||||
from chainlib.eth.cli.config import (
|
||||
Config,
|
||||
process_config,
|
||||
)
|
||||
from chainlib.eth.cli.log import process_log
|
||||
from chainlib.eth.cli.encode import CLIEncoder
|
||||
from chainlib.eth.constant import ZERO_ADDRESS
|
||||
from chainlib.eth.address import to_checksum
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
from chainlib.jsonrpc import (
|
||||
JSONRPCRequest,
|
||||
IntSequenceGenerator,
|
||||
)
|
||||
from chainlib.eth.tx import (
|
||||
TxFactory,
|
||||
TxFormat,
|
||||
raw,
|
||||
)
|
||||
from chainlib.error import SignerMissingException
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.eth.runnable.util import decode_for_puny_humans
|
||||
from chainlib.eth.jsonrpc import to_blockheight_param
|
||||
from chainlib.eth.address import to_checksum_address
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
config_dir = os.path.join(script_dir, '..', 'data', 'config')
|
||||
|
||||
|
||||
def process_config_local(config, arg, args, flags):
|
||||
config.add(args.signature, '_SIGNATURE', False)
|
||||
config.add(args.contract_args, '_CONTRACT_ARGS', False)
|
||||
return config
|
||||
|
||||
arg_flags = ArgFlag()
|
||||
arg = Arg(arg_flags)
|
||||
flags = arg_flags.STD_WRITE | arg_flags.EXEC | arg_flags.FEE | arg_flags.FMT_HUMAN | arg_flags.FMT_WIRE | arg_flags.FMT_RPC
|
||||
|
||||
argparser = chainlib.eth.cli.ArgumentParser()
|
||||
argparser = process_args(argparser, arg, flags)
|
||||
argparser.add_argument('--mode', type=str, choices=['tx', 'call', 'arg'], help='Mode of operation')
|
||||
argparser.add_argument('--signature', type=str, help='Method signature to encode')
|
||||
argparser.add_argument('contract_args', type=str, nargs='*', help='arguments to encode')
|
||||
args = argparser.parse_args()
|
||||
|
||||
logg = process_log(args, logg)
|
||||
|
||||
config = Config()
|
||||
config = process_config(config, arg, args, flags)
|
||||
config = process_config_local(config, arg, args, flags)
|
||||
logg.debug('config loaded:\n{}'.format(config))
|
||||
|
||||
wallet = chainlib.eth.cli.Wallet(EIP155Signer)
|
||||
wallet.from_config(config)
|
||||
|
||||
rpc = chainlib.eth.cli.Rpc(wallet=wallet)
|
||||
conn = rpc.connect_by_config(config)
|
||||
|
||||
send = config.true('_RPC_SEND')
|
||||
|
||||
chain_spec = None
|
||||
try:
|
||||
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
signer_address = ZERO_ADDRESS
|
||||
signer = None
|
||||
try:
|
||||
signer = rpc.get_signer()
|
||||
signer_address = rpc.get_signer_address()
|
||||
except SignerMissingException:
|
||||
pass
|
||||
|
||||
code = '0x'
|
||||
cli_encoder = CLIEncoder(signature=config.get('_SIGNATURE'))
|
||||
|
||||
for arg in config.get('_CONTRACT_ARGS'):
|
||||
cli_encoder.add_from(arg)
|
||||
|
||||
code += cli_encoder.get()
|
||||
|
||||
exec_address = config.get('_EXEC_ADDRESS')
|
||||
if exec_address:
|
||||
exec_address = add_0x(to_checksum_address(exec_address))
|
||||
|
||||
mode = args.mode
|
||||
if mode == None:
|
||||
if signer == None:
|
||||
mode = 'call'
|
||||
else:
|
||||
mode = 'tx'
|
||||
|
||||
if not config.get('_SIGNATURE'):
|
||||
if mode != 'arg':
|
||||
logg.error('mode tx without contract method signature makes no sense. Use eth-get with --data instead.')
|
||||
sys.exit(1)
|
||||
if args.format == 'rpc':
|
||||
logg.error('rpc format with arg put does not make sense')
|
||||
sys.exit(1)
|
||||
|
||||
if mode == 'arg':
|
||||
print(strip_0x(code))
|
||||
return
|
||||
elif not exec_address:
|
||||
logg.error('exec address (-e) must be defined with mode "{}"'.format(args.mode))
|
||||
sys.exit(1)
|
||||
|
||||
if config.get('RPC_PROVIDER'):
|
||||
logg.debug('provider {}'.format(config.get('RPC_PROVIDER')))
|
||||
if not config.get('_FEE_LIMIT') or not config.get('_FEE_PRICE'):
|
||||
gas_oracle = rpc.get_gas_oracle()
|
||||
(price, limit) = gas_oracle.get_gas()
|
||||
if not config.get('_FEE_PRICE'):
|
||||
config.add(price, '_FEE_PRICE')
|
||||
if not config.get('_FEE_LIMIT'):
|
||||
config.add(limit, '_FEE_LIMIT')
|
||||
|
||||
if mode == 'tx':
|
||||
if not config.get('_NONCE'):
|
||||
nonce_oracle = rpc.get_nonce_oracle()
|
||||
config.add(nonce_oracle.get_nonce(), '_NONCE')
|
||||
else:
|
||||
for arg in [
|
||||
'_FEE_PRICE',
|
||||
'_FEE_LIMIT',
|
||||
'_NONCE',
|
||||
]:
|
||||
if not config.get(arg):
|
||||
logg.error('--{} must be specified when no rpc provider has been set.'.format(arg.replace('_', '-').lower()))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if mode == 'call': #signer == None or config.true('_NOTX'):
|
||||
c = TxFactory(chain_spec)
|
||||
j = JSONRPCRequest(id_generator=rpc.id_generator)
|
||||
o = j.template()
|
||||
gas_limit = add_0x(int.to_bytes(config.get('_FEE_LIMIT'), 8, byteorder='big').hex(), compact_value=True)
|
||||
gas_price = add_0x(int.to_bytes(config.get('_FEE_PRICE'), 8, byteorder='big').hex(), compact_value=True)
|
||||
o['method'] = 'eth_call'
|
||||
o['params'].append({
|
||||
'to': exec_address,
|
||||
'from': signer_address,
|
||||
'value': '0x0',
|
||||
'gas': gas_limit, # TODO: better get of network gas limit
|
||||
'gasPrice': gas_price,
|
||||
'data': add_0x(code),
|
||||
})
|
||||
height = to_blockheight_param(config.get('_HEIGHT'))
|
||||
o['params'].append(height)
|
||||
o = j.finalize(o)
|
||||
|
||||
if config.get('_RPC_SEND'):
|
||||
r = conn.do(o)
|
||||
try:
|
||||
print(strip_0x(r))
|
||||
return
|
||||
except ValueError:
|
||||
sys.stderr.write('query returned an empty value ({})\n'.format(r))
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(o)
|
||||
return
|
||||
|
||||
if signer == None:
|
||||
logg.error('mode "tx" without signer does not make sense. Please specify a key file with -y.')
|
||||
sys.exit(1)
|
||||
|
||||
if chain_spec == None:
|
||||
raise ValueError('chain spec must be specified')
|
||||
|
||||
c = TxFactory(chain_spec, signer=signer, gas_oracle=rpc.get_gas_oracle(), nonce_oracle=rpc.get_nonce_oracle())
|
||||
tx = c.template(signer_address, config.get('_EXEC_ADDRESS'), use_nonce=True)
|
||||
tx = c.set_code(tx, code)
|
||||
tx_format = TxFormat.JSONRPC
|
||||
if config.get('_RAW'):
|
||||
tx_format = TxFormat.RLP_SIGNED
|
||||
(tx_hash_hex, o) = c.finalize(tx, tx_format=tx_format)
|
||||
if send:
|
||||
r = conn.do(o)
|
||||
print(r)
|
||||
else:
|
||||
if config.get('_RAW'):
|
||||
o = strip_0x(o)
|
||||
print(o)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,23 +0,0 @@
|
||||
# standard imports
|
||||
import sys
|
||||
|
||||
# external imports
|
||||
import chainlib.eth.cli
|
||||
from hexathon import add_0x
|
||||
|
||||
cmds = {
|
||||
'gas': chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.WALLET,
|
||||
'info': chainlib.eth.cli.argflag_reset(chainlib.cli.argflag_std_base_read, chainlib.eth.cli.Flag.CHAIN_SPEC),
|
||||
'get': chainlib.eth.cli.argflag_reset(chainlib.cli.argflag_std_base_read, chainlib.eth.cli.Flag.CHAIN_SPEC),
|
||||
'decode': chainlib.cli.argflag_std_base | chainlib.eth.cli.Flag.CHAIN_SPEC,
|
||||
'encode': chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC | chainlib.eth.cli.Flag.FEE | chainlib.eth.cli.Flag.FMT_HUMAN | chainlib.eth.cli.Flag.FMT_WIRE | chainlib.eth.cli.Flag.FMT_RPC,
|
||||
'count': chainlib.eth.cli.argflag_std_base_read | chainlib.eth.cli.Flag.WALLET,
|
||||
'raw': chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC,
|
||||
'balance': chainlib.eth.cli.argflag_std_base | chainlib.eth.cli.Flag.WALLET,
|
||||
'wait': chainlib.eth.cli.argflag_reset(chainlib.eth.cli.argflag_std_base_read | chainlib.eth.cli.Flag.NO_TARGET | chainlib.eth.cli.Flag.RPC_AUTH, chainlib.eth.cli.Flag.CHAIN_SPEC | chainlib.eth.cli.Flag.RAW),
|
||||
'checksum': 0,
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
b = cmds[sys.argv[1]]
|
||||
print(add_0x(hex(b)))
|
||||
@@ -14,144 +14,100 @@ from hexathon import (
|
||||
add_0x,
|
||||
strip_0x,
|
||||
)
|
||||
from chainlib.settings import ChainSettings
|
||||
from chainlib.jsonrpc import (
|
||||
JSONRPCRequest,
|
||||
IntSequenceGenerator,
|
||||
)
|
||||
from chainlib.chain import ChainSpec
|
||||
|
||||
# local imports
|
||||
from chainlib.eth.address import to_checksum_address
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
from chainlib.jsonrpc import (
|
||||
JSONRPCRequest,
|
||||
IntSequenceGenerator,
|
||||
)
|
||||
from chainlib.eth.gas import Gas
|
||||
from chainlib.eth.gas import balance as gas_balance
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.eth.runnable.util import decode_for_puny_humans
|
||||
from chainlib.eth.address import (
|
||||
is_same_address,
|
||||
is_checksum_address,
|
||||
)
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.cli.arg import (
|
||||
Arg,
|
||||
ArgFlag,
|
||||
process_args,
|
||||
)
|
||||
from chainlib.eth.cli.config import (
|
||||
Config,
|
||||
process_config,
|
||||
)
|
||||
from chainlib.eth.cli.log import process_log
|
||||
from chainlib.eth.settings import process_settings
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
|
||||
def process_config_local(config, arg, args, flags):
|
||||
config.add(args.data, '_DATA', False)
|
||||
config.add(args.amount, '_VALUE', False)
|
||||
return config
|
||||
|
||||
|
||||
arg_flags = ArgFlag()
|
||||
arg = Arg(arg_flags)
|
||||
flags = arg_flags.STD_WRITE | arg_flags.WALLET
|
||||
|
||||
argparser = chainlib.eth.cli.ArgumentParser()
|
||||
argparser = process_args(argparser, arg, flags)
|
||||
arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.WALLET
|
||||
argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
|
||||
argparser.add_argument('--data', type=str, help='Transaction data')
|
||||
argparser.add_argument('amount', type=str, help='Token amount to send')
|
||||
argparser.add_positional('amount', type=int, help='Token amount to send')
|
||||
args = argparser.parse_args()
|
||||
extra_args = {
|
||||
'data': None,
|
||||
'amount': None,
|
||||
}
|
||||
#config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args=extra_args, default_config_dir=config_dir)
|
||||
config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args=extra_args)
|
||||
|
||||
logg = process_log(args, logg)
|
||||
block_all = args.ww
|
||||
block_last = args.w or block_all
|
||||
|
||||
config = Config()
|
||||
config = process_config(config, arg, args, flags)
|
||||
config = process_config_local(config, arg, args, flags)
|
||||
logg.debug('config loaded:\n{}'.format(config))
|
||||
wallet = chainlib.eth.cli.Wallet()
|
||||
wallet.from_config(config)
|
||||
|
||||
settings = ChainSettings()
|
||||
settings = process_settings(settings, config)
|
||||
logg.debug('settings loaded:\n{}'.format(settings))
|
||||
rpc = chainlib.eth.cli.Rpc(wallet=wallet)
|
||||
conn = rpc.connect_by_config(config)
|
||||
|
||||
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
|
||||
|
||||
value = config.get('_AMOUNT')
|
||||
|
||||
send = config.true('_RPC_SEND')
|
||||
|
||||
|
||||
def balance(conn, address, id_generator):
|
||||
def balance(address, id_generator):
|
||||
o = gas_balance(address, id_generator=id_generator)
|
||||
r = conn.do(o)
|
||||
try:
|
||||
balance = int(r)
|
||||
except ValueError:
|
||||
balance = strip_0x(r)
|
||||
balance = int(balance, 16)
|
||||
return balance
|
||||
hx = strip_0x(r)
|
||||
return int(hx, 16)
|
||||
|
||||
|
||||
def main():
|
||||
g = Gas(
|
||||
settings.get('CHAIN_SPEC'),
|
||||
signer=settings.get('SIGNER'),
|
||||
gas_oracle=settings.get('GAS_ORACLE'),
|
||||
nonce_oracle=settings.get('NONCE_ORACLE'),
|
||||
)
|
||||
signer = rpc.get_signer()
|
||||
signer_address = rpc.get_sender_address()
|
||||
|
||||
g = Gas(chain_spec, signer=signer, gas_oracle=rpc.get_gas_oracle(), nonce_oracle=rpc.get_nonce_oracle())
|
||||
|
||||
recipient = to_checksum_address(config.get('_RECIPIENT'))
|
||||
if not config.true('_UNSAFE') and not is_checksum_address(recipient):
|
||||
if not config.true('_UNSAFE') and recipient != add_0x(config.get('_RECIPIENT')):
|
||||
raise ValueError('invalid checksum address')
|
||||
|
||||
logg.info('gas transfer from {} to {} value {}'.format(signer_address, recipient, value))
|
||||
if logg.isEnabledFor(logging.DEBUG):
|
||||
try:
|
||||
sender_balance = balance(
|
||||
settings.get('CONN'),
|
||||
settings.get('SENDER_ADDRESS'),
|
||||
settings.get('RPC_ID_GENERATOR'),
|
||||
)
|
||||
recipient_balance = balance(
|
||||
settings.get('CONN'),
|
||||
settings.get('RECIPIENT'),
|
||||
settings.get('RPC_ID_GENERATOR'),
|
||||
)
|
||||
logg.debug('sender {} balance before: {}'.format(settings.get('SENDER_ADDRESS'), sender_balance))
|
||||
logg.debug('recipient {} balance before: {}'.format(settings.get('RECIPIENT'), recipient_balance))
|
||||
sender_balance = balance(signer_address, rpc.id_generator)
|
||||
recipient_balance = balance(recipient, rpc.id_generator)
|
||||
logg.debug('sender {} balance before: {}'.format(signer_address, sender_balance))
|
||||
logg.debug('recipient {} balance before: {}'.format(recipient, recipient_balance))
|
||||
except urllib.error.URLError:
|
||||
pass
|
||||
|
||||
(tx_hash_hex, o) = g.create(
|
||||
settings.get('SENDER_ADDRESS'),
|
||||
settings.get('RECIPIENT'),
|
||||
settings.get('VALUE'),
|
||||
data=config.get('_DATA'),
|
||||
id_generator=settings.get('RPC_ID_GENERATOR'),
|
||||
)
|
||||
|
||||
logg.info('gas transfer from {} to {} value {} hash {}'.format(settings.get('SENDER_ADDRESS'), settings.get('RECIPIENT'), settings.get('VALUE'), tx_hash_hex))
|
||||
(tx_hash_hex, o) = g.create(signer_address, recipient, value, data=config.get('_DATA'), id_generator=rpc.id_generator)
|
||||
|
||||
if settings.get('RPC_SEND'):
|
||||
settings.get('CONN').do(o)
|
||||
if config.true('_WAIT'):
|
||||
r = settings.get('CONN').wait(tx_hash_hex)
|
||||
if send:
|
||||
conn.do(o)
|
||||
if block_last:
|
||||
r = conn.wait(tx_hash_hex)
|
||||
if logg.isEnabledFor(logging.DEBUG):
|
||||
sender_balance = balance(
|
||||
settings.get('CONN'),
|
||||
settings.get('SENDER_ADDRESS'),
|
||||
settings.get('RPC_ID_GENERATOR'),
|
||||
)
|
||||
recipient_balance = balance(
|
||||
settings.get('CONN'),
|
||||
settings.get('RECIPIENT'),
|
||||
settings.get('RPC_ID_GENERATOR'),
|
||||
)
|
||||
logg.debug('sender {} balance before: {}'.format(settings.get('SENDER_ADDRESS'), sender_balance))
|
||||
logg.debug('recipient {} balance before: {}'.format(settings.get('RECIPIENT'), recipient_balance))
|
||||
sender_balance = balance(signer_address, rpc.id_generator)
|
||||
recipient_balance = balance(recipient, rpc.id_generator)
|
||||
logg.debug('sender {} balance after: {}'.format(signer_address, sender_balance))
|
||||
logg.debug('recipient {} balance after: {}'.format(recipient, recipient_balance))
|
||||
if r['status'] == 0:
|
||||
logg.critical('VM revert for {}. Wish I could tell you more'.format(tx_hash_hex))
|
||||
logg.critical('VM revert. Wish I could tell you more')
|
||||
sys.exit(1)
|
||||
print(tx_hash_hex)
|
||||
else:
|
||||
#if logg.isEnabledFor(logging.INFO):
|
||||
if config.true('_RAW'):
|
||||
print(o['params'][0])
|
||||
else:
|
||||
io_str = io.StringIO()
|
||||
decode_for_puny_humans(o['params'][0], settings.get('CHAIN_SPEC'), io_str)
|
||||
decode_for_puny_humans(o['params'][0], chain_spec, io_str)
|
||||
print(io_str.getvalue())
|
||||
|
||||
|
||||
|
||||
@@ -23,15 +23,12 @@ from chainlib.jsonrpc import (
|
||||
)
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.status import Status
|
||||
from chainlib.settings import ChainSettings
|
||||
|
||||
# local imports
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
from chainlib.eth.tx import (
|
||||
Tx,
|
||||
pack,
|
||||
transaction,
|
||||
receipt,
|
||||
)
|
||||
from chainlib.eth.address import (
|
||||
to_checksum_address,
|
||||
@@ -44,67 +41,33 @@ from chainlib.eth.block import (
|
||||
from chainlib.eth.runnable.util import decode_for_puny_humans
|
||||
from chainlib.eth.jsonrpc import to_blockheight_param
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.cli.arg import (
|
||||
Arg,
|
||||
ArgFlag,
|
||||
process_args,
|
||||
)
|
||||
from chainlib.eth.cli.config import (
|
||||
Config,
|
||||
process_config,
|
||||
)
|
||||
from chainlib.eth.contract import code
|
||||
from chainlib.eth.cli.log import process_log
|
||||
from chainlib.eth.settings import process_settings
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.WARNING, format='%(asctime)s %(levelname)s %(filename)s:%(lineno)d %(message)s')
|
||||
logg = logging.getLogger()
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
config_dir = os.path.join(script_dir, '..', 'data', 'config')
|
||||
|
||||
|
||||
def process_config_local(config, arg, args, flags):
|
||||
config.add(args.item, '_ITEM', False)
|
||||
return config
|
||||
|
||||
|
||||
def process_settings_local(settings, config):
|
||||
item = config.get('_ITEM')
|
||||
item = strip_0x(item)
|
||||
|
||||
if len(item) == 40:
|
||||
config.add(item, '_RECIPIENT', False)
|
||||
elif len(item) == 64:
|
||||
config.add(item, '_HASH', False)
|
||||
|
||||
return process_settings(settings, config)
|
||||
|
||||
|
||||
arg_flags = ArgFlag()
|
||||
arg = Arg(arg_flags)
|
||||
flags = arg_flags.STD_BASE_READ | arg_flags.TARGET
|
||||
flags = arg_flags.less(flags, arg_flags.CHAIN_SPEC)
|
||||
|
||||
argparser = chainlib.eth.cli.ArgumentParser()
|
||||
argparser = process_args(argparser, arg, flags)
|
||||
argparser.add_argument('item', type=str, help='Address or transaction to retrieve data for')
|
||||
arg_flags = chainlib.eth.cli.argflag_std_read
|
||||
argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
|
||||
argparser.add_positional('item', type=str, help='Address or transaction to retrieve data for')
|
||||
args = argparser.parse_args()
|
||||
config = chainlib.eth.cli.Config.from_args(args, arg_flags, default_config_dir=config_dir)
|
||||
|
||||
logg = process_log(args, logg)
|
||||
rpc = chainlib.eth.cli.Rpc()
|
||||
conn = rpc.connect_by_config(config)
|
||||
|
||||
config = Config()
|
||||
config = process_config(config, arg, args, flags)
|
||||
config = process_config_local(config, arg, args, flags)
|
||||
logg.debug('config loaded:\n{}'.format(config))
|
||||
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
|
||||
|
||||
settings = ChainSettings()
|
||||
settings = process_settings_local(settings, config)
|
||||
logg.debug('settings loaded:\n{}'.format(settings))
|
||||
item = add_0x(args.item)
|
||||
|
||||
|
||||
def get_transaction(conn, chain_spec, tx_hash, id_generator):
|
||||
o = transaction(tx_hash, id_generator=id_generator)
|
||||
def get_transaction(conn, tx_hash, id_generator):
|
||||
j = JSONRPCRequest(id_generator=id_generator)
|
||||
o = j.template()
|
||||
o['method'] = 'eth_getTransactionByHash'
|
||||
o['params'].append(tx_hash)
|
||||
o = j.finalize(o)
|
||||
tx_src = conn.do(o)
|
||||
if tx_src == None:
|
||||
logg.error('Transaction {} not found'.format(tx_hash))
|
||||
@@ -118,8 +81,12 @@ def get_transaction(conn, chain_spec, tx_hash, id_generator):
|
||||
status = -1
|
||||
rcpt = None
|
||||
|
||||
o = receipt(tx_hash, id_generator=id_generator)
|
||||
o = j.template()
|
||||
o['method'] = 'eth_getTransactionReceipt'
|
||||
o['params'].append(tx_hash)
|
||||
o = j.finalize(o)
|
||||
rcpt = conn.do(o)
|
||||
#status = int(strip_0x(rcpt['status']), 16)
|
||||
|
||||
if tx == None:
|
||||
tx = Tx(tx_src)
|
||||
@@ -130,16 +97,23 @@ def get_transaction(conn, chain_spec, tx_hash, id_generator):
|
||||
r = conn.do(o)
|
||||
block = Block(r)
|
||||
tx.apply_block(block)
|
||||
logg.debug('foo {}'.format(tx_src))
|
||||
tx.generate_wire(chain_spec)
|
||||
return tx
|
||||
|
||||
|
||||
|
||||
def get_address(conn, address, id_generator, height):
|
||||
o = code(address, height, id_generator=id_generator)
|
||||
r = conn.do(o)
|
||||
j = JSONRPCRequest(id_generator=id_generator)
|
||||
o = j.template()
|
||||
o['method'] = 'eth_getCode'
|
||||
o['params'].append(address)
|
||||
height = to_blockheight_param(height)
|
||||
o['params'].append(height)
|
||||
o = j.finalize(o)
|
||||
code = conn.do(o)
|
||||
|
||||
content = strip_0x(r, allow_empty=True)
|
||||
content = strip_0x(code, allow_empty=True)
|
||||
if len(content) == 0:
|
||||
return None
|
||||
|
||||
@@ -147,24 +121,18 @@ def get_address(conn, address, id_generator, height):
|
||||
|
||||
|
||||
def main():
|
||||
address = item
|
||||
r = None
|
||||
if settings.get('HASH') != None:
|
||||
hsh = settings.get('HASH')[0]
|
||||
r = get_transaction(
|
||||
settings.get('CONN'),
|
||||
settings.get('CHAIN_SPEC'),
|
||||
hsh,
|
||||
settings.get('RPC_ID_GENERATOR'),
|
||||
)
|
||||
if len(address) > 42:
|
||||
r = get_transaction(conn, address, rpc.id_generator)
|
||||
if not config.true('_RAW'):
|
||||
r = r.to_human()
|
||||
else:
|
||||
r = get_address(
|
||||
settings.get('CONN'),
|
||||
settings.get('RECIPIENT'),
|
||||
settings.get('RPC_ID_GENERATOR'),
|
||||
settings.get('HEIGHT'),
|
||||
)
|
||||
if config.get('_UNSAFE'):
|
||||
address = to_checksum_address(address)
|
||||
elif not is_checksum_address(address):
|
||||
raise ValueError('invalid checksum address: {}'.format(address))
|
||||
r = get_address(conn, address, rpc.id_generator, config.get('_HEIGHT'))
|
||||
if r != None:
|
||||
print(r)
|
||||
|
||||
|
||||
@@ -16,8 +16,7 @@ from hexathon import (
|
||||
even,
|
||||
)
|
||||
import sha3
|
||||
from funga.eth.signer import EIP155Signer
|
||||
from chainlib.settings import ChainSettings
|
||||
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
||||
|
||||
# local imports
|
||||
from chainlib.eth.address import AddressChecksum
|
||||
@@ -25,7 +24,6 @@ from chainlib.eth.chain import network_id
|
||||
from chainlib.eth.block import (
|
||||
block_latest,
|
||||
block_by_number,
|
||||
syncing,
|
||||
Block,
|
||||
)
|
||||
from chainlib.eth.tx import count
|
||||
@@ -36,109 +34,66 @@ from chainlib.eth.gas import (
|
||||
price,
|
||||
)
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.cli.arg import (
|
||||
Arg,
|
||||
ArgFlag,
|
||||
process_args,
|
||||
)
|
||||
from chainlib.eth.cli.config import (
|
||||
Config,
|
||||
process_config,
|
||||
)
|
||||
from chainlib.eth.cli.log import process_log
|
||||
from chainlib.eth.settings import process_settings
|
||||
|
||||
BLOCK_SAMPLES = 10
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
config_dir = os.path.join(script_dir, '..', 'data', 'config')
|
||||
|
||||
results_translation = {
|
||||
'network_id': 'Network Id',
|
||||
'block': 'Block',
|
||||
'syncing': 'Syncing',
|
||||
'gas_limit': 'Gas Limit',
|
||||
'gas_price': 'Gas Price',
|
||||
'block_time': 'Block time',
|
||||
}
|
||||
|
||||
|
||||
def process_config_local(config, arg, args, flags):
|
||||
config.add(args.local, '_LOCAL', False)
|
||||
config.add(args.long, '_LONG', False)
|
||||
config.add(args.entry, '_ENTRY', False)
|
||||
if config.get('_ENTRY') != None:
|
||||
if config.get('_ENTRY') not in results_translation.keys():
|
||||
raise ValueError('Unknown entry {}'.format(config.get('_ENTRY')))
|
||||
return config
|
||||
|
||||
arg_flags = ArgFlag()
|
||||
arg = Arg(arg_flags)
|
||||
flags = arg_flags.STD_READ | arg_flags.ENV
|
||||
|
||||
argparser = chainlib.eth.cli.ArgumentParser()
|
||||
argparser = process_args(argparser, arg, flags)
|
||||
arg_flags = chainlib.eth.cli.argflag_std_read
|
||||
argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
|
||||
argparser.add_positional('address', type=str, help='Address to retrieve info for', required=False)
|
||||
argparser.add_argument('--long', action='store_true', help='Calculate averages through sampling of blocks and txs')
|
||||
argparser.add_argument('--local', action='store_true', help='Include local info')
|
||||
argparser.add_argument('entry', nargs='?', help='Output single item')
|
||||
args = argparser.parse_args()
|
||||
|
||||
logg = process_log(args, logg)
|
||||
config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args={'long': None}, default_config_dir=config_dir)
|
||||
|
||||
config = Config()
|
||||
config = process_config(config, arg, args, flags)
|
||||
config = process_config_local(config, arg, args, flags)
|
||||
logg.debug('config loaded:\n{}'.format(config))
|
||||
holder_address = args.address
|
||||
wallet = chainlib.eth.cli.Wallet()
|
||||
wallet.from_config(config)
|
||||
if wallet.get_signer_address() == None and holder_address != None:
|
||||
wallet.from_address(holder_address)
|
||||
|
||||
settings = ChainSettings()
|
||||
settings = process_settings(settings, config)
|
||||
logg.debug('settings loaded:\n{}'.format(settings))
|
||||
rpc = chainlib.eth.cli.Rpc(wallet=wallet)
|
||||
conn = rpc.connect_by_config(config)
|
||||
|
||||
token_symbol = 'eth'
|
||||
|
||||
def set_result(results, k, v, w=sys.stdout):
|
||||
kt = results_translation[k]
|
||||
if str(config.get('_ENTRY')) == k:
|
||||
w.write('{}'.format(v))
|
||||
return True
|
||||
logg.info('{}: {}\n'.format(kt, v))
|
||||
results[k] = v
|
||||
return False
|
||||
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
|
||||
|
||||
human = not config.true('_RAW')
|
||||
|
||||
longmode = config.true('_LONG')
|
||||
|
||||
def main():
|
||||
human = not config.true('_RAW')
|
||||
results = {}
|
||||
o = network_id(id_generator=rpc.id_generator)
|
||||
r = conn.do(o)
|
||||
#if human:
|
||||
# n = format(n, ',')
|
||||
sys.stdout.write('Network id: {}\n'.format(r))
|
||||
|
||||
o = network_id(id_generator=settings.get('RPC_ID_GENERATOR'))
|
||||
r = settings.get('CONN').do(o)
|
||||
if set_result(results, 'network_id', r):
|
||||
return
|
||||
|
||||
o = block_latest(id_generator=settings.get('RPC_ID_GENERATOR'))
|
||||
r = settings.get('CONN').do(o)
|
||||
try:
|
||||
n = int(r, 16)
|
||||
except ValueError:
|
||||
n = int(r)
|
||||
o = block_latest(id_generator=rpc.id_generator)
|
||||
r = conn.do(o)
|
||||
n = int(r, 16)
|
||||
first_block_number = n
|
||||
if human:
|
||||
n = format(n, ',')
|
||||
if set_result(results, 'block', n):
|
||||
return
|
||||
sys.stdout.write('Block: {}\n'.format(n))
|
||||
|
||||
o = block_by_number(first_block_number, False, id_generator=settings.get('RPC_ID_GENERATOR'))
|
||||
r = settings.get('CONN').do(o)
|
||||
o = block_by_number(first_block_number, False, id_generator=rpc.id_generator)
|
||||
r = conn.do(o)
|
||||
last_block = Block(r)
|
||||
last_timestamp = last_block.timestamp
|
||||
|
||||
if config.true('_LONG'):
|
||||
if longmode:
|
||||
aggr_time = 0.0
|
||||
aggr_gas = 0
|
||||
for i in range(BLOCK_SAMPLES):
|
||||
o = block_by_number(first_block_number-i, False, id_generator=settings.get('RPC_ID_GENERATOR'))
|
||||
r = settings.get('CONN').do(o)
|
||||
o = block_by_number(first_block_number-i, False, id_generator=rpc.id_generator)
|
||||
r = conn.do(o)
|
||||
block = Block(r)
|
||||
aggr_time += last_block.timestamp - block.timestamp
|
||||
|
||||
@@ -152,31 +107,22 @@ def main():
|
||||
if human:
|
||||
n = format(n, ',')
|
||||
|
||||
if set_result(results, 'gas_limit', n):
|
||||
return
|
||||
if set_result(results, 'block_time', aggr_time / BLOCK_SAMPLES):
|
||||
return
|
||||
sys.stdout.write('Gaslimit: {}\n'.format(n))
|
||||
sys.stdout.write('Blocktime: {}\n'.format(aggr_time / BLOCK_SAMPLES))
|
||||
|
||||
o = price(id_generator=settings.get('RPC_ID_GENERATOR'))
|
||||
r = settings.get('CONN').do(o)
|
||||
o = price(id_generator=rpc.id_generator)
|
||||
r = conn.do(o)
|
||||
n = int(r, 16)
|
||||
if human:
|
||||
n = format(n, ',')
|
||||
if set_result(results, 'gas_price', n):
|
||||
return
|
||||
sys.stdout.write('Gasprice: {}\n'.format(n))
|
||||
|
||||
if config.get('_LOCAL'):
|
||||
o = syncing()
|
||||
r = settings.get('CONN').do(o)
|
||||
if set_result(results, 'syncing', r):
|
||||
return
|
||||
|
||||
if config.get('_ENTRY') != None:
|
||||
raise RuntimeError('entry {} ({}) not processed, please review the flag settings'.format(config.get('_ENTRY'), results_translation[config.get('_ENTRY')]))
|
||||
|
||||
for k in results.keys():
|
||||
kt = results_translation[k]
|
||||
sys.stdout.write('{}: {}\n'.format(kt, results[k]))
|
||||
if holder_address != None:
|
||||
o = count(holder_address)
|
||||
r = conn.do(o)
|
||||
n = int(r, 16)
|
||||
sys.stdout.write('Address: {}\n'.format(holder_address))
|
||||
sys.stdout.write('Nonce: {}\n'.format(n))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -10,15 +10,13 @@ import logging
|
||||
import urllib
|
||||
|
||||
# external imports
|
||||
from chainlib.settings import ChainSettings
|
||||
from funga.eth.signer import EIP155Signer
|
||||
from funga.eth.keystore.dict import DictKeystore
|
||||
import chainlib.eth.cli
|
||||
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
||||
from crypto_dev_signer.keystore.dict import DictKeystore
|
||||
from hexathon import (
|
||||
add_0x,
|
||||
strip_0x,
|
||||
)
|
||||
from chainlib.error import SignerMissingException
|
||||
from chainlib.chain import ChainSpec
|
||||
|
||||
# local imports
|
||||
from chainlib.eth.address import to_checksum
|
||||
@@ -39,121 +37,100 @@ from chainlib.eth.tx import (
|
||||
TxFactory,
|
||||
raw,
|
||||
)
|
||||
from chainlib.error import SignerMissingException
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.eth.runnable.util import decode_for_puny_humans
|
||||
from chainlib.eth.jsonrpc import to_blockheight_param
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.cli.arg import (
|
||||
Arg,
|
||||
ArgFlag,
|
||||
process_args,
|
||||
)
|
||||
from chainlib.eth.cli.config import (
|
||||
Config,
|
||||
process_config,
|
||||
)
|
||||
from chainlib.eth.cli.log import process_log
|
||||
from chainlib.eth.settings import process_settings
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
config_dir = os.path.join(script_dir, '..', 'data', 'config')
|
||||
|
||||
|
||||
def process_config_local(config, arg, args, flags):
|
||||
config.add(args.deploy, '_DEPLOY', False)
|
||||
config.add(args.mode, '_MODE', False)
|
||||
config.add(args.data, '_DATA', False)
|
||||
return config
|
||||
|
||||
|
||||
arg_flags = ArgFlag()
|
||||
arg = Arg(arg_flags)
|
||||
flags = arg_flags.STD_WRITE | arg_flags.EXEC
|
||||
|
||||
argparser = chainlib.eth.cli.ArgumentParser()
|
||||
argparser = process_args(argparser, arg, flags)
|
||||
argparser.add_argument('--deploy', action='store_true', help='Deploy data as contract')
|
||||
argparser.add_argument('--mode', choices=['tx', 'call'], type=str, help='Mode of operation')
|
||||
argparser.add_argument('data', type=str, help='Transaction data')
|
||||
arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC
|
||||
argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
|
||||
argparser.add_positional('data', type=str, help='Transaction data')
|
||||
args = argparser.parse_args()
|
||||
config = chainlib.eth.cli.Config.from_args(args, arg_flags, default_config_dir=config_dir)
|
||||
|
||||
logg = process_log(args, logg)
|
||||
block_all = args.ww
|
||||
block_last = args.w or block_all
|
||||
|
||||
config = Config()
|
||||
config = process_config(config, arg, args, flags)
|
||||
config = process_config_local(config, arg, args, flags)
|
||||
logg.debug('config loaded:\n{}'.format(config))
|
||||
wallet = chainlib.eth.cli.Wallet(EIP155Signer)
|
||||
wallet.from_config(config)
|
||||
|
||||
settings = ChainSettings()
|
||||
settings = process_settings(settings, config)
|
||||
logg.debug('settings loaded:\n{}'.format(settings))
|
||||
rpc = chainlib.eth.cli.Rpc(wallet=wallet)
|
||||
conn = rpc.connect_by_config(config)
|
||||
|
||||
send = config.true('_RPC_SEND')
|
||||
|
||||
if config.get('_EXEC_ADDRESS') != None:
|
||||
send = False
|
||||
|
||||
chain_spec = None
|
||||
try:
|
||||
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def main():
|
||||
if config.get('_EXEC_ADDRESS') != None or config.true('_DEPLOY'):
|
||||
if not args.u and exec_address != exec_address:
|
||||
|
||||
signer_address = None
|
||||
try:
|
||||
signer = rpc.get_signer()
|
||||
signer_address = rpc.get_signer_address()
|
||||
except SignerMissingException:
|
||||
pass
|
||||
|
||||
if config.get('_EXEC_ADDRESS') != None:
|
||||
exec_address = add_0x(to_checksum(config.get('_EXEC_ADDRESS')))
|
||||
if not args.u and exec_address != add_0x(exec_address):
|
||||
raise ValueError('invalid checksum address')
|
||||
|
||||
if settings.get('SENDER_ADDRESS'):
|
||||
j = JSONRPCRequest(id_generator=settings.get('RPC_ID_GENERATOR'))
|
||||
o = j.template()
|
||||
o['method'] = 'eth_call'
|
||||
o['params'].append({
|
||||
'to': settings.get('EXEC'),
|
||||
'from': settings.get('SENDER_ADDRESS'),
|
||||
'value': '0x00',
|
||||
'gas': add_0x(int.to_bytes(8000000, 8, byteorder='big').hex()), # TODO: better get of network gas limit
|
||||
'gasPrice': '0x01',
|
||||
'data': add_0x(config.get('_DATA')),
|
||||
})
|
||||
height = to_blockheight_param(config.get('_HEIGHT'))
|
||||
o['params'].append(height)
|
||||
o = j.finalize(o)
|
||||
r = settings.get('CONN').do(o)
|
||||
try:
|
||||
print(strip_0x(r))
|
||||
except ValueError:
|
||||
sys.stderr.write('query returned an empty value ({})\n'.format(r))
|
||||
sys.exit(1)
|
||||
j = JSONRPCRequest(id_generator=rpc.id_generator)
|
||||
o = j.template()
|
||||
o['method'] = 'eth_call'
|
||||
o['params'].append({
|
||||
'to': exec_address,
|
||||
'from': signer_address,
|
||||
'value': '0x00',
|
||||
'gas': add_0x(int.to_bytes(8000000, 8, byteorder='big').hex()), # TODO: better get of network gas limit
|
||||
'gasPrice': '0x01',
|
||||
'data': add_0x(args.data),
|
||||
})
|
||||
height = to_blockheight_param(config.get('_HEIGHT'))
|
||||
o['params'].append(height)
|
||||
o = j.finalize(o)
|
||||
r = conn.do(o)
|
||||
try:
|
||||
print(strip_0x(r))
|
||||
except ValueError:
|
||||
sys.stderr.write('query returned an empty value\n')
|
||||
sys.exit(1)
|
||||
return
|
||||
|
||||
else:
|
||||
if settings.get('CHAIN_SPEC') == None:
|
||||
if signer_address != None:
|
||||
if chain_spec == None:
|
||||
raise ValueError('chain spec must be specified')
|
||||
g = TxFactory(
|
||||
settings.get('CHAIN_SPEC'),
|
||||
signer=settings.get('SIGNER'),
|
||||
gas_oracle=settings.get('GAS_ORACLE'),
|
||||
nonce_oracle=settings.get('NONCE_ORACLE'),
|
||||
)
|
||||
tx = g.template(
|
||||
settings.get('SENDER_ADDRESS'),
|
||||
settings.get('EXEC'),
|
||||
use_nonce=True,
|
||||
)
|
||||
if config.get('_DATA') != None:
|
||||
tx = g.set_code(tx, add_0x(config.get('_DATA')))
|
||||
g = TxFactory(chain_spec, signer=rpc.get_signer(), gas_oracle=rpc.get_gas_oracle(), nonce_oracle=rpc.get_nonce_oracle())
|
||||
tx = g.template(signer_address, exec_address, use_nonce=True)
|
||||
if args.data != None:
|
||||
tx = g.set_code(tx, add_0x(args.data))
|
||||
|
||||
(tx_hash_hex, o) = g.finalize(tx, id_generator=rpc.id_generator)
|
||||
|
||||
if send:
|
||||
r = settings.get('CONN').do(o)
|
||||
r = conn.do(o)
|
||||
print(r)
|
||||
else:
|
||||
if config.get('_RAW'):
|
||||
o = strip_0x(o)
|
||||
print(o)
|
||||
print(tx_hash_hex)
|
||||
|
||||
else:
|
||||
o = raw(config.get('_DATA'), id_generator=settings.get('RPC_ID_GENERATOR'))
|
||||
if settings.get('RPC_SEND'):
|
||||
r = settings.get('CONN').do(o)
|
||||
if config.true('_WAIT'):
|
||||
r = settings.get('CONN').wait(tx_hash_hex)
|
||||
if r['status'] == 0:
|
||||
logg.critical('VM revert for {}. Wish I could tell you more'.format(tx_hash_hex))
|
||||
sys.exit(1)
|
||||
o = raw(args.data, id_generator=rpc.id_generator)
|
||||
if send:
|
||||
r = conn.do(o)
|
||||
print(r)
|
||||
else:
|
||||
print(o)
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# standard imports
|
||||
import io
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import argparse
|
||||
import logging
|
||||
import urllib
|
||||
|
||||
# external imports
|
||||
from chainlib.settings import ChainSettings
|
||||
from funga.eth.signer import EIP155Signer
|
||||
from funga.eth.keystore.dict import DictKeystore
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.jsonrpc import (
|
||||
JSONRPCRequest,
|
||||
IntSequenceGenerator,
|
||||
)
|
||||
from hexathon import (
|
||||
add_0x,
|
||||
strip_0x,
|
||||
uniform as hex_uniform,
|
||||
)
|
||||
|
||||
# local imports
|
||||
from chainlib.eth.address import to_checksum
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
from chainlib.eth.nonce import (
|
||||
RPCNonceOracle,
|
||||
OverrideNonceOracle,
|
||||
)
|
||||
from chainlib.eth.gas import (
|
||||
RPCGasOracle,
|
||||
OverrideGasOracle,
|
||||
)
|
||||
from chainlib.eth.tx import (
|
||||
TxFactory,
|
||||
raw,
|
||||
)
|
||||
from chainlib.eth.error import RevertEthException
|
||||
from chainlib.eth.runnable.util import decode_for_puny_humans
|
||||
from chainlib.eth.jsonrpc import to_blockheight_param
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.cli.arg import (
|
||||
Arg,
|
||||
ArgFlag,
|
||||
process_args,
|
||||
)
|
||||
from chainlib.eth.cli.config import (
|
||||
Config,
|
||||
process_config,
|
||||
)
|
||||
from chainlib.eth.cli.log import process_log
|
||||
from chainlib.eth.settings import process_settings
|
||||
|
||||
logg = logging.getLogger()
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
config_dir = os.path.join(script_dir, '..', 'data', 'config')
|
||||
|
||||
|
||||
def process_config_local(config, arg, args, flags):
|
||||
config.add(args.ignore, '_IGNORE', False)
|
||||
config.add(args.ignore_all, '_IGNORE_ALL', False)
|
||||
config.add(args.hashes, '_HASH', False)
|
||||
return config
|
||||
|
||||
|
||||
def process_settings_local(settings, config):
|
||||
settings.set('HASH', config.get('_HASH'))
|
||||
return settings
|
||||
|
||||
|
||||
arg_flags = ArgFlag()
|
||||
arg = Arg(arg_flags)
|
||||
flags = arg_flags.STD_READ
|
||||
|
||||
argparser = chainlib.eth.cli.ArgumentParser()
|
||||
argparser = process_args(argparser, arg, flags)
|
||||
argparser.add_argument('--ignore', type=str, action='append', default=[], help='Ignore error from the given transaction')
|
||||
argparser.add_argument('--ignore-all', action='store_true', dest='ignore_all', help='Ignore errors from all transactions')
|
||||
argparser.add_argument('hashes', nargs='*', type=str, help='Transaction hashes to wait for')
|
||||
args = argparser.parse_args()
|
||||
|
||||
logg = process_log(args, logg)
|
||||
|
||||
config = Config()
|
||||
config = process_config(config, arg, args, flags)
|
||||
config = process_config_local(config, arg, args, flags)
|
||||
logg.debug('config loaded:\n{}'.format(config))
|
||||
|
||||
settings = ChainSettings()
|
||||
settings = process_settings(settings, config)
|
||||
logg.debug('settings loaded:\n{}'.format(settings))
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
hashes_ready = []
|
||||
hashes_ignore = []
|
||||
|
||||
for hsh in config.get('_IGNORE'):
|
||||
hashes_ignore.append(add_0x(hex_uniform(strip_0x(hsh))))
|
||||
|
||||
if len(settings.get('HASH')) == 1:
|
||||
hsh = settings.get('HASH')[0]
|
||||
try:
|
||||
hashes_ready = [hsh]
|
||||
except ValueError:
|
||||
logg.debug('hash argument not a hash, will try it as a file name')
|
||||
f = open(hsh)
|
||||
for hsh in f:
|
||||
hashes_ready.append(hsh)
|
||||
f.close()
|
||||
else:
|
||||
for hsh in settings.get('HASH'):
|
||||
if hsh in hashes_ready:
|
||||
logg.debug('skipping duplicate hash {}'.format(hsh))
|
||||
continue
|
||||
hashes_ready.append(hsh)
|
||||
|
||||
for hsh in hashes_ready:
|
||||
logg.info('processing transaction hash {}'.format(hsh))
|
||||
try:
|
||||
r = settings.get('CONN').wait(hsh)
|
||||
except RevertEthException:
|
||||
if config.get('_IGNORE_ALL') or hsh in hashes_ignore:
|
||||
logg.debug('ignoring revert in transaction hash {}'.format(hsh))
|
||||
continue
|
||||
sys.stderr.write('revert in transaction hash {}\n'.format(hsh))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,156 +0,0 @@
|
||||
# external imports
|
||||
from chainlib.settings import process_settings as base_process_settings
|
||||
from chainlib.error import SignerMissingException
|
||||
from hexathon import (
|
||||
add_0x,
|
||||
strip_0x,
|
||||
)
|
||||
from chainlib.block import BlockSpec
|
||||
|
||||
# local imports
|
||||
import chainlib.eth.cli
|
||||
from chainlib.eth.address import to_checksum_address
|
||||
|
||||
|
||||
def process_settings_rpc(settings, config):
|
||||
rpc = chainlib.eth.cli.Rpc(settings.get('WALLET'))
|
||||
conn = rpc.connect_by_config(config)
|
||||
|
||||
settings.set('CONN', conn)
|
||||
settings.set('RPC_ID_GENERATOR', rpc.id_generator)
|
||||
settings.set('RPC_SEND', config.true('_RPC_SEND'))
|
||||
|
||||
gas_oracle = rpc.get_gas_oracle()
|
||||
settings.set('GAS_ORACLE', gas_oracle)
|
||||
|
||||
try:
|
||||
settings.set('SIGNER', rpc.get_signer())
|
||||
sender_address = rpc.get_sender_address()
|
||||
settings.set('SENDER_ADDRESS', add_0x(sender_address))
|
||||
except AttributeError:
|
||||
pass
|
||||
except SignerMissingException:
|
||||
pass
|
||||
|
||||
nonce_oracle = rpc.get_nonce_oracle()
|
||||
settings.set('NONCE_ORACLE', nonce_oracle)
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
def process_settings_blockspec(settings, config):
|
||||
blockspec_in = None
|
||||
try:
|
||||
blockspec_in = config.get('_HEIGHT')
|
||||
except KeyError:
|
||||
return settings
|
||||
|
||||
blockspec = None
|
||||
if blockspec_in == 'latest':
|
||||
blockspec = BlockSpec.LATEST
|
||||
elif blockspec_in == 'pending':
|
||||
blockspec = BlockSpec.PENDING
|
||||
else:
|
||||
blockspec = int(blockspec_in)
|
||||
|
||||
settings.set('HEIGHT', blockspec)
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
def process_settings_wallet(settings, config):
|
||||
wallet = chainlib.eth.cli.Wallet()
|
||||
wallet.from_config(config)
|
||||
|
||||
settings.set('WALLET', wallet)
|
||||
|
||||
recipient_in = None
|
||||
try:
|
||||
recipient_in = config.get('_RECIPIENT')
|
||||
except KeyError:
|
||||
return settings
|
||||
|
||||
if recipient_in == None:
|
||||
return settings
|
||||
|
||||
if wallet.get_signer_address() == None and recipient_in != None:
|
||||
recipient_in = wallet.from_address(recipient_in)
|
||||
recipient_in = strip_0x(recipient_in)
|
||||
|
||||
recipient = to_checksum_address(recipient_in)
|
||||
if not config.true('_UNSAFE') and recipient != recipient_in:
|
||||
raise ValueError('invalid checksum address: {}'.format(recipient_in))
|
||||
recipient = add_0x(recipient)
|
||||
|
||||
settings.set('RECIPIENT', recipient)
|
||||
return settings
|
||||
|
||||
|
||||
def process_settings_contract(settings, config):
|
||||
exec_address_in = None
|
||||
try:
|
||||
exec_address_in = config.get('_EXEC_ADDRESS')
|
||||
except KeyError:
|
||||
return settings
|
||||
|
||||
if exec_address_in == None:
|
||||
return settings
|
||||
|
||||
exec_address = to_checksum_address(exec_address_in)
|
||||
if not config.true('_UNSAFE') and exec_address != exec_address_in:
|
||||
raise ValueError('invalid checksum address: {}'.format(exec_address_in))
|
||||
exec_address = add_0x(exec_address)
|
||||
|
||||
settings.set('EXEC', exec_address)
|
||||
return settings
|
||||
|
||||
|
||||
def process_settings_data(settings, config):
|
||||
data = None
|
||||
try:
|
||||
data = config.get('_DATA')
|
||||
except KeyError:
|
||||
return settings
|
||||
|
||||
if data == None:
|
||||
return settings
|
||||
|
||||
data = add_0x(data)
|
||||
settings.set('DATA', data)
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
def process_settings_hash(settings, config):
|
||||
hshs = None
|
||||
try:
|
||||
hshs = config.get('_HASH')
|
||||
except KeyError:
|
||||
return settings
|
||||
|
||||
if isinstance(hshs, str):
|
||||
hshs = [hshs]
|
||||
|
||||
r = []
|
||||
for hsh in hshs:
|
||||
hsh = strip_0x(hsh)
|
||||
l = len(hsh)
|
||||
if l != 64:
|
||||
raise ValueError('invalid hash length {} for {}'.format(l, hsh))
|
||||
hsh = add_0x(hsh)
|
||||
r.append(hsh)
|
||||
|
||||
settings.set('HASH', r)
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
def process_settings(settings, config):
|
||||
settings = base_process_settings(settings, config)
|
||||
settings = process_settings_wallet(settings, config)
|
||||
settings = process_settings_rpc(settings, config)
|
||||
settings = process_settings_blockspec(settings, config)
|
||||
settings = process_settings_data(settings, config)
|
||||
settings = process_settings_hash(settings, config)
|
||||
settings = process_settings_contract(settings, config)
|
||||
return settings
|
||||
@@ -1,53 +0,0 @@
|
||||
# standard imports
|
||||
import logging
|
||||
import json
|
||||
|
||||
# external imports
|
||||
from potaahto.symbols import snake_and_camel
|
||||
from hexathon import (
|
||||
uniform,
|
||||
strip_0x,
|
||||
)
|
||||
|
||||
# local imports
|
||||
from chainlib.src import (
|
||||
Src as BaseSrc,
|
||||
SrcItem,
|
||||
)
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Src(BaseSrc):
|
||||
|
||||
@classmethod
|
||||
def src_normalize(self, v):
|
||||
src = snake_and_camel(v)
|
||||
logg.debug('normalize has {}'.format(src))
|
||||
if isinstance(src.get('v'), str):
|
||||
try:
|
||||
src['v'] = int(src['v'])
|
||||
except ValueError:
|
||||
src['v'] = int(src['v'], 16)
|
||||
return src
|
||||
|
||||
|
||||
def normal(self, v, typ=SrcItem.AUTO):
|
||||
if typ == SrcItem.SRC:
|
||||
return self.src_normalize(v)
|
||||
|
||||
if typ == SrcItem.HASH:
|
||||
v = strip_0x(v, pad=False)
|
||||
v = uniform(v, compact_value=True)
|
||||
elif typ == SrcItem.ADDRESS:
|
||||
v = strip_0x(v, pad=False)
|
||||
v = uniform(v, compact_value=True)
|
||||
elif typ == SrcItem.PAYLOAD:
|
||||
v = strip_0x(v, pad=False, allow_empty=True)
|
||||
v = uniform(v, compact_value=False, allow_empty=True)
|
||||
|
||||
return v
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return json.dumps(self.src)
|
||||
@@ -10,31 +10,22 @@ from hexathon import (
|
||||
strip_0x,
|
||||
add_0x,
|
||||
compact,
|
||||
to_int as hex_to_int,
|
||||
same as hex_same,
|
||||
)
|
||||
from rlp import decode as rlp_decode
|
||||
from rlp import encode as rlp_encode
|
||||
from funga.eth.transaction import EIP155Transaction
|
||||
from funga.eth.encoding import (
|
||||
public_key_to_address,
|
||||
chain_id_to_v,
|
||||
)
|
||||
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
|
||||
from chainlib.hash import keccak256_hex_to_hex
|
||||
from chainlib.status import Status
|
||||
from chainlib.jsonrpc import JSONRPCRequest
|
||||
from chainlib.tx import (
|
||||
Tx as BaseTx,
|
||||
TxResult as BaseTxResult,
|
||||
)
|
||||
from chainlib.tx import Tx as BaseTx
|
||||
from chainlib.eth.nonce import (
|
||||
nonce as nonce_query,
|
||||
nonce_confirmed as nonce_query_confirmed,
|
||||
)
|
||||
from chainlib.eth.address import is_same_address
|
||||
from chainlib.block import BlockSpec
|
||||
from chainlib.src import SrcItem
|
||||
|
||||
# local imports
|
||||
from .address import to_checksum
|
||||
@@ -46,7 +37,6 @@ from .constant import (
|
||||
)
|
||||
from .contract import ABIContractEncoder
|
||||
from .jsonrpc import to_blockheight_param
|
||||
from .src import Src
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
@@ -103,11 +93,7 @@ def pack(tx_src, chain_spec):
|
||||
tx_src['r'],
|
||||
tx_src['s'],
|
||||
]:
|
||||
try:
|
||||
a = strip_0x(a)
|
||||
except TypeError:
|
||||
a = strip_0x(hex(a)) # believe it or not, eth_tester returns signatures as ints not hex
|
||||
for b in bytes.fromhex(a):
|
||||
for b in bytes.fromhex(strip_0x(a)):
|
||||
signature[cursor] = b
|
||||
cursor += 1
|
||||
|
||||
@@ -174,14 +160,14 @@ def __unpack_raw(tx_raw_bytes, chain_id=1):
|
||||
vb = chain_id
|
||||
if chain_id != 0:
|
||||
v = int.from_bytes(d[6], 'big')
|
||||
if v > 29:
|
||||
vb = v - (chain_id * 2) - 35
|
||||
vb = v - (chain_id * 2) - 35
|
||||
r = bytearray(32)
|
||||
r[32-len(d[7]):] = d[7]
|
||||
s = bytearray(32)
|
||||
s[32-len(d[8]):] = d[8]
|
||||
logg.debug('vb {}'.format(vb))
|
||||
sig = b''.join([r, s, bytes([vb])])
|
||||
#so = KeyAPI.Signature(signature_bytes=sig)
|
||||
|
||||
h = sha3.keccak_256()
|
||||
h.update(rlp_encode(d))
|
||||
@@ -313,7 +299,7 @@ class TxFactory:
|
||||
:param chain_spec: Chain spec to use for signer.
|
||||
:type chain_spec: chainlib.chain.ChainSpec
|
||||
:param signer: Signer middleware.
|
||||
:type param: Object implementing interface ofchainlib.eth.connection.sign_transaction_to_wire
|
||||
:type param: Object implementing interface of chainlib.eth.connection.sign_transaction_to_wire
|
||||
:param gas_oracle: Backend to generate gas parameters
|
||||
:type gas_oracle: Object implementing chainlib.eth.gas.GasOracle interface
|
||||
:param nonce_oracle: Backend to generate gas parameters
|
||||
@@ -409,15 +395,11 @@ class TxFactory:
|
||||
"""
|
||||
txe = EIP155Transaction(tx, tx['nonce'], tx['chainId'])
|
||||
txes = txe.serialize()
|
||||
gas_price = strip_0x(txes['gasPrice'])
|
||||
gas_price = compact(gas_price)
|
||||
gas = strip_0x(txes['gas'])
|
||||
gas = compact(gas)
|
||||
return {
|
||||
'from': tx['from'],
|
||||
'to': txes['to'],
|
||||
'gasPrice': add_0x(gas_price, compact_value=True),
|
||||
'gas': add_0x(gas, compact_value=True),
|
||||
'gasPrice': '0x' + compact(txes['gasPrice']),
|
||||
'gas': '0x' + compact(txes['gas']),
|
||||
'data': txes['data'],
|
||||
}
|
||||
|
||||
@@ -438,9 +420,7 @@ class TxFactory:
|
||||
elif tx_format == TxFormat.RLP_SIGNED:
|
||||
return self.build_raw(tx)
|
||||
elif tx_format == TxFormat.RAW_ARGS:
|
||||
return strip_0x(tx['data'])
|
||||
elif tx_format == TxFormat.DICT:
|
||||
return tx
|
||||
return tx['data']
|
||||
raise NotImplementedError('tx formatting {} not implemented'.format(tx_format))
|
||||
|
||||
|
||||
@@ -520,51 +500,7 @@ class TxFactory:
|
||||
return o
|
||||
|
||||
|
||||
class TxResult(BaseTxResult, Src):
|
||||
|
||||
def apply_src(self, v):
|
||||
self.contract = None
|
||||
|
||||
v = super(TxResult, self).apply_src(v)
|
||||
|
||||
self.set_hash(v['transaction_hash'])
|
||||
try:
|
||||
status_number = int(v['status'], 16)
|
||||
except TypeError:
|
||||
status_number = int(v['status'])
|
||||
except KeyError as e:
|
||||
if strict:
|
||||
raise(e)
|
||||
logg.debug('setting "success" status on missing status property for {}'.format(self.hash))
|
||||
status_number = 1
|
||||
|
||||
if v['block_number'] == None:
|
||||
self.status = Status.PENDING
|
||||
else:
|
||||
if status_number == 1:
|
||||
self.status = Status.SUCCESS
|
||||
elif status_number == 0:
|
||||
self.status = Status.ERROR
|
||||
try:
|
||||
self.tx_index = hex_to_int(v['transaction_index'])
|
||||
except TypeError:
|
||||
self.tx_index = int(v['transaction_index'])
|
||||
self.block_hash = v['block_hash']
|
||||
|
||||
|
||||
# TODO: replace with rpc receipt/transaction translator when available
|
||||
contract_address = v.get('contract_address')
|
||||
if contract_address != None:
|
||||
self.contract = contract_address
|
||||
|
||||
self.logs = v['logs']
|
||||
try:
|
||||
self.fee_cost = hex_to_int(v['gas_used'])
|
||||
except TypeError:
|
||||
self.fee_cost = int(v['gas_used'])
|
||||
|
||||
|
||||
class Tx(BaseTx, Src):
|
||||
class Tx(BaseTx):
|
||||
"""Wraps transaction data, transaction receipt data and block data, enforces local standardization of fields, and provides useful output formats for viewing transaction contents.
|
||||
|
||||
If block is applied, the transaction data or transaction hash must exist in its transactions array.
|
||||
@@ -581,88 +517,106 @@ class Tx(BaseTx, Src):
|
||||
#:todo: divide up constructor method
|
||||
"""
|
||||
|
||||
def __init__(self, src, block=None, result=None, strict=False, rcpt=None):
|
||||
# backwards compat
|
||||
self.gas_price = None
|
||||
self.gas_limit = None
|
||||
def __init__(self, src, block=None, rcpt=None):
|
||||
self.__rcpt_block_hash = None
|
||||
|
||||
src = self.src_normalize(src)
|
||||
self.index = -1
|
||||
tx_hash = add_0x(src['hash'])
|
||||
self.hash = strip_0x(tx_hash)
|
||||
if block != None:
|
||||
self.apply_block(block)
|
||||
try:
|
||||
self.value = int(strip_0x(src['value']), 16)
|
||||
except TypeError:
|
||||
self.value = int(src['value'])
|
||||
try:
|
||||
self.nonce = int(strip_0x(src['nonce']), 16)
|
||||
except TypeError:
|
||||
self.nonce = int(src['nonce'])
|
||||
address_from = strip_0x(src['from'])
|
||||
try:
|
||||
self.gas_price = int(strip_0x(src['gasPrice']), 16)
|
||||
except TypeError:
|
||||
self.gas_price = int(src['gasPrice'])
|
||||
try:
|
||||
self.gas_limit = int(strip_0x(src['gas']), 16)
|
||||
except TypeError:
|
||||
self.gas_limit = int(src['gas'])
|
||||
self.outputs = [to_checksum(address_from)]
|
||||
self.contract = None
|
||||
self.v = None
|
||||
self.r = None
|
||||
self.s = None
|
||||
|
||||
super(Tx, self).__init__(src, block=block, result=result, strict=strict)
|
||||
|
||||
if result == None and rcpt != None:
|
||||
self.apply_receipt(rcpt)
|
||||
|
||||
|
||||
def apply_src(self, src):
|
||||
try:
|
||||
inpt = src['input']
|
||||
except KeyError:
|
||||
inpt = src['data']
|
||||
src['input'] = src['data']
|
||||
|
||||
src = super(Tx, self).apply_src(src)
|
||||
|
||||
hsh = self.normal(src['hash'], SrcItem.HASH)
|
||||
self.set_hash(hsh)
|
||||
|
||||
try:
|
||||
self.value = hex_to_int(src['value'])
|
||||
except TypeError:
|
||||
self.value = int(src['value'])
|
||||
|
||||
try:
|
||||
self.nonce = hex_to_int(src['nonce'])
|
||||
except TypeError:
|
||||
self.nonce = int(src['nonce'])
|
||||
|
||||
try:
|
||||
self.fee_limit = hex_to_int(src['gas'])
|
||||
except TypeError:
|
||||
self.fee_limit = int(src['gas'])
|
||||
|
||||
try:
|
||||
self.fee_price = hex_to_int(src['gas_price'])
|
||||
except TypeError:
|
||||
self.fee_price = int(src['gas_price'])
|
||||
|
||||
self.gas_price = self.fee_price
|
||||
self.gas_limit = self.fee_limit
|
||||
|
||||
address_from = self.normal(src['from'], SrcItem.ADDRESS)
|
||||
self.outputs = [to_checksum(address_from)]
|
||||
if inpt != '0x':
|
||||
inpt = strip_0x(inpt)
|
||||
else:
|
||||
inpt = ''
|
||||
self.payload = inpt
|
||||
|
||||
to = src['to']
|
||||
if to == None:
|
||||
to = ZERO_ADDRESS
|
||||
self.inputs = [to_checksum(strip_0x(to))]
|
||||
|
||||
self.payload = self.normal(src['input'], SrcItem.PAYLOAD)
|
||||
|
||||
self.block = block
|
||||
try:
|
||||
self.set_wire(src['raw'])
|
||||
self.wire = src['raw']
|
||||
except KeyError:
|
||||
logg.debug('no inline raw tx src, and no raw rendering implemented, field will be "None"')
|
||||
logg.warning('no inline raw tx src, and no raw rendering implemented, field will be "None"')
|
||||
|
||||
self.status = Status.PENDING
|
||||
self.logs = None
|
||||
|
||||
if rcpt != None:
|
||||
self.apply_receipt(rcpt)
|
||||
|
||||
self.v = src.get('v')
|
||||
self.r = src.get('r')
|
||||
self.s = src.get('s')
|
||||
|
||||
#self.status = Status.PENDING
|
||||
self.wire = None
|
||||
|
||||
self.tx_src = src
|
||||
|
||||
|
||||
def src(self):
|
||||
"""Retrieve normalized representation source used to construct transaction object.
|
||||
|
||||
:rtype: dict
|
||||
:returns: Transaction representation
|
||||
"""
|
||||
return self.tx_src
|
||||
|
||||
|
||||
@classmethod
|
||||
def src_normalize(self, src):
|
||||
"""Normalizes transaction representation source data.
|
||||
|
||||
:param src: Transaction representation
|
||||
:type src: dict
|
||||
:rtype: dict
|
||||
:returns: Transaction representation, normalized
|
||||
"""
|
||||
src = snake_and_camel(src)
|
||||
|
||||
if isinstance(src.get('v'), str):
|
||||
try:
|
||||
src['v'] = int(src['v'])
|
||||
except ValueError:
|
||||
src['v'] = int(src['v'], 16)
|
||||
return src
|
||||
|
||||
|
||||
def as_dict(self):
|
||||
return self.src
|
||||
return self.src()
|
||||
|
||||
|
||||
def apply_receipt(self, rcpt, strict=False):
|
||||
result = TxResult(rcpt)
|
||||
self.apply_result(result)
|
||||
|
||||
|
||||
def apply_result(self, result, strict=False):
|
||||
def apply_receipt(self, rcpt):
|
||||
"""Apply receipt data to transaction object.
|
||||
|
||||
Effect is the same as passing a receipt at construction.
|
||||
@@ -670,14 +624,46 @@ class Tx(BaseTx, Src):
|
||||
:param rcpt: Receipt data
|
||||
:type rcpt: dict
|
||||
"""
|
||||
if not hex_same(result.hash, self.hash):
|
||||
raise ValueError('result hash {} does not match transaction hash {}'.format(result.hash, self.hash))
|
||||
rcpt = self.src_normalize(rcpt)
|
||||
logg.debug('rcpt {}'.format(rcpt))
|
||||
|
||||
tx_hash = add_0x(rcpt['transaction_hash'])
|
||||
if rcpt['transaction_hash'] != add_0x(self.hash):
|
||||
raise ValueError('rcpt hash {} does not match transaction hash {}'.format(rcpt['transaction_hash'], self.hash))
|
||||
|
||||
block_hash = add_0x(rcpt['block_hash'])
|
||||
if self.block != None:
|
||||
if not hex_same(result.block_hash, self.block.hash):
|
||||
raise ValueError('result block hash {} does not match transaction block hash {}'.format(result.block_hash, self.block.hash))
|
||||
if block_hash != add_0x(self.block.hash):
|
||||
raise ValueError('rcpt block hash {} does not match transaction block hash {}'.format(rcpt['block_hash'], self.block.hash))
|
||||
|
||||
super(Tx, self).apply_result(result)
|
||||
try:
|
||||
status_number = int(rcpt['status'], 16)
|
||||
except TypeError:
|
||||
status_number = int(rcpt['status'])
|
||||
if rcpt['block_number'] == None:
|
||||
self.status = Status.PENDING
|
||||
else:
|
||||
if status_number == 1:
|
||||
self.status = Status.SUCCESS
|
||||
elif status_number == 0:
|
||||
self.status = Status.ERROR
|
||||
try:
|
||||
self.tx_index = int(rcpt['transaction_index'], 16)
|
||||
except TypeError:
|
||||
self.tx_index = int(rcpt['transaction_index'])
|
||||
# TODO: replace with rpc receipt/transaction translator when available
|
||||
contract_address = rcpt.get('contractAddress')
|
||||
if contract_address == None:
|
||||
contract_address = rcpt.get('contract_address')
|
||||
if contract_address != None:
|
||||
self.contract = contract_address
|
||||
self.logs = rcpt['logs']
|
||||
try:
|
||||
self.gas_used = int(rcpt['gasUsed'], 16)
|
||||
except TypeError:
|
||||
self.gas_used = int(rcpt['gasUsed'])
|
||||
|
||||
self.__rcpt_block_hash = rcpt['block_hash']
|
||||
|
||||
|
||||
def apply_block(self, block):
|
||||
@@ -686,6 +672,9 @@ class Tx(BaseTx, Src):
|
||||
:param block: Block object
|
||||
:type block: chainlib.block.Block
|
||||
"""
|
||||
if self.__rcpt_block_hash != None:
|
||||
if block.hash != self.__rcpt_block_hash:
|
||||
raise ValueError('block hash {} does not match already applied receipt block hash {}'.format(block.hash, self.__rcpt_block_hash))
|
||||
self.index = block.get_tx(self.hash)
|
||||
self.block = block
|
||||
|
||||
@@ -699,18 +688,18 @@ class Tx(BaseTx, Src):
|
||||
:returns: Wire format, in hex
|
||||
"""
|
||||
if self.wire == None:
|
||||
b = pack(self.src, chain_spec)
|
||||
self.set_wire(add_0x(b.hex()))
|
||||
b = pack(self.src(), chain_spec)
|
||||
self.wire = add_0x(b.hex())
|
||||
return self.wire
|
||||
|
||||
|
||||
@staticmethod
|
||||
def from_src(src, block=None, rcpt=None, strict=False):
|
||||
def from_src(src, block=None, rcpt=None):
|
||||
"""Creates a new Tx object.
|
||||
|
||||
Alias of constructor.
|
||||
"""
|
||||
return Tx(src, block=block, rcpt=rcpt, strict=strict)
|
||||
return Tx(src, block=block, rcpt=rcpt)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
@@ -749,16 +738,13 @@ input {}
|
||||
self.payload,
|
||||
)
|
||||
|
||||
status = Status.UNKNOWN.name
|
||||
logg.debug('selfstatus {}'.format(self.status))
|
||||
if self.result != None and self.result.status != Status.PENDING:
|
||||
if self.status != Status.PENDING:
|
||||
s += """gas_used {}
|
||||
""".format(
|
||||
self.result.fee_cost,
|
||||
status = self.result.status.name
|
||||
self.gas_used,
|
||||
)
|
||||
|
||||
s += 'status ' + status + '\n'
|
||||
s += 'status ' + self.status.name + '\n'
|
||||
|
||||
if self.block != None:
|
||||
s += """block_number {}
|
||||
@@ -767,7 +753,7 @@ tx_index {}
|
||||
""".format(
|
||||
self.block.number,
|
||||
self.block.hash,
|
||||
self.result.tx_index,
|
||||
self.tx_index,
|
||||
)
|
||||
|
||||
|
||||
@@ -780,9 +766,7 @@ tx_index {}
|
||||
if self.wire != None:
|
||||
s += """src {}
|
||||
""".format(
|
||||
str(self.wire),
|
||||
self.wire,
|
||||
)
|
||||
|
||||
return s
|
||||
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ from hexathon import (
|
||||
)
|
||||
from chainlib.eth.tx import receipt
|
||||
|
||||
from funga.eth.signer import EIP155Signer
|
||||
from funga.eth.encoding import private_key_to_address
|
||||
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
||||
from crypto_dev_signer.encoding import private_key_to_address
|
||||
|
||||
|
||||
logg = logging.getLogger().getChild(__name__)
|
||||
|
||||
@@ -5,8 +5,8 @@ import logging
|
||||
|
||||
# external imports
|
||||
import eth_tester
|
||||
from funga.eth.signer import EIP155Signer
|
||||
from funga.eth.keystore.dict import DictKeystore
|
||||
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
|
||||
from crypto_dev_signer.keystore.dict import DictKeystore
|
||||
from hexathon import (
|
||||
strip_0x,
|
||||
add_0x,
|
||||
@@ -26,8 +26,7 @@ from chainlib.connection import (
|
||||
from chainlib.eth.address import to_checksum_address
|
||||
from chainlib.chain import ChainSpec
|
||||
|
||||
#logg = logging.getLogger(__name__)
|
||||
logg = logging.getLogger()
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
test_address = bytes.fromhex('Eb3907eCad74a0013c259D5874AE7f22DcBcC95C')
|
||||
|
||||
@@ -64,7 +63,6 @@ class EthTesterCase(unittest.TestCase):
|
||||
self.helper = eth_tester_instance
|
||||
self.backend = self.helper.backend
|
||||
self.rpc = TestRPCConnection(None, eth_tester_instance, self.signer)
|
||||
|
||||
for a in self.keystore.list():
|
||||
self.accounts.append(add_0x(to_checksum_address(a)))
|
||||
|
||||
@@ -75,6 +73,7 @@ class EthTesterCase(unittest.TestCase):
|
||||
RPCConnection.register_constructor(ConnType.CUSTOM, rpc_with_tester, tag='signer')
|
||||
RPCConnection.register_location('custom', self.chain_spec, tag='default', exist_ok=True)
|
||||
RPCConnection.register_location('custom', self.chain_spec, tag='signer', exist_ok=True)
|
||||
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
.TH eth-balance 1
|
||||
|
||||
.SH NAME
|
||||
eth-balance \- Get network gas token balance for an address
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBeth-balance\fP [ -p \fIrpc_provider\fP ] \fIaddress\fP
|
||||
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
Query the network for the gas token balance of an account.
|
||||
.P
|
||||
The balance will be returned as an integer value denominated in the gas unit.
|
||||
|
||||
|
||||
.SS OPTION
|
||||
@@ -1 +0,0 @@
|
||||
a Address to get balance for. -a, --address
|
||||
@@ -1,7 +0,0 @@
|
||||
.SH ABOUT THE CHECKSUM
|
||||
.P
|
||||
Checksum protection may be used as protection against address typos.
|
||||
.P
|
||||
It uses the value of the address itself as input to an algorithm, which results in altering the case of the letters in the hexadecimal address.
|
||||
.P
|
||||
A checksum address consisting of only numbers will always pass checksum.
|
||||
@@ -1,11 +0,0 @@
|
||||
.TH eth-checksum 1
|
||||
|
||||
.SH NAME
|
||||
eth-checksum \- Calculate checksum address
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBeth-checksum\fP \fIaddress\fP
|
||||
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
Converts \fIaddress\fP into a checksum-protected address.
|
||||
@@ -1,15 +0,0 @@
|
||||
.TH eth-count 1
|
||||
|
||||
.SH NAME
|
||||
eth-count \- Get transaction count for an address
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBeth-count\fP [ -p \fIrpc_provider\fP ] \fIaddress\fP
|
||||
|
||||
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
Query the network for the number of transactions known for an account. The result can be used as the \fInonce\fP value for a consecutive transaction.
|
||||
|
||||
|
||||
.SS OPTIONS
|
||||
@@ -1 +0,0 @@
|
||||
a Address to count transactions for. -a, --address
|
||||
@@ -1,14 +0,0 @@
|
||||
.TH eth-decode 1
|
||||
|
||||
.SH NAME
|
||||
eth-decode \- Decode a transaction in wire-format to human readable form
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBeth-decode\fI [ -i \fIchain_spec\fP ] encoded_tx
|
||||
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
This tool deserializes a wire-format transaction and outputs its fields in human-readable form. It does not require a node to operate, and does not apply transaction state.
|
||||
.P
|
||||
The transaction wire-format is an ordered concatenation of transaction values, which in turn is serialized using the Recurive Length Prefix (RLP) format. \fBeth-decode\fP accepts the RLP-encoded transaction as a hex string.
|
||||
.P
|
||||
@@ -1,31 +0,0 @@
|
||||
.SH MODES
|
||||
|
||||
The modes parameter specifies what kind of operaion the encoding should be generated for. There are three valid modes:
|
||||
|
||||
.SS tx
|
||||
Generates a transaction that changes state. Used with \fB--format\fP \fIrpc\fP it will generate an \fIeth_sendRawTransaction\fP jsonrpc object. Used with \fB--format\fP \fIbin\fP it outputs signed RLP only in hexdecimal.
|
||||
|
||||
.SS call
|
||||
Generates a query that reads state. Used with \fB--format\fP \fIrpc\fP it will generate a \fIeth_call\fP jsonrpc object with applicable fields filled out from environment, arguments and/or rpc retrieval. \fB--format\fP \fIbin\fP is not valid for this mode.
|
||||
|
||||
.SS arg
|
||||
Encodes the argument part only, optionally with a method signature. \fB--format\fP \fIrpc\fP is not valid for this mode.
|
||||
|
||||
.SH SPECIFYING VALUES
|
||||
Dynamic value types are not yet supported.
|
||||
|
||||
.SS Specifying an unsigned integer:
|
||||
.IP u:1024
|
||||
|
||||
.SS Specifying an address:
|
||||
.IP a:19062190B1925b5b6689D7073fDfC8c2976EF8Cb
|
||||
|
||||
.SS Specifying bytes values:
|
||||
|
||||
.IP b:deadbeef
|
||||
.IP b4:deadbeef
|
||||
.IP b32:deadbeef
|
||||
|
||||
.SS Specifying a string value:
|
||||
|
||||
.IP s:foobar
|
||||
@@ -1,22 +0,0 @@
|
||||
.SS Build a signed ERC20 transfer in wire format, setting nonce and fee details manually.
|
||||
.EX
|
||||
$ eth-encode -f bin -y <\fIkey_file_path\fP> -e <\fItoken_address\fP> --fee-price 1000000000 --fee-limit 100000 --nonce 42 --signature transfer a:00000000000000000000000000000000DeaDBeef u:1024
|
||||
.EE
|
||||
|
||||
.SS Build Smart contract call with method signature, retrieving fee and nonce settings from rpc
|
||||
|
||||
\fBeth-encode\fP --mode call -f rpc -e <\fItoken_address\fP> --signature balanceOf -p <\fIrpc_endpoint\fP> a:deadbeef
|
||||
|
||||
.SS Build smart contract ERC20 transfer argument with signature
|
||||
.EX
|
||||
\fBeth-encode\fP --mode arg --signature transfer a:00000000000000000000000000000000DeaDBeef u:1024
|
||||
.TP Outupt
|
||||
a9059cbb00000000000000000000000000000000000000000000000000000000deadbeef0000000000000000000000000000000000000000000000000000000000000400
|
||||
.EE
|
||||
|
||||
.SS Build smart contract ERC20 transfer argument types without signature
|
||||
.EX
|
||||
\fBeth-encode\fP --mode arg a:00000000000000000000000000000000DeaDBeef u:1024
|
||||
.TP Output
|
||||
00000000000000000000000000000000000000000000000000000000deadbeef0000000000000000000000000000000000000000000000000000000000000400
|
||||
.EE
|
||||
@@ -1,17 +0,0 @@
|
||||
.TH eth-encode 1
|
||||
|
||||
.SH NAME
|
||||
eth-encode \- Encode arbitrary contract calls and transactions
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBeth-encode\fP [ --mode \fImode\fP ] [ -f \fIformat\fP ] [ -p \fIrpc_provider\fP ] [ -i \fIchain_Spec\fP] [ -s ] [ -w ] [ -e \fIsmart_contract_address\fP ] --signature \fIcontract_method_name\fP [ \fIvalue_specifiers\fP ... ]
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
Generate wire-format or rpc query any EVM smart contract call or transaction by specifying method and arguments.
|
||||
|
||||
The resulting call or transaction can either be stored offline for later use, or directly sent to the network using the \fB-s\fP option.
|
||||
|
||||
A description of value formatting is given in the \fBSPECIFYING VALUES\fP section below. Usage is demonstrated in the \fBEXAMPLES\fP section.
|
||||
|
||||
.SS OPTIONS
|
||||
@@ -1 +0,0 @@
|
||||
mode Mode of operation encoding is for. Must be one of "tx," "call," or "arg." See \fBMODES\fP below. --mode mode
|
||||
@@ -1,75 +0,0 @@
|
||||
.P
|
||||
In the follwing we willconsaider transactions signed by the private key for address Eb3907eCad74a0013c259D5874AE7f22DcBcC95C:
|
||||
|
||||
.SS Offline transaction
|
||||
|
||||
.EX
|
||||
$ eth-gas -y <\fIkey_file_path\fP> -a 00000000000000000000000000000000DeaDBeef --fee-price 100000000000 --fee-limit 21000 --nonce 42 1024
|
||||
from: Eb3907eCad74a0013c259D5874AE7f22DcBcC95C
|
||||
to: 00000000000000000000000000000000DeaDBeef
|
||||
nonce: 42
|
||||
gasPrice: 100000000000 (100 gwei)
|
||||
gas: 21000
|
||||
value: 1024 (0.000000000000001024 eth)
|
||||
data: 0x
|
||||
v: 37
|
||||
recovery_byte: 0
|
||||
r: 0x0c97432d4db724e66a56f7ced04174cf6129e2555709f206dd6d3a156b4af23a
|
||||
s: 0x287862548314a59c7ca6139eee8b51400eb40a67b08b8dc13d67302abecccae0
|
||||
chainId: 1
|
||||
hash: 0x003030af05460633e85b16fff7a17607818dc67e58f89396e5491ad6f5438971
|
||||
hash_unsigned: 0xa59cf9e5438b186de381892b7879ce66476d5469478c7148880da5d553ade651
|
||||
src: 0xf8662a85174876e8008252089400000000000000000000000000000000deadbeef8204008025a00c97432d4db724e66a56f7ced04174cf6129e2555709f206dd6d3a156b4af23aa0287862548314a59c7ca6139eee8b51400eb40a67b08b8dc13d67302abecccae0
|
||||
.EE
|
||||
|
||||
.SS Offline transaction with arbitrary data
|
||||
|
||||
.EX
|
||||
$ eth-gas -y <\fIkey_file_path\fP> -a 00000000000000000000000000000000DeaDBeef --fee-price 100000000000 --fee-limit 21000 --nonce 42 --data 0x2a 1024
|
||||
from: Eb3907eCad74a0013c259D5874AE7f22DcBcC95C
|
||||
to: 00000000000000000000000000000000DeaDBeef
|
||||
nonce: 42
|
||||
gasPrice: 100000000000 (100 gwei)
|
||||
gas: 21000
|
||||
value: 1024 (0.000000000000001024 eth)
|
||||
data: 0x2a
|
||||
v: 37
|
||||
recovery_byte: 0
|
||||
r: 0x800b6982d3f178201d7e7e7693b9c90b3fbcd54d04b6fff5284c81101fad54dd
|
||||
s: 0x3b86d710d31ac74b58f0040b0f51fdb6bdbabea62a68cf99c05e765e7e81de87
|
||||
chainId: 1
|
||||
hash: 0xede30052befd80760c5ab543babdccc3d97fe90523e5710d77220155a82faa47
|
||||
hash_unsigned: 0xad82d8cf1a412541c8a94ef71c50e9172c3a37853af036adee2f55c577da9770
|
||||
src: 0xf8662a85174876e8008252089400000000000000000000000000000000deadbeef8204002a25a0800b6982d3f178201d7e7e7693b9c90b3fbcd54d04b6fff5284c81101fad54dda03b86d710d31ac74b58f0040b0f51fdb6bdbabea62a68cf99c05e765e7e81de87
|
||||
.EE
|
||||
|
||||
.SS Offline transaction with wire-format output
|
||||
|
||||
.EX
|
||||
$ eth-gas -y <\fIkey_file_path\fP> -a 00000000000000000000000000000000DeaDBeef --fee-price 100000000000 --fee-limit 21000 --nonce 42 --raw 1024
|
||||
0xf8662a85174876e8008252089400000000000000000000000000000000deadbeef8204008025a00c97432d4db724e66a56f7ced04174cf6129e2555709f206dd6d3a156b4af23aa0287862548314a59c7ca6139eee8b51400eb40a67b08b8dc13d67302abecccae0
|
||||
.EE
|
||||
|
||||
.SS Sign transaction for a different network
|
||||
|
||||
.EX
|
||||
$ eth-gas -i evm:london:3:rinkeby -y /home/lash/src/contrib/grassrootseconomics/cic-dev/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c -a 00000000000000000000000000000000DeaDBeef --fee-price 100000000000 --fee-limit 21000 --nonce 42 --data 0x2a 1024
|
||||
from: Eb3907eCad74a0013c259D5874AE7f22DcBcC95C
|
||||
to: 00000000000000000000000000000000DeaDBeef
|
||||
nonce: 42
|
||||
gasPrice: 100000000000 (100 gwei)
|
||||
gas: 21000
|
||||
value: 1024 (0.000000000000001024 eth)
|
||||
data: 0x2a
|
||||
v: 41
|
||||
recovery_byte: 0
|
||||
r: 0xe522c25784111a512cbf46f883e3bdacffc2cdbd465fa1042892c28fc10ee054
|
||||
s: 0x5f84eb51a0c9871cfcedaba4e6274b300014899b3a2fec9292de6fe5919bcd07
|
||||
chainId: 3
|
||||
hash: 0x771200a20072294a6a843b89b98d5f868c9aa94da75dacf6a9f5834dfd241199
|
||||
hash_unsigned: 0xa5f9e8a5cda6985d81f4129955b7529f48ecb54728badac16ec550384e3a2bcc
|
||||
src: 0xf8662a85174876e8008252089400000000000000000000000000000000deadbeef8204002a29a0e522c25784111a512cbf46f883e3bdacffc2cdbd465fa1042892c28fc10ee054a05f84eb51a0c9871cfcedaba4e6274b300014899b3a2fec9292de6fe5919bcd07
|
||||
.EE
|
||||
|
||||
.P
|
||||
The wire-format can in turn be decoded using the \fBeth-decode\fP tool)
|
||||
@@ -1,19 +0,0 @@
|
||||
.TH eth-gas 1
|
||||
.SH NAME
|
||||
eth-gas - Create EVM gas token transaction
|
||||
.SH SYNOPSIS
|
||||
.P
|
||||
\fBeth-gas\fP -a RECIPIENT -y KEYFILE [ -p \fIrpc_provider ] [ -s ] [ -u ] AMOUNT
|
||||
.P
|
||||
\fBeth-gas\fP -a RECIPIENT -y KEYFILE [ --fee-price PRICE ] [ --fee-limit LIMIT ] [ --nonce NONCE ] [ -s ] [ -u ] AMOUNT
|
||||
.SH DESCRIPTION
|
||||
\fBeth-gas\fP generates serialized gas token transactions in various output formats.
|
||||
|
||||
If an \fIrpc_provider\fP is available, the valuess \fIfee_price\fP and \fInonce\fP will be automatically retrieved if they are not explicitly specified. If missing values cannot be retrieved, an error will occur.
|
||||
|
||||
Providing all arguments enables fully offline creation of the transaction.
|
||||
|
||||
See \fBEXAMPLES\fP for more details on inputs and outputs.
|
||||
|
||||
|
||||
.SS OPTIONS
|
||||
@@ -1 +0,0 @@
|
||||
a Beneficiary of the gas token transaction.
|
||||
@@ -1,19 +0,0 @@
|
||||
.TH eth-get 1
|
||||
|
||||
.SH NAME
|
||||
eth-get \- Retrieve transaction and transaction state from network
|
||||
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\fBeth-get\fP [ -p \fIrpc_provider\fP] \fItx_hash\fP
|
||||
.PP
|
||||
\fBeth-get\fP [ -p \fIrpc_provider\fP] \fIaddress\fP
|
||||
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
Retrieve a transaction by its transaction hash, or contract code by its address.
|
||||
.P
|
||||
In the context of transaction, \fBeth-get\fP retrieves the state of the transaction (the "receipt") and applies it to the output. It also re-serializes the transaction wire format for reference.
|
||||
|
||||
|
||||
.SS OPTIONS
|
||||
@@ -1,27 +0,0 @@
|
||||
.TH eth-info 1
|
||||
|
||||
.SH NAME
|
||||
eth-info - Return key metrics from the current state of the EVM network.
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBeth-info\fP [ -p \fIrpc_provider\fP ] [ \fIkey\fP ]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBeth-info\fP reports statistics from the current state of the EVM network:
|
||||
|
||||
.EX
|
||||
$ eth-info
|
||||
Block: 1024478
|
||||
Gas price: 1000000000
|
||||
.EE
|
||||
|
||||
An individual data item may be specified using the \fIkey\fP positional argument:
|
||||
|
||||
.EX
|
||||
$ eth-info block
|
||||
Block: 1024478
|
||||
$ eth-info --raw gas_price
|
||||
1000000000
|
||||
.EE
|
||||
|
||||
.SS OPTIONS
|
||||
@@ -1,8 +0,0 @@
|
||||
.SH EXAMPLES
|
||||
|
||||
Outputs of \fBeth-gas\fP and \fBeth-encode\fP map directly to inputs for \fBeth-raw\fP.
|
||||
|
||||
.SS Encapsulate a gas transaction
|
||||
|
||||
.EX
|
||||
$ eth-gas -y <\fIkey_file_path\fP> -a 00000000000000000000000000000000DeaDBeef --fee-price 100000000000 --fee-limit 21000 --nonce 42 --raw 1024 | eth-raw
|
||||
@@ -1,26 +0,0 @@
|
||||
.TH eth-raw 1
|
||||
|
||||
.SH NAME
|
||||
eth-raw \- Create and send a jsonrpc transaction from signed rlp transaction
|
||||
|
||||
.SH SYNOPSIS
|
||||
.P
|
||||
\fBeth-raw\fP [ --deploy ] \fItransaction_data\fP
|
||||
.P
|
||||
\fBeth-raw\fP [ -p \fIrpc_provider\fP ] [ --deploy ] -s \fItransaction_data\fP
|
||||
|
||||
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
Creates a jsonrpc object from serialized data.
|
||||
.P
|
||||
If \fB-y\fP is defined, and \fB--mode\fP is not set, or set to "tx", a \fIeth_sendRawTransaction\fP object will be created.
|
||||
.P
|
||||
Otherwise, an \fIeth_call\fP object will be created. The recipient of the call will be the contract specified with \fB-e\fP. If \fB-y\fP has been set, the sender of the query will be the address corresponding to the key file.
|
||||
.P
|
||||
If the \fB-s\fP option is added, the jsonrpc object will be sent to the rpc provider. \fBNote\fP If the jsonrpc object is a transaction, this may incur real costs.
|
||||
.P
|
||||
See the \fBEXAMPLES\fP section for details on how to use \fBeth-raw\fP with the outputs from \fBeth-gas\fP and \fBeth-encode\fP
|
||||
|
||||
|
||||
.SS OPTIONS
|
||||
@@ -1,4 +0,0 @@
|
||||
.SH SEE ALSO
|
||||
|
||||
.BP
|
||||
confini-dump(1), eth-keyfile(1), eth-encode(1), eth-gas(1)
|
||||
@@ -1,17 +0,0 @@
|
||||
.TH eth-wait 1
|
||||
|
||||
.SH NAE
|
||||
eth-wait \- Wait for a transaction to be confirmed on network
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBeth-wait\fP [ -p \fIrpc_provider\fP ] \fItransaction_hash\fP ...
|
||||
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
Blocks until network confirmation for the transactions are returned from \fIrpc_provider\fP.
|
||||
.P
|
||||
By default, if execution of the transaction failed on the network, the command will cause an error. This behavior can be adjusted using the \fB--ignore\fP or \fB--ignore-all\fP option.
|
||||
.P
|
||||
A transaction hash unknown to the \fIrpc_provider\fP will also cause an error.
|
||||
|
||||
.SS OPTIONS
|
||||
@@ -1,2 +0,0 @@
|
||||
ignore Ignore error from the specified transaction. May be defined more than once. --ignore tx_hash
|
||||
ignoreall Ignore errors from all transactions. --ignore-all
|
||||
@@ -1,6 +1,7 @@
|
||||
funga-eth~=0.6.1
|
||||
funga-eth>=0.5.0a1,<0.6.0
|
||||
pysha3==1.0.2
|
||||
hexathon~=0.1.7
|
||||
hexathon~=0.0.1a8
|
||||
websocket-client==0.57.0
|
||||
potaahto~=0.1.1
|
||||
chainlib~=0.3.0
|
||||
potaahto~=0.0.1a1
|
||||
chainlib==0.0.10a1
|
||||
confini>=0.4.1a1,<0.5.0
|
||||
|
||||
13
setup.cfg
13
setup.cfg
@@ -1,10 +1,10 @@
|
||||
[metadata]
|
||||
name = chainlib-eth
|
||||
version = 0.3.0
|
||||
version = 0.0.10a2
|
||||
description = Ethereum implementation of the chainlib interface
|
||||
author = Louis Holbrook
|
||||
author_email = dev@holbrook.no
|
||||
url = https://gitlab.com/chaintool/chainlib-eth
|
||||
url = https://gitlab.com/chaintools/chainlib
|
||||
keywords =
|
||||
dlt
|
||||
blockchain
|
||||
@@ -14,7 +14,6 @@ classifiers =
|
||||
Programming Language :: Python :: 3
|
||||
Operating System :: OS Independent
|
||||
Development Status :: 3 - Alpha
|
||||
Topic :: Software Development :: Libraries
|
||||
Environment :: Console
|
||||
Intended Audience :: Developers
|
||||
License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
||||
@@ -26,26 +25,22 @@ licence_files =
|
||||
|
||||
[options]
|
||||
include_package_data = True
|
||||
python_requires = >= 3.7
|
||||
python_requires = >= 3.6
|
||||
packages =
|
||||
chainlib.eth
|
||||
chainlib.eth.dialect
|
||||
chainlib.eth.runnable
|
||||
chainlib.eth.pytest
|
||||
chainlib.eth.unittest
|
||||
chainlib.eth.cli
|
||||
|
||||
[options.entry_points]
|
||||
console_scripts =
|
||||
eth-count = chainlib.eth.runnable.count:main
|
||||
eth-balance = chainlib.eth.runnable.balance:main
|
||||
eth-checksum = chainlib.eth.runnable.checksum:main
|
||||
eth-gas = chainlib.eth.runnable.gas:main
|
||||
eth-raw = chainlib.eth.runnable.raw:main
|
||||
eth-get = chainlib.eth.runnable.get:main
|
||||
eth-decode = chainlib.eth.runnable.decode:main
|
||||
eth-encode = chainlib.eth.runnable.encode:main
|
||||
eth-info = chainlib.eth.runnable.info:main
|
||||
eth-nonce = chainlib.eth.runnable.count:main
|
||||
eth-wait = chainlib.eth.runnable.wait:main
|
||||
eth-block = chainlib.eth.runnable.block:main
|
||||
eth = chainlib.eth.runnable.info:main
|
||||
|
||||
@@ -2,4 +2,3 @@ eth_tester==0.5.0b3
|
||||
py-evm==0.3.0a20
|
||||
rlp==2.0.1
|
||||
pytest==6.0.1
|
||||
coverage==5.5
|
||||
|
||||
@@ -12,7 +12,7 @@ from tests.base import TestBase
|
||||
class TestChain(TestBase):
|
||||
|
||||
def test_chain_spec(self):
|
||||
checksum_address = 'Eb3907eCad74a0013c259D5874AE7f22DcBcC95C'
|
||||
checksum_address = '0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C'
|
||||
plain_address = checksum_address.lower()
|
||||
|
||||
self.assertEqual(checksum_address, to_checksum(checksum_address))
|
||||
|
||||
@@ -1,67 +1,12 @@
|
||||
# standard imports
|
||||
import unittest
|
||||
import os
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
# local imports
|
||||
from chainlib.eth.jsonrpc import to_blockheight_param
|
||||
from chainlib.eth.block import Block
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
|
||||
class TestBlock(unittest.TestCase):
|
||||
|
||||
|
||||
def test_block(self):
|
||||
tx_one_src = {
|
||||
'hash': os.urandom(32).hex(),
|
||||
'from': os.urandom(20).hex(),
|
||||
'to': os.urandom(20).hex(),
|
||||
'value': 13,
|
||||
'data': '0xdeadbeef',
|
||||
'nonce': 666,
|
||||
'gasPrice': 100,
|
||||
'gas': 21000,
|
||||
}
|
||||
|
||||
tx_two_src_hash = os.urandom(32).hex()
|
||||
|
||||
block_hash = os.urandom(32).hex()
|
||||
parent_hash = os.urandom(32).hex()
|
||||
block_author = os.urandom(20).hex()
|
||||
block_time = datetime.datetime.utcnow().timestamp()
|
||||
block_src = {
|
||||
'number': 42,
|
||||
'hash': block_hash,
|
||||
'author': block_author,
|
||||
'transactions': [
|
||||
tx_one_src,
|
||||
tx_two_src_hash,
|
||||
],
|
||||
'timestamp': block_time,
|
||||
'gas_used': '0x1234',
|
||||
'gas_limit': '0x2345',
|
||||
'parent_hash': parent_hash
|
||||
}
|
||||
block = Block(block_src)
|
||||
|
||||
self.assertEqual(block.number, 42)
|
||||
self.assertEqual(block.hash, block_hash)
|
||||
self.assertEqual(block.author, block_author)
|
||||
self.assertEqual(block.timestamp, int(block_time))
|
||||
|
||||
tx_index = block.tx_index_by_hash(tx_one_src['hash'])
|
||||
self.assertEqual(tx_index, 0)
|
||||
|
||||
tx_retrieved = block.tx_by_index(tx_index)
|
||||
self.assertEqual(tx_retrieved.hash, tx_one_src['hash'])
|
||||
|
||||
tx_index = block.tx_index_by_hash(tx_two_src_hash)
|
||||
self.assertEqual(tx_index, 1)
|
||||
|
||||
|
||||
def test_blockheight_param(self):
|
||||
self.assertEqual(to_blockheight_param('latest'), 'latest')
|
||||
self.assertEqual(to_blockheight_param(0), 'latest')
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# standard imports
|
||||
import unittest
|
||||
import os
|
||||
import logging
|
||||
|
||||
# external imports
|
||||
from aiee.arg import process_args
|
||||
|
||||
# local imports
|
||||
#from chainlib.cli.base import argflag_std_base
|
||||
from chainlib.eth.cli.arg import (
|
||||
ArgFlag,
|
||||
Arg,
|
||||
ArgumentParser,
|
||||
)
|
||||
from chainlib.eth.cli.config import (
|
||||
Config,
|
||||
process_config,
|
||||
)
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
data_dir = os.path.join(script_dir, 'testdata')
|
||||
config_dir = os.path.join(data_dir, 'config')
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
|
||||
class TestCli(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.flags = ArgFlag()
|
||||
self.arg = Arg(self.flags)
|
||||
|
||||
|
||||
def test_args_process_single(self):
|
||||
ap = ArgumentParser()
|
||||
flags = self.flags.VERBOSE | self.flags.CONFIG
|
||||
process_args(ap, self.arg, flags)
|
||||
|
||||
argv = [
|
||||
'-vv',
|
||||
'-n',
|
||||
'foo',
|
||||
]
|
||||
args = ap.parse_args(argv)
|
||||
config = Config(config_dir)
|
||||
config = process_config(config, self.arg, args, flags)
|
||||
self.assertEqual(config.get('CONFIG_USER_NAMESPACE'), 'foo')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -7,19 +7,16 @@ import logging
|
||||
import json
|
||||
|
||||
# external imports
|
||||
from funga.eth.transaction import EIP155Transaction
|
||||
from funga.eth.signer.defaultsigner import EIP155Signer
|
||||
from funga.eth.keystore.dict import DictKeystore
|
||||
from crypto_dev_signer.eth.transaction import EIP155Transaction
|
||||
from crypto_dev_signer.eth.signer.defaultsigner import ReferenceSigner
|
||||
from crypto_dev_signer.keystore.dict import DictKeystore
|
||||
|
||||
# local imports
|
||||
import chainlib
|
||||
from chainlib.eth.connection import EthUnixSignerConnection
|
||||
from chainlib.eth.sign import sign_transaction
|
||||
from chainlib.eth.tx import TxFactory
|
||||
from chainlib.eth.address import (
|
||||
to_checksum_address,
|
||||
is_same_address,
|
||||
)
|
||||
from chainlib.eth.address import to_checksum_address
|
||||
from chainlib.jsonrpc import (
|
||||
jsonrpc_response,
|
||||
jsonrpc_error,
|
||||
@@ -55,13 +52,11 @@ class Mocket(socket.socket):
|
||||
logg.debug('mocket received {}'.format(v))
|
||||
Mocket.req_id = o['id']
|
||||
params = o['params'][0]
|
||||
from_address = to_checksum_address(params.get('from'))
|
||||
if not is_same_address(alice, from_address):
|
||||
logg.error('from {} does not match alice {}'.format(from_address, alice)) #params))
|
||||
if to_checksum_address(params.get('from')) != alice:
|
||||
logg.error('from does not match alice {}'.format(params))
|
||||
Mocket.error = True
|
||||
to_address = to_checksum_address(params.get('to'))
|
||||
if not is_same_address(bob, to_address):
|
||||
logg.error('to {} does not match bob {}'.format(to_address, bob)) #params))
|
||||
if to_checksum_address(params.get('to')) != bob:
|
||||
logg.error('to does not match bob {}'.format(params))
|
||||
Mocket.error = True
|
||||
if not Mocket.error:
|
||||
Mocket.tx = EIP155Transaction(params, params['nonce'], params['chainId'])
|
||||
@@ -97,7 +92,7 @@ class TestSign(TestBase):
|
||||
logg.debug('alice {}'.format(alice))
|
||||
logg.debug('bob {}'.format(bob))
|
||||
|
||||
self.signer = EIP155Signer(keystore)
|
||||
self.signer = ReferenceSigner(keystore)
|
||||
|
||||
Mocket.signer = self.signer
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# standard imports
|
||||
import unittest
|
||||
import datetime
|
||||
import os
|
||||
|
||||
# external imports
|
||||
from chainlib.stat import ChainStat
|
||||
@@ -20,10 +19,6 @@ class TestStat(unittest.TestCase):
|
||||
'hash': None,
|
||||
'transactions': [],
|
||||
'number': 41,
|
||||
'author': os.urandom(20).hex(),
|
||||
'gas_used': '0x1234',
|
||||
'gas_limit': '0x2345',
|
||||
'parent_hash': None,
|
||||
})
|
||||
|
||||
d = datetime.datetime.utcnow()
|
||||
@@ -32,10 +27,6 @@ class TestStat(unittest.TestCase):
|
||||
'hash': None,
|
||||
'transactions': [],
|
||||
'number': 42,
|
||||
'author': os.urandom(20).hex(),
|
||||
'gas_used': '0x1234',
|
||||
'gas_limit': '0x2345',
|
||||
'parent_hash': None,
|
||||
})
|
||||
|
||||
s.block_apply(block_a)
|
||||
@@ -48,10 +39,6 @@ class TestStat(unittest.TestCase):
|
||||
'hash': None,
|
||||
'transactions': [],
|
||||
'number': 43,
|
||||
'author': os.urandom(20).hex(),
|
||||
'gas_used': '0x1234',
|
||||
'gas_limit': '0x2345',
|
||||
'parent_hash': None,
|
||||
})
|
||||
|
||||
s.block_apply(block_c)
|
||||
|
||||
@@ -23,14 +23,10 @@ from chainlib.eth.contract import (
|
||||
ABIContractEncoder,
|
||||
ABIContractType,
|
||||
)
|
||||
from chainlib.eth.address import (
|
||||
to_checksum_address,
|
||||
is_same_address,
|
||||
)
|
||||
from chainlib.eth.address import to_checksum_address
|
||||
from hexathon import (
|
||||
strip_0x,
|
||||
add_0x,
|
||||
same as hex_same,
|
||||
)
|
||||
from chainlib.eth.block import Block
|
||||
|
||||
@@ -40,27 +36,6 @@ logg = logging.getLogger()
|
||||
|
||||
class TxTestCase(EthTesterCase):
|
||||
|
||||
def test_tx_basic(self):
|
||||
tx_src = {
|
||||
'hash': os.urandom(32).hex(),
|
||||
'from': os.urandom(20).hex(),
|
||||
'to': os.urandom(20).hex(),
|
||||
'value': 13,
|
||||
'data': '0xdeadbeef',
|
||||
'nonce': 666,
|
||||
'gasPrice': 100,
|
||||
'gas': 21000,
|
||||
}
|
||||
|
||||
tx = Tx(tx_src)
|
||||
|
||||
self.assertEqual(tx.hash, tx_src['hash'])
|
||||
self.assertTrue(is_same_address(tx.outputs[0], tx_src['from']))
|
||||
self.assertTrue(is_same_address(tx.inputs[0], tx_src['to']))
|
||||
self.assertEqual(tx.value, tx_src['value'])
|
||||
self.assertEqual(tx.nonce, tx_src['nonce'])
|
||||
self.assertTrue(hex_same(tx.payload, tx_src['data']))
|
||||
|
||||
|
||||
def test_tx_reciprocal(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
@@ -68,21 +43,8 @@ class TxTestCase(EthTesterCase):
|
||||
c = Gas(signer=self.signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle, chain_spec=self.chain_spec)
|
||||
(tx_hash_hex, o) = c.create(self.accounts[0], self.accounts[1], 1024, tx_format=TxFormat.RLP_SIGNED)
|
||||
tx = unpack(bytes.fromhex(strip_0x(o)), self.chain_spec)
|
||||
self.assertTrue(is_same_address(tx['from'], self.accounts[0]))
|
||||
self.assertTrue(is_same_address(tx['to'], self.accounts[1]))
|
||||
|
||||
|
||||
def test_tx_repack(self):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||
gas_oracle = RPCGasOracle(self.rpc)
|
||||
c = Gas(signer=self.signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle, chain_spec=self.chain_spec)
|
||||
(tx_hash_hex, o) = c.create(self.accounts[0], self.accounts[1], 1024)
|
||||
self.rpc.do(o)
|
||||
|
||||
o = transaction(tx_hash_hex)
|
||||
tx_src = self.rpc.do(o)
|
||||
tx = Tx(tx_src)
|
||||
tx_bin = pack(tx.src, self.chain_spec)
|
||||
self.assertEqual(tx['from'], self.accounts[0])
|
||||
self.assertEqual(tx['to'], self.accounts[1])
|
||||
|
||||
|
||||
def test_tx_pack(self):
|
||||
@@ -129,10 +91,6 @@ class TxTestCase(EthTesterCase):
|
||||
'number': 42,
|
||||
'timestamp': 13241324,
|
||||
'transactions': [],
|
||||
'author': os.urandom(20).hex(),
|
||||
'gas_used': 21000,
|
||||
'gas_limit': '0x2345',
|
||||
'parent_hash': None,
|
||||
})
|
||||
with self.assertRaises(AttributeError):
|
||||
tx = Tx(tx_data, block=block)
|
||||
@@ -175,12 +133,7 @@ class TxTestCase(EthTesterCase):
|
||||
'number': 42,
|
||||
'timestamp': 13241324,
|
||||
'transactions': [],
|
||||
'author': os.urandom(20).hex(),
|
||||
'gas_used': 21000,
|
||||
'gas_limit': '0x2345',
|
||||
'parent_hash': None,
|
||||
})
|
||||
|
||||
block.txs = [add_0x(tx_data['hash'])]
|
||||
with self.assertRaises(ValueError):
|
||||
tx = Tx(tx_data, rcpt=rcpt, block=block)
|
||||
|
||||
Reference in New Issue
Block a user