Compare commits

..

63 Commits

Author SHA1 Message Date
lash
a71b3d6388
Add changelog detail 2022-04-26 21:36:44 +00:00
lash
2dd92fe74b
Add fee limit, fee price to Tx object 2022-04-19 19:46:11 +00:00
lash
129e25bbf5
Bump chainlib dep 2022-04-10 19:05:58 +00:00
lash
a76020b13b
Add dict output 2022-04-10 19:04:50 +00:00
lash
3cfeb9ce84
Upgrade deps 2022-03-06 19:33:09 +00:00
lash
601db731d9
Handle int instead of hex signature values in pack from eth_tester 2022-03-01 14:43:43 +00:00
lash
c954f4d1b4
Allow encode without nonce when not tx, add rcpt src to tx 2022-03-01 07:50:30 +00:00
lash
b59eebe181
Add remaining man pages 2022-02-25 11:07:40 +00:00
lash
2f906037a9
Add more detail on examples 2022-02-24 20:05:38 +00:00
lash
1362c9aac6
WIP add eth-encode overrides 2022-02-24 19:00:54 +00:00
lash
e5e8680fc6
Improve eth-encode interface with --format and --mode options 2022-02-24 15:51:38 +00:00
lash
90d4c4eb95
Add man page for eth-encode 2022-02-24 12:07:56 +00:00
lash
edf8c4b604
Add chain spec example for eth-gas 2022-02-24 11:40:35 +00:00
lash
f61ac91205
Auto-apply overrides and examples if they exist, add examples for eth-gas 2022-02-24 11:32:33 +00:00
lash
7e6daa0be3
Add get man page, remove chain spec arg from get, info 2022-02-24 10:36:15 +00:00
lash
a3081367db
Add makefile for man 2022-02-23 13:16:04 +00:00
lash
d49e3dd6ec
Add environment description override 2022-02-23 09:47:03 +00:00
lash
d3f2b1f1fa
WIP add enviornment support 2022-02-22 14:47:06 +00:00
lash
79a1123dc8
Upgrade chainlib, allow passphrase file for wallet key 2022-02-20 18:27:51 +00:00
lash
5c09630b6e
Skip buggy hexathon 2022-02-14 13:57:37 +00:00
lash
e9f31ed7f1
Make block by number compatible with geth 2022-02-12 12:30:52 +00:00
lash
7f2c32975d
Enable unpack of pre EIP155 txs 2022-01-23 20:36:29 +00:00
lash
109666ba1d
Bump version to eliminate rlp cytoolz warnings 2022-01-21 11:22:26 +00:00
lash
8ac349f092 Revert "Bring in loglevel changes in chainlib, bump version"
This reverts commit 677b742690.
2022-01-21 00:15:33 +00:00
lash
677b742690
Bring in loglevel changes in chainlib, bump version 2022-01-21 00:14:31 +00:00
lash
96a0f3beb0
Skip compulsory exec address for offline encode, add wait to raw 2022-01-09 12:09:23 +00:00
nolash
1fbd94d382
Remove padding in hex values in encode cli command 2022-01-07 12:53:27 +00:00
nolash
1a73c0d1ed
Bump version 2022-01-07 12:27:20 +00:00
nolash
e9b7d27670
Add raw output to notx/nosign encode (args only) 2022-01-07 12:27:02 +00:00
nolash
f688cba5cc
Re-bump chainlib 2022-01-04 17:14:56 +00:00
nolash
700e668a4b
Bump chainlib 2022-01-04 17:09:49 +00:00
nolash
7832071512 Merge branch 'lash/funga' 2021-12-21 14:52:35 +00:00
nolash
f618a5c9d7
Add missing rpc verify config directive 2021-12-21 14:50:38 +00:00
nolash
6bc0caaad7
Correct inverted addess checksum check for gas cli 2021-12-10 02:35:38 +01:00
nolash
2ef596df86
Upgrade chainlib and self 2021-12-06 19:03:08 +01:00
nolash
bfbb1dea26
Add raw args option 2021-12-06 19:00:55 +01:00
nolash
6474a2399a
Enable call when wallet set for encode cli command 2021-11-15 14:29:40 +01:00
nolash
d3c73c7e5b
Upgrade deps. commit patch version 2021-11-10 09:59:36 +01:00
nolash
80e5339886
Fix wrong symbol for rpc call in eth-encode 2021-11-04 12:20:42 +01:00
nolash
53cea0817e
Fix remaining 0x problems 2021-10-30 16:49:47 +02:00
nolash
5f9634d5a4
Upgrade chainlib 2021-10-28 12:17:32 +02:00
nolash
6ee3ea4638
Handle null-value block hashes on receipts 2021-10-25 11:25:03 +02:00
nolash
31e75f60de
Fix missing conflict resolution in eth-encode, non-0x address fallthrough in eth-info 2021-10-25 09:57:31 +02:00
nolash
b51e5dc408
Bump chainlib 2021-10-21 07:28:00 +02:00
nolash
8c23535ffe
Add wait for hashes script 2021-10-19 19:40:53 +02:00
nolash
6cadad372f
Upgrade deps 2021-10-18 14:27:40 +02:00
nolash
47b7fa7eef
Replace crypto_dev_signer with funga 2021-10-18 14:23:54 +02:00
nolash
5cfb6a7dda
Rehabilitate tests 2021-10-18 14:04:49 +02:00
nolash
2204c512c3
Rehabilitate tests 2021-10-18 13:57:42 +02:00
nolash
c66f5fdff9 Merge branch 'master' into 0.0.10-dev 2021-10-18 13:32:11 +02:00
nolash
700c52089e Merge branch 'master' of file:///home/lash/src/client/cic/grassrootseconomics/chainlib-eth 2021-10-18 13:31:18 +02:00
nolash
76c8ff58fc Merge branch 'lash/cli-encode' 2021-10-18 13:30:06 +02:00
nolash
d6b258f214 Merge remote-tracking branch 'origin/master' into lash/schmerge 2021-10-18 12:52:26 +02:00
Louis Holbrook
91d748d09f Merge branch 'lash/gas-checksum-cli' into 'master'
bug: Correct rpc format for gas cli request

See merge request chaintool/chainlib-eth!10
2021-10-18 10:49:40 +00:00
Louis Holbrook
a188c4e6bb bug: Correct rpc format for gas cli request 2021-10-18 10:49:40 +00:00
Louis Holbrook
778994e07e Merge branch 'lash/cli-encode' into 'master'
feat: Add generic contract tx/call encoder cli tool

See merge request chaintool/chainlib-eth!6
2021-10-18 10:18:21 +00:00
Louis Holbrook
94e016366b feat: Add generic contract tx/call encoder cli tool 2021-10-18 10:18:20 +00:00
Louis Holbrook
2011ce8bb8 Merge branch 'lash/normalize-verify-sig' into 'master'
refactor: Normalize signature verification

See merge request chaintool/chainlib-eth!9
2021-10-18 10:07:03 +00:00
Louis Holbrook
ab8c510fa0 refactor: Normalize signature verification 2021-10-18 10:07:03 +00:00
nolash
ee6c97f581
Add tx wait method to test rpc 2021-10-11 21:12:59 +02:00
nolash
14ccb8d375
Bump version and deps 2021-10-10 12:18:11 +02:00
nolash
1c021fae2a
Bump version 2021-10-07 16:55:51 +02:00
nolash
46fecaf8c8
Add normalize tx in verify sig unittest 2021-10-07 16:55:23 +02:00
54 changed files with 843 additions and 122 deletions

View File

@ -1,3 +1,26 @@
- 0.0.5-pending - 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:
* Receive all ethereum components from chainlib package * Receive all ethereum components from chainlib package
* Make settings configurable * Make settings configurable

16
Makefile Normal file
View File

@ -0,0 +1,16 @@
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

View File

@ -4,7 +4,7 @@ from hexathon import (
strip_0x, strip_0x,
uniform, uniform,
) )
from crypto_dev_signer.encoding import ( from funga.eth.encoding import (
is_address, is_address,
is_checksum_address, is_checksum_address,
to_checksum_address, to_checksum_address,
@ -42,3 +42,7 @@ class AddressChecksum:
:returns: Checksum address :returns: Checksum address
""" """
return to_checksum_address(v) return to_checksum_address(v)
def is_same_address(a, b):
return uniform(strip_0x(a)) == uniform(strip_0x(b))

View File

@ -1,10 +1,11 @@
import sys
# external imports # external imports
from chainlib.jsonrpc import JSONRPCRequest from chainlib.jsonrpc import JSONRPCRequest
from chainlib.block import Block as BaseBlock from chainlib.block import Block as BaseBlock
from hexathon import ( from hexathon import (
add_0x, add_0x,
strip_0x, strip_0x,
even, compact,
) )
# local imports # local imports
@ -34,7 +35,8 @@ def block_by_hash(hsh, include_tx=True, id_generator=None):
def block_by_number(n, include_tx=True, id_generator=None): def block_by_number(n, include_tx=True, id_generator=None):
"""Implements chainlib.interface.ChainInterface method """Implements chainlib.interface.ChainInterface method
""" """
nhx = add_0x(even(hex(n)[2:])) hx = strip_0x(hex(n))
nhx = add_0x(compact(hx), compact_value=True)
j = JSONRPCRequest(id_generator) j = JSONRPCRequest(id_generator)
o = j.template() o = j.template()
o['method'] = 'eth_getBlockByNumber' o['method'] = 'eth_getBlockByNumber'
@ -60,6 +62,20 @@ def transaction_count(block_hash, id_generator=None):
return j.finalize(o) 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): class Block(BaseBlock):
"""Encapsulates an Ethereum block """Encapsulates an Ethereum block

View File

@ -4,6 +4,7 @@ from chainlib.cli import (
argflag_std_read, argflag_std_read,
argflag_std_write, argflag_std_write,
argflag_std_base, argflag_std_base,
reset as argflag_reset, argflag_std_base_read,
flag_reset as argflag_reset,
Flag, Flag,
) )

View File

@ -16,10 +16,12 @@ class CLIEncoder(ABIContractEncoder):
__re_uint = r'^([uU])[int]*([0-9]+)?$' __re_uint = r'^([uU])[int]*([0-9]+)?$'
__re_bytes = r'^([bB])[ytes]*([0-9]+)?$' __re_bytes = r'^([bB])[ytes]*([0-9]+)?$'
__re_string = r'^([sS])[tring]*$' __re_string = r'^([sS])[tring]*$'
__re_address = r'^([aA])[ddress]*?$'
__translations = [ __translations = [
'to_uint', 'to_uint',
'to_bytes', 'to_bytes',
'to_string', 'to_string',
'to_address',
] ]
def __init__(self, signature=None): def __init__(self, signature=None):
@ -58,6 +60,18 @@ class CLIEncoder(ABIContractEncoder):
return (s, a) 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): def to_string(self, typ):
m = re.match(self.__re_string, typ) m = re.match(self.__re_string, typ)
if m == None: if m == None:

View File

@ -13,6 +13,7 @@ from chainlib.eth.nonce import (
) )
# TODO: how is the keystore implemented in rpc here?
class Rpc(BaseRpc): class Rpc(BaseRpc):
"""Convenience constructor to set Ethereum defaults for chainlib cli Rpc object """Convenience constructor to set Ethereum defaults for chainlib cli Rpc object

View File

@ -1,5 +1,6 @@
# external imports # external imports
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer from funga.eth.signer import EIP155Signer
from funga.eth.keystore.dict import DictKeystore
from chainlib.cli import Wallet as BaseWallet from chainlib.cli import Wallet as BaseWallet
# local imports # local imports
@ -13,7 +14,7 @@ class Wallet(BaseWallet):
:type checksummer: Implementation of chainlib.eth.address.AddressChecksum :type checksummer: Implementation of chainlib.eth.address.AddressChecksum
""" """
def __init__(self, checksummer=AddressChecksum): def __init__(self, checksummer=AddressChecksum):
super(Wallet, self).__init__(EIP155Signer, checksummer=checksummer) super(Wallet, self).__init__(EIP155Signer, checksummer=checksummer, keystore=DictKeystore())

View File

@ -36,6 +36,7 @@ from chainlib.jsonrpc import (
from chainlib.eth.tx import ( from chainlib.eth.tx import (
unpack, unpack,
) )
from potaahto.symbols import snake_and_camel
logg = logging.getLogger(__name__) logg = logging.getLogger(__name__)
@ -88,7 +89,12 @@ class EthHTTPConnection(JSONRPCHTTPConnection):
e = jsonrpc_result(r, error_parser) e = jsonrpc_result(r, error_parser)
if e != None: if e != None:
logg.debug('({}) poll receipt completed {}'.format(str(self), r)) 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']))) logg.debug('e {}'.format(strip_0x(e['status'])))
if strip_0x(e['status']) == '00': if strip_0x(e['status']) == '00':
raise RevertEthException(tx_hash_hex) raise RevertEthException(tx_hash_hex)

View File

@ -1,13 +1,13 @@
[rpc] [rpc]
http_provider = http://localhost:8545
provider = http://localhost:8545 provider = http://localhost:8545
auth = auth =
credentials = credentials =
dialect = default dialect = default
scheme = http scheme = http
verify = 1
[chain] [chain]
spec = evm:ethereum:1 spec = evm:berlin:1:ethereum
[wallet] [wallet]
key_file = key_file =

2
chainlib/eth/data/env/env.ini vendored Normal file
View File

@ -0,0 +1,2 @@
[rpc]
provider = Fully-qualified URL to EVM node's RPC endpoint.

View File

@ -6,7 +6,7 @@ from hexathon import (
add_0x, add_0x,
strip_0x, strip_0x,
) )
from crypto_dev_signer.eth.transaction import EIP155Transaction from funga.eth.transaction import EIP155Transaction
# local imports # local imports
from chainlib.fee import FeeOracle from chainlib.fee import FeeOracle
@ -55,7 +55,7 @@ def balance(address, id_generator=None, height=BlockSpec.LATEST):
j = JSONRPCRequest(id_generator) j = JSONRPCRequest(id_generator)
o = j.template() o = j.template()
o['method'] = 'eth_getBalance' o['method'] = 'eth_getBalance'
o['params'].append(address) o['params'].append(add_0x(address))
height = to_blockheight_param(height) height = to_blockheight_param(height)
o['params'].append(height) o['params'].append(height)
return j.finalize(o) return j.finalize(o)

View File

@ -44,7 +44,7 @@ class NonceOracle(BaseNonceOracle):
""" """
def __init__(self, address, id_generator=None): def __init__(self, address, id_generator=None):
self.id_generator = id_generator self.id_generator = id_generator
super(NonceOracle, self).__init__(address) super(NonceOracle, self).__init__(add_0x(address))
def get_nonce(self): def get_nonce(self):

View File

@ -5,8 +5,8 @@ import logging
# external imports # external imports
import eth_tester import eth_tester
import pytest import pytest
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer from funga.eth.signer import EIP155Signer
from crypto_dev_signer.keystore.dict import DictKeystore from funga.eth.keystore.dict import DictKeystore
# local imports # local imports
from chainlib.eth.unittest.base import * from chainlib.eth.unittest.base import *

View File

@ -3,7 +3,6 @@
# external imports # external imports
import pytest import pytest
#from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
@pytest.fixture(scope='function') @pytest.fixture(scope='function')

View File

@ -24,7 +24,7 @@ from chainlib.eth.gas import (
balance, balance,
) )
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer from funga.eth.signer import EIP155Signer
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger() logg = logging.getLogger()

View File

@ -15,8 +15,8 @@ from chainlib.eth.connection import EthHTTPConnection
from chainlib.eth.tx import count from chainlib.eth.tx import count
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from chainlib.jsonrpc import IntSequenceGenerator from chainlib.jsonrpc import IntSequenceGenerator
from crypto_dev_signer.keystore.dict import DictKeystore from funga.eth.keystore.dict import DictKeystore
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer from funga.eth.signer import EIP155Signer
from hexathon import add_0x from hexathon import add_0x
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
@ -25,7 +25,7 @@ logg = logging.getLogger()
script_dir = os.path.dirname(os.path.realpath(__file__)) script_dir = os.path.dirname(os.path.realpath(__file__))
config_dir = os.path.join(script_dir, '..', 'data', 'config') config_dir = os.path.join(script_dir, '..', 'data', 'config')
arg_flags = chainlib.eth.cli.argflag_std_read arg_flags = chainlib.eth.cli.argflag_std_base_read | chainlib.eth.cli.Flag.WALLET
argparser = chainlib.eth.cli.ArgumentParser(arg_flags) argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
argparser.add_positional('address', type=str, help='Ethereum address of recipient') argparser.add_positional('address', type=str, help='Ethereum address of recipient')
args = argparser.parse_args() args = argparser.parse_args()
@ -43,7 +43,7 @@ conn = rpc.connect_by_config(config)
def main(): def main():
# TODO: should tolerate if address not prefixed with 0x # TODO: should tolerate if address not prefixed with 0x
o = count(holder_address, id_generator=rpc.id_generator) o = count(add_0x(holder_address), id_generator=rpc.id_generator)
r = conn.do(o) r = conn.do(o)
count_result = None count_result = None
try: try:

View File

@ -11,16 +11,17 @@ import urllib
import sha3 import sha3
# external imports # external imports
import chainlib.eth.cli from chainlib.cli import flag_reset
from chainlib.eth.cli.encode import CLIEncoder from funga.eth.signer import EIP155Signer
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer from funga.eth.keystore.dict import DictKeystore
from crypto_dev_signer.keystore.dict import DictKeystore
from hexathon import ( from hexathon import (
add_0x, add_0x,
strip_0x, strip_0x,
) )
# local imports # local imports
import chainlib.eth.cli
from chainlib.eth.cli.encode import CLIEncoder
from chainlib.eth.constant import ZERO_ADDRESS from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.eth.address import to_checksum from chainlib.eth.address import to_checksum
from chainlib.eth.connection import EthHTTPConnection from chainlib.eth.connection import EthHTTPConnection
@ -28,14 +29,6 @@ from chainlib.jsonrpc import (
JSONRPCRequest, JSONRPCRequest,
IntSequenceGenerator, IntSequenceGenerator,
) )
from chainlib.eth.nonce import (
RPCNonceOracle,
OverrideNonceOracle,
)
from chainlib.eth.gas import (
RPCGasOracle,
OverrideGasOracle,
)
from chainlib.eth.tx import ( from chainlib.eth.tx import (
TxFactory, TxFactory,
TxFormat, TxFormat,
@ -53,8 +46,11 @@ logg = logging.getLogger()
script_dir = os.path.dirname(os.path.realpath(__file__)) script_dir = os.path.dirname(os.path.realpath(__file__))
config_dir = os.path.join(script_dir, '..', 'data', 'config') config_dir = os.path.join(script_dir, '..', 'data', 'config')
arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC
arg_flags = 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
arg_flags = flag_reset(arg_flags, chainlib.cli.Flag.NO_TARGET)
argparser = chainlib.eth.cli.ArgumentParser(arg_flags) argparser = chainlib.eth.cli.ArgumentParser(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('--signature', type=str, help='Method signature to encode')
argparser.add_argument('contract_args', type=str, nargs='*', help='arguments to encode') argparser.add_argument('contract_args', type=str, nargs='*', help='arguments to encode')
args = argparser.parse_args() args = argparser.parse_args()
@ -63,9 +59,7 @@ extra_args = {
'contract_args': None, 'contract_args': 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, default_config_dir=config_dir)
logg.debug('config loaded:\n{}'.format(config))
if not config.get('_EXEC_ADDRESS'):
argparser.error('exec address (-e) must be defined')
block_all = args.ww block_all = args.ww
block_last = args.w or block_all block_last = args.w or block_all
@ -103,28 +97,77 @@ def main():
code += cli_encoder.get() 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 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)) print(strip_0x(code))
return return
elif not exec_address:
logg.error('exec address (-e) must be defined with mode "{}"'.format(args.mode))
sys.exit(1)
exec_address = add_0x(to_checksum_address(config.get('_EXEC_ADDRESS'))) 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 signer == None: 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) c = TxFactory(chain_spec)
j = JSONRPCRequest(id_generator=rpc.id_generator) j = JSONRPCRequest(id_generator=rpc.id_generator)
o = j.template() 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['method'] = 'eth_call'
o['params'].append({ o['params'].append({
'to': exec_address, 'to': exec_address,
'from': signer_address, 'from': signer_address,
'value': '0x00', 'value': '0x0',
'gas': add_0x(int.to_bytes(8000000, 8, byteorder='big').hex()), # TODO: better get of network gas limit 'gas': gas_limit, # TODO: better get of network gas limit
'gasPrice': '0x01', 'gasPrice': gas_price,
'data': add_0x(code), 'data': add_0x(code),
}) })
height = to_blockheight_param(config.get('_HEIGHT')) height = to_blockheight_param(config.get('_HEIGHT'))
o['params'].append(height) o['params'].append(height)
o = j.finalize(o) o = j.finalize(o)
if config.get('_RPC_SEND'):
r = conn.do(o) r = conn.do(o)
try: try:
print(strip_0x(r)) print(strip_0x(r))
@ -132,6 +175,13 @@ def main():
except ValueError: except ValueError:
sys.stderr.write('query returned an empty value ({})\n'.format(r)) sys.stderr.write('query returned an empty value ({})\n'.format(r))
sys.exit(1) 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: if chain_spec == None:
raise ValueError('chain spec must be specified') raise ValueError('chain spec must be specified')
@ -144,7 +194,7 @@ def main():
tx_format = TxFormat.RLP_SIGNED tx_format = TxFormat.RLP_SIGNED
(tx_hash_hex, o) = c.finalize(tx, tx_format=tx_format) (tx_hash_hex, o) = c.finalize(tx, tx_format=tx_format)
if send: if send:
r = conn.do(r) r = conn.do(o)
print(r) print(r)
else: else:
if config.get('_RAW'): if config.get('_RAW'):

View File

@ -0,0 +1,23 @@
# 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)))

View File

@ -26,6 +26,10 @@ from chainlib.eth.gas import Gas
from chainlib.eth.gas import balance as gas_balance from chainlib.eth.gas import balance as gas_balance
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from chainlib.eth.runnable.util import decode_for_puny_humans 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 import chainlib.eth.cli
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
@ -62,8 +66,12 @@ send = config.true('_RPC_SEND')
def balance(address, id_generator): def balance(address, id_generator):
o = gas_balance(address, id_generator=id_generator) o = gas_balance(address, id_generator=id_generator)
r = conn.do(o) r = conn.do(o)
hx = strip_0x(r) try:
return int(hx, 16) balance = int(r)
except ValueError:
balance = strip_0x(r)
balance = int(balance, 16)
return balance
def main(): def main():
@ -73,32 +81,32 @@ def main():
g = Gas(chain_spec, signer=signer, gas_oracle=rpc.get_gas_oracle(), nonce_oracle=rpc.get_nonce_oracle()) 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')) recipient = to_checksum_address(config.get('_RECIPIENT'))
if not config.true('_UNSAFE') and recipient != add_0x(config.get('_RECIPIENT')): if not config.true('_UNSAFE') and not is_checksum_address(recipient):
raise ValueError('invalid checksum address') raise ValueError('invalid checksum address')
logg.info('gas transfer from {} to {} value {}'.format(signer_address, recipient, value)) logg.info('gas transfer from {} to {} value {}'.format(signer_address, recipient, value))
if logg.isEnabledFor(logging.DEBUG): if logg.isEnabledFor(logging.DEBUG):
try: try:
sender_balance = balance(signer_address, rpc.id_generator) sender_balance = balance(add_0x(signer_address), rpc.id_generator)
recipient_balance = balance(add_0x(recipient), rpc.id_generator) recipient_balance = balance(add_0x(recipient), rpc.id_generator)
logg.debug('sender {} balance before: {}'.format(signer_address, sender_balance)) logg.debug('sender {} balance before: {}'.format(signer_address, sender_balance))
logg.debug('recipient {} balance before: {}'.format(recipient, recipient_balance)) logg.debug('recipient {} balance before: {}'.format(recipient, recipient_balance))
except urllib.error.URLError: except urllib.error.URLError:
pass pass
(tx_hash_hex, o) = g.create(signer_address, recipient, value, data=config.get('_DATA'), id_generator=rpc.id_generator) (tx_hash_hex, o) = g.create(signer_address, add_0x(recipient), value, data=config.get('_DATA'), id_generator=rpc.id_generator)
if send: if send:
conn.do(o) conn.do(o)
if block_last: if block_last:
r = conn.wait(tx_hash_hex) r = conn.wait(tx_hash_hex)
if logg.isEnabledFor(logging.DEBUG): if logg.isEnabledFor(logging.DEBUG):
sender_balance = balance(signer_address, rpc.id_generator) sender_balance = balance(add_0x(signer_address), rpc.id_generator)
recipient_balance = balance(add_0x(recipient), rpc.id_generator) recipient_balance = balance(add_0x(recipient), rpc.id_generator)
logg.debug('sender {} balance after: {}'.format(signer_address, sender_balance)) logg.debug('sender {} balance after: {}'.format(signer_address, sender_balance))
logg.debug('recipient {} balance after: {}'.format(recipient, recipient_balance)) logg.debug('recipient {} balance after: {}'.format(recipient, recipient_balance))
if r['status'] == 0: if r['status'] == 0:
logg.critical('VM revert. Wish I could tell you more') logg.critical('VM revert for {}. Wish I could tell you more'.format(tx_hash_hex))
sys.exit(1) sys.exit(1)
print(tx_hash_hex) print(tx_hash_hex)
else: else:

View File

@ -48,7 +48,8 @@ logg = logging.getLogger()
script_dir = os.path.dirname(os.path.realpath(__file__)) script_dir = os.path.dirname(os.path.realpath(__file__))
config_dir = os.path.join(script_dir, '..', 'data', 'config') config_dir = os.path.join(script_dir, '..', 'data', 'config')
arg_flags = chainlib.eth.cli.argflag_std_read arg_flags = chainlib.eth.cli.argflag_std_base_read
arg_flags = chainlib.eth.cli.argflag_reset(arg_flags, chainlib.eth.cli.Flag.CHAIN_SPEC)
argparser = chainlib.eth.cli.ArgumentParser(arg_flags) argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
argparser.add_positional('item', type=str, help='Address or transaction to retrieve data for') argparser.add_positional('item', type=str, help='Address or transaction to retrieve data for')
args = argparser.parse_args() args = argparser.parse_args()
@ -63,6 +64,7 @@ item = add_0x(args.item)
def get_transaction(conn, tx_hash, id_generator): def get_transaction(conn, tx_hash, id_generator):
tx_hash = add_0x(tx_hash)
j = JSONRPCRequest(id_generator=id_generator) j = JSONRPCRequest(id_generator=id_generator)
o = j.template() o = j.template()
o['method'] = 'eth_getTransactionByHash' o['method'] = 'eth_getTransactionByHash'
@ -97,13 +99,13 @@ def get_transaction(conn, tx_hash, id_generator):
r = conn.do(o) r = conn.do(o)
block = Block(r) block = Block(r)
tx.apply_block(block) tx.apply_block(block)
logg.debug('foo {}'.format(tx_src))
tx.generate_wire(chain_spec) tx.generate_wire(chain_spec)
return tx return tx
def get_address(conn, address, id_generator, height): def get_address(conn, address, id_generator, height):
address = add_0x(address)
j = JSONRPCRequest(id_generator=id_generator) j = JSONRPCRequest(id_generator=id_generator)
o = j.template() o = j.template()
o['method'] = 'eth_getCode' o['method'] = 'eth_getCode'

View File

@ -16,7 +16,7 @@ from hexathon import (
even, even,
) )
import sha3 import sha3
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer from funga.eth.signer import EIP155Signer
# local imports # local imports
from chainlib.eth.address import AddressChecksum from chainlib.eth.address import AddressChecksum
@ -24,6 +24,7 @@ from chainlib.eth.chain import network_id
from chainlib.eth.block import ( from chainlib.eth.block import (
block_latest, block_latest,
block_by_number, block_by_number,
syncing,
Block, Block,
) )
from chainlib.eth.tx import count from chainlib.eth.tx import count
@ -43,21 +44,35 @@ logg = logging.getLogger()
script_dir = os.path.dirname(os.path.realpath(__file__)) script_dir = os.path.dirname(os.path.realpath(__file__))
config_dir = os.path.join(script_dir, '..', 'data', 'config') 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',
}
arg_flags = chainlib.eth.cli.argflag_std_read arg_flags = chainlib.eth.cli.argflag_std_read
argparser = chainlib.eth.cli.ArgumentParser(arg_flags) 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('--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_positional('entry', required=False, help='Output single item')
args = argparser.parse_args() args = argparser.parse_args()
config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args={'long': None}, default_config_dir=config_dir) extra_args = {
'local': None,
'long': None,
'entry': None,
}
config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args=extra_args, default_config_dir=config_dir)
holder_address = args.address if config.get('_ENTRY') != None:
wallet = chainlib.eth.cli.Wallet() if config.get('_ENTRY') not in results_translation.keys():
wallet.from_config(config) raise ValueError('Unknown entry {}'.format(config.get('_ENTRY')))
if wallet.get_signer_address() == None and holder_address != None:
wallet.from_address(holder_address)
rpc = chainlib.eth.cli.Rpc(wallet=wallet) rpc = chainlib.eth.cli.Rpc()
conn = rpc.connect_by_config(config) conn = rpc.connect_by_config(config)
token_symbol = 'eth' token_symbol = 'eth'
@ -68,20 +83,37 @@ human = not config.true('_RAW')
longmode = config.true('_LONG') longmode = config.true('_LONG')
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
def main(): def main():
results = {}
o = network_id(id_generator=rpc.id_generator) o = network_id(id_generator=rpc.id_generator)
r = conn.do(o) r = conn.do(o)
#if human: #if human:
# n = format(n, ',') # n = format(n, ',')
sys.stdout.write('Network id: {}\n'.format(r)) if set_result(results, 'network_id', r):
return
o = block_latest(id_generator=rpc.id_generator) o = block_latest(id_generator=rpc.id_generator)
r = conn.do(o) r = conn.do(o)
try:
n = int(r, 16) n = int(r, 16)
except ValueError:
n = int(r)
first_block_number = n first_block_number = n
if human: if human:
n = format(n, ',') n = format(n, ',')
sys.stdout.write('Block: {}\n'.format(n)) if set_result(results, 'block', n):
return
o = block_by_number(first_block_number, False, id_generator=rpc.id_generator) o = block_by_number(first_block_number, False, id_generator=rpc.id_generator)
r = conn.do(o) r = conn.do(o)
@ -107,22 +139,31 @@ def main():
if human: if human:
n = format(n, ',') n = format(n, ',')
sys.stdout.write('Gaslimit: {}\n'.format(n)) if set_result(results, 'gas_limit', n):
sys.stdout.write('Blocktime: {}\n'.format(aggr_time / BLOCK_SAMPLES)) return
if set_result(results, 'block_time', aggr_time / BLOCK_SAMPLES):
return
o = price(id_generator=rpc.id_generator) o = price(id_generator=rpc.id_generator)
r = conn.do(o) r = conn.do(o)
n = int(r, 16) n = int(r, 16)
if human: if human:
n = format(n, ',') n = format(n, ',')
sys.stdout.write('Gasprice: {}\n'.format(n)) if set_result(results, 'gas_price', n):
return
if holder_address != None: if config.get('_LOCAL'):
o = count(holder_address) o = syncing()
r = conn.do(o) r = conn.do(o)
n = int(r, 16) if set_result(results, 'syncing', r):
sys.stdout.write('Address: {}\n'.format(holder_address)) return
sys.stdout.write('Nonce: {}\n'.format(n))
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 __name__ == '__main__': if __name__ == '__main__':

View File

@ -11,8 +11,8 @@ import urllib
# external imports # external imports
import chainlib.eth.cli import chainlib.eth.cli
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer from funga.eth.signer import EIP155Signer
from crypto_dev_signer.keystore.dict import DictKeystore from funga.eth.keystore.dict import DictKeystore
from hexathon import ( from hexathon import (
add_0x, add_0x,
strip_0x, strip_0x,
@ -51,6 +51,7 @@ config_dir = os.path.join(script_dir, '..', 'data', 'config')
arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC
argparser = chainlib.eth.cli.ArgumentParser(arg_flags) argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
argparser.add_argument('--deploy', action='store_true', help='Deploy data as contract') 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_positional('data', type=str, help='Transaction data') argparser.add_positional('data', type=str, help='Transaction data')
args = argparser.parse_args() args = argparser.parse_args()
config = chainlib.eth.cli.Config.from_args(args, arg_flags, default_config_dir=config_dir) config = chainlib.eth.cli.Config.from_args(args, arg_flags, default_config_dir=config_dir)
@ -133,6 +134,11 @@ def main():
o = raw(args.data, id_generator=rpc.id_generator) o = raw(args.data, id_generator=rpc.id_generator)
if send: if send:
r = conn.do(o) r = conn.do(o)
if block_last:
r = 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)
print(r) print(r)
else: else:
print(o) print(o)

View File

@ -0,0 +1,114 @@
# 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
import chainlib.eth.cli
from funga.eth.signer import EIP155Signer
from funga.eth.keystore.dict import DictKeystore
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.jsonrpc import (
JSONRPCRequest,
IntSequenceGenerator,
)
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.chain import ChainSpec
from chainlib.eth.runnable.util import decode_for_puny_humans
from chainlib.eth.jsonrpc import to_blockheight_param
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')
arg_flags = chainlib.eth.cli.argflag_std_read
argparser = chainlib.eth.cli.ArgumentParser(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_positional('hashes', append=True, type=str, help='Transaction hashes to wait for')
args = argparser.parse_args()
extra_args = {
'ignore': None,
'ignore_all': None,
'hashes': None,
}
config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args=extra_args, default_config_dir=config_dir)
rpc = chainlib.eth.cli.Rpc()
conn = rpc.connect_by_config(config)
chain_spec = None
try:
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
except AttributeError:
pass
def main():
hashes_ready = []
hashes_ignore = []
for hsh in config.get('_IGNORE'):
hashes_ignore.append(add_0x(hex_uniform(strip_0x(hsh))))
if len(config.get('_HASHES')) == 1:
try:
hsh = add_0x(hex_uniform(strip_0x(config.get('_HASHES')[0])))
hashes_ready = [hsh]
except ValueError:
logg.debug('hash argument not a hash, will try it as a file name')
f = open(config.get('_HASHES')[0])
for hsh in f:
logg.debug('hshs {}'.format(hsh))
hashes_ready.append(add_0x(hex_uniform(strip_0x(hsh.rstrip()))))
f.close()
else:
for hsh in config.get('_HASHES'):
logg.debug('hsh {}'.format(hsh))
hashes_ready.append(add_0x(hex_uniform(strip_0x(hsh))))
for hsh in hashes_ready:
logg.debug('processing transaction hash {}'.format(hsh))
try:
r = conn.wait(hsh)
except RevertEthException:
if config.get('_IGNORE_ALL') or hsh in hashes_ignore:
logg.info('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()

View File

@ -13,9 +13,11 @@ from hexathon import (
) )
from rlp import decode as rlp_decode from rlp import decode as rlp_decode
from rlp import encode as rlp_encode from rlp import encode as rlp_encode
from crypto_dev_signer.eth.transaction import EIP155Transaction from funga.eth.transaction import EIP155Transaction
from crypto_dev_signer.encoding import public_key_to_address from funga.eth.encoding import (
from crypto_dev_signer.eth.encoding import chain_id_to_v public_key_to_address,
chain_id_to_v,
)
from potaahto.symbols import snake_and_camel from potaahto.symbols import snake_and_camel
from chainlib.hash import keccak256_hex_to_hex from chainlib.hash import keccak256_hex_to_hex
from chainlib.status import Status from chainlib.status import Status
@ -93,7 +95,11 @@ def pack(tx_src, chain_spec):
tx_src['r'], tx_src['r'],
tx_src['s'], tx_src['s'],
]: ]:
for b in bytes.fromhex(strip_0x(a)): 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):
signature[cursor] = b signature[cursor] = b
cursor += 1 cursor += 1
@ -160,6 +166,7 @@ def __unpack_raw(tx_raw_bytes, chain_id=1):
vb = chain_id vb = chain_id
if chain_id != 0: if chain_id != 0:
v = int.from_bytes(d[6], 'big') 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 = bytearray(32)
r[32-len(d[7]):] = d[7] r[32-len(d[7]):] = d[7]
@ -394,11 +401,13 @@ class TxFactory:
""" """
txe = EIP155Transaction(tx, tx['nonce'], tx['chainId']) txe = EIP155Transaction(tx, tx['nonce'], tx['chainId'])
txes = txe.serialize() txes = txe.serialize()
gas_price = strip_0x(txes['gasPrice'])
gas = strip_0x(txes['gas'])
return { return {
'from': tx['from'], 'from': tx['from'],
'to': txes['to'], 'to': txes['to'],
'gasPrice': '0x' + compact(txes['gasPrice']), 'gasPrice': add_0x(compact(gas_price)),
'gas': '0x' + compact(txes['gas']), 'gas': add_0x(compact(gas)),
'data': txes['data'], 'data': txes['data'],
} }
@ -418,6 +427,10 @@ class TxFactory:
return self.build(tx, id_generator=id_generator) return self.build(tx, id_generator=id_generator)
elif tx_format == TxFormat.RLP_SIGNED: elif tx_format == TxFormat.RLP_SIGNED:
return self.build_raw(tx) return self.build_raw(tx)
elif tx_format == TxFormat.RAW_ARGS:
return strip_0x(tx['data'])
elif tx_format == TxFormat.DICT:
return tx
raise NotImplementedError('tx formatting {} not implemented'.format(tx_format)) raise NotImplementedError('tx formatting {} not implemented'.format(tx_format))
@ -514,7 +527,7 @@ class Tx(BaseTx):
#:todo: divide up constructor method #:todo: divide up constructor method
""" """
def __init__(self, src, block=None, rcpt=None): def __init__(self, src, block=None, rcpt=None, strict=False):
self.__rcpt_block_hash = None self.__rcpt_block_hash = None
src = self.src_normalize(src) src = self.src_normalize(src)
@ -543,6 +556,9 @@ class Tx(BaseTx):
self.outputs = [to_checksum(address_from)] self.outputs = [to_checksum(address_from)]
self.contract = None self.contract = None
self.fee_limit = self.gas_limit
self.fee_price = self.gas_price
try: try:
inpt = src['input'] inpt = src['input']
except KeyError: except KeyError:
@ -564,13 +580,14 @@ class Tx(BaseTx):
try: try:
self.wire = src['raw'] self.wire = src['raw']
except KeyError: except KeyError:
logg.warning('no inline raw tx src, and no raw rendering implemented, field will be "None"') logg.debug('no inline raw tx src, and no raw rendering implemented, field will be "None"')
self.status = Status.PENDING self.status = Status.PENDING
self.logs = None self.logs = None
self.tx_rcpt_src = None
if rcpt != None: if rcpt != None:
self.apply_receipt(rcpt) self.apply_receipt(rcpt, strict=strict)
self.v = src.get('v') self.v = src.get('v')
self.r = src.get('r') self.r = src.get('r')
@ -613,7 +630,11 @@ class Tx(BaseTx):
return self.src() return self.src()
def apply_receipt(self, rcpt): def rcpt_src(self):
return self.tx_rcpt_src
def apply_receipt(self, rcpt, strict=False):
"""Apply receipt data to transaction object. """Apply receipt data to transaction object.
Effect is the same as passing a receipt at construction. Effect is the same as passing a receipt at construction.
@ -623,6 +644,7 @@ class Tx(BaseTx):
""" """
rcpt = self.src_normalize(rcpt) rcpt = self.src_normalize(rcpt)
logg.debug('rcpt {}'.format(rcpt)) logg.debug('rcpt {}'.format(rcpt))
self.tx_rcpt_src = rcpt
tx_hash = add_0x(rcpt['transaction_hash']) tx_hash = add_0x(rcpt['transaction_hash'])
if rcpt['transaction_hash'] != add_0x(self.hash): if rcpt['transaction_hash'] != add_0x(self.hash):
@ -637,6 +659,12 @@ class Tx(BaseTx):
status_number = int(rcpt['status'], 16) status_number = int(rcpt['status'], 16)
except TypeError: except TypeError:
status_number = int(rcpt['status']) status_number = int(rcpt['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 rcpt['block_number'] == None: if rcpt['block_number'] == None:
self.status = Status.PENDING self.status = Status.PENDING
else: else:
@ -691,12 +719,12 @@ class Tx(BaseTx):
@staticmethod @staticmethod
def from_src(src, block=None, rcpt=None): def from_src(src, block=None, rcpt=None, strict=False):
"""Creates a new Tx object. """Creates a new Tx object.
Alias of constructor. Alias of constructor.
""" """
return Tx(src, block=block, rcpt=rcpt) return Tx(src, block=block, rcpt=rcpt, strict=strict)
def __str__(self): def __str__(self):

View File

@ -5,6 +5,7 @@ import logging
# external imports # external imports
import eth_tester import eth_tester
import coincurve import coincurve
from chainlib.encode import TxHexNormalizer
from chainlib.connection import ( from chainlib.connection import (
RPCConnection, RPCConnection,
error_parser, error_parser,
@ -22,9 +23,10 @@ from hexathon import (
add_0x, add_0x,
strip_0x, strip_0x,
) )
from chainlib.eth.tx import receipt
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer from funga.eth.signer import EIP155Signer
from crypto_dev_signer.encoding import private_key_to_address from funga.eth.encoding import private_key_to_address
logg = logging.getLogger().getChild(__name__) logg = logging.getLogger().getChild(__name__)
@ -80,6 +82,11 @@ class TestRPCConnection(RPCConnection):
return jsonrpc_result(r, error_parser) return jsonrpc_result(r, error_parser)
def wait(self, tx_hash_hex):
o = receipt(tx_hash_hex)
return self.do(o)
def eth_blockNumber(self, p): def eth_blockNumber(self, p):
block = self.backend.get_block_by_number('latest') block = self.backend.get_block_by_number('latest')
return block['number'] return block['number']
@ -184,7 +191,8 @@ class TestRPCConnection(RPCConnection):
pk_bytes = self.backend.keystore.get(tx.sender) pk_bytes = self.backend.keystore.get(tx.sender)
pk = coincurve.PrivateKey(secret=pk_bytes) pk = coincurve.PrivateKey(secret=pk_bytes)
result_address = private_key_to_address(pk) result_address = private_key_to_address(pk)
assert strip_0x(result_address) == strip_0x(tx.sender) tx_normalize = TxHexNormalizer()
assert tx_normalize.wallet_address(strip_0x(result_address)) == tx_normalize.wallet_address(strip_0x(tx.sender))
def sign_transaction(self, tx, passphrase=''): def sign_transaction(self, tx, passphrase=''):

View File

@ -5,8 +5,8 @@ import logging
# external imports # external imports
import eth_tester import eth_tester
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer from funga.eth.signer import EIP155Signer
from crypto_dev_signer.keystore.dict import DictKeystore from funga.eth.keystore.dict import DictKeystore
from hexathon import ( from hexathon import (
strip_0x, strip_0x,
add_0x, add_0x,

View File

@ -0,0 +1,16 @@
.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

View File

@ -0,0 +1 @@
a Address to get balance for. -a, --address

View File

@ -0,0 +1,7 @@
.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.

View File

@ -0,0 +1,11 @@
.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.

15
man/eth-count.head.groff Normal file
View File

@ -0,0 +1,15 @@
.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
man/eth-count.overrides Normal file
View File

@ -0,0 +1 @@
a Address to count transactions for. -a, --address

14
man/eth-decode.head.groff Normal file
View File

@ -0,0 +1,14 @@
.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

View File

@ -0,0 +1,31 @@
.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

View File

@ -0,0 +1,22 @@
.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

17
man/eth-encode.head.groff Normal file
View File

@ -0,0 +1,17 @@
.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
man/eth-encode.overrides Normal file
View File

@ -0,0 +1 @@
mode Mode of operation encoding is for. Must be one of "tx," "call," or "arg." See \fBMODES\fP below. --mode mode

View File

@ -0,0 +1,75 @@
.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)

19
man/eth-gas.head.groff Normal file
View File

@ -0,0 +1,19 @@
.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
man/eth-gas.overrides Normal file
View File

@ -0,0 +1 @@
a Beneficiary of the gas token transaction.

19
man/eth-get.head.groff Normal file
View File

@ -0,0 +1,19 @@
.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

27
man/eth-info.head.groff Normal file
View File

@ -0,0 +1,27 @@
.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

View File

@ -0,0 +1,8 @@
.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

26
man/eth-raw.head.groff Normal file
View File

@ -0,0 +1,26 @@
.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

View File

@ -0,0 +1,4 @@
.SH SEE ALSO
.BP
confini-dump(1), eth-keyfile(1), eth-encode(1), eth-gas(1)

17
man/eth-wait.head.groff Normal file
View File

@ -0,0 +1,17 @@
.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

2
man/eth-wait.overrides Normal file
View File

@ -0,0 +1,2 @@
ignore Ignore error from the specified transaction. May be defined more than once. --ignore tx_hash
ignoreall Ignore errors from all transactions. --ignore-all

View File

@ -1,7 +1,7 @@
crypto-dev-signer>=0.4.15rc2,<=0.4.15 funga-eth~=0.6.0
pysha3==1.0.2 pysha3==1.0.2
hexathon~=0.0.1a8 hexathon~=0.1.5
websocket-client==0.57.0 websocket-client==0.57.0
potaahto~=0.0.1a1 potaahto~=0.1.1
chainlib==0.0.9rc1 chainlib~=0.1.0
confini>=0.4.1a1,<0.5.0 confini~=0.6.0

View File

@ -1,6 +1,6 @@
[metadata] [metadata]
name = chainlib-eth name = chainlib-eth
version = 0.0.9rc1 version = 0.1.1
description = Ethereum implementation of the chainlib interface description = Ethereum implementation of the chainlib interface
author = Louis Holbrook author = Louis Holbrook
author_email = dev@holbrook.no author_email = dev@holbrook.no
@ -14,6 +14,7 @@ classifiers =
Programming Language :: Python :: 3 Programming Language :: Python :: 3
Operating System :: OS Independent Operating System :: OS Independent
Development Status :: 3 - Alpha Development Status :: 3 - Alpha
Topic :: Software Development :: Libraries
Environment :: Console Environment :: Console
Intended Audience :: Developers Intended Audience :: Developers
License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+) License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
@ -36,6 +37,7 @@ packages =
[options.entry_points] [options.entry_points]
console_scripts = console_scripts =
eth-count = chainlib.eth.runnable.count:main
eth-balance = chainlib.eth.runnable.balance:main eth-balance = chainlib.eth.runnable.balance:main
eth-checksum = chainlib.eth.runnable.checksum:main eth-checksum = chainlib.eth.runnable.checksum:main
eth-gas = chainlib.eth.runnable.gas:main eth-gas = chainlib.eth.runnable.gas:main
@ -45,4 +47,4 @@ console_scripts =
eth-encode = chainlib.eth.runnable.encode:main eth-encode = chainlib.eth.runnable.encode:main
eth-info = chainlib.eth.runnable.info:main eth-info = chainlib.eth.runnable.info:main
eth-nonce = chainlib.eth.runnable.count:main eth-nonce = chainlib.eth.runnable.count:main
eth = chainlib.eth.runnable.info:main eth-wait = chainlib.eth.runnable.wait:main

View File

@ -2,3 +2,4 @@ eth_tester==0.5.0b3
py-evm==0.3.0a20 py-evm==0.3.0a20
rlp==2.0.1 rlp==2.0.1
pytest==6.0.1 pytest==6.0.1
coverage==5.5

View File

@ -12,7 +12,7 @@ from tests.base import TestBase
class TestChain(TestBase): class TestChain(TestBase):
def test_chain_spec(self): def test_chain_spec(self):
checksum_address = '0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C' checksum_address = 'Eb3907eCad74a0013c259D5874AE7f22DcBcC95C'
plain_address = checksum_address.lower() plain_address = checksum_address.lower()
self.assertEqual(checksum_address, to_checksum(checksum_address)) self.assertEqual(checksum_address, to_checksum(checksum_address))

View File

@ -7,16 +7,19 @@ import logging
import json import json
# external imports # external imports
from crypto_dev_signer.eth.transaction import EIP155Transaction from funga.eth.transaction import EIP155Transaction
from crypto_dev_signer.eth.signer.defaultsigner import ReferenceSigner from funga.eth.signer.defaultsigner import EIP155Signer
from crypto_dev_signer.keystore.dict import DictKeystore from funga.eth.keystore.dict import DictKeystore
# local imports # local imports
import chainlib import chainlib
from chainlib.eth.connection import EthUnixSignerConnection from chainlib.eth.connection import EthUnixSignerConnection
from chainlib.eth.sign import sign_transaction from chainlib.eth.sign import sign_transaction
from chainlib.eth.tx import TxFactory from chainlib.eth.tx import TxFactory
from chainlib.eth.address import to_checksum_address from chainlib.eth.address import (
to_checksum_address,
is_same_address,
)
from chainlib.jsonrpc import ( from chainlib.jsonrpc import (
jsonrpc_response, jsonrpc_response,
jsonrpc_error, jsonrpc_error,
@ -52,11 +55,13 @@ class Mocket(socket.socket):
logg.debug('mocket received {}'.format(v)) logg.debug('mocket received {}'.format(v))
Mocket.req_id = o['id'] Mocket.req_id = o['id']
params = o['params'][0] params = o['params'][0]
if to_checksum_address(params.get('from')) != alice: from_address = to_checksum_address(params.get('from'))
logg.error('from does not match alice {}'.format(params)) if not is_same_address(alice, from_address):
logg.error('from {} does not match alice {}'.format(from_address, alice)) #params))
Mocket.error = True Mocket.error = True
if to_checksum_address(params.get('to')) != bob: to_address = to_checksum_address(params.get('to'))
logg.error('to does not match bob {}'.format(params)) if not is_same_address(bob, to_address):
logg.error('to {} does not match bob {}'.format(to_address, bob)) #params))
Mocket.error = True Mocket.error = True
if not Mocket.error: if not Mocket.error:
Mocket.tx = EIP155Transaction(params, params['nonce'], params['chainId']) Mocket.tx = EIP155Transaction(params, params['nonce'], params['chainId'])
@ -92,7 +97,7 @@ class TestSign(TestBase):
logg.debug('alice {}'.format(alice)) logg.debug('alice {}'.format(alice))
logg.debug('bob {}'.format(bob)) logg.debug('bob {}'.format(bob))
self.signer = ReferenceSigner(keystore) self.signer = EIP155Signer(keystore)
Mocket.signer = self.signer Mocket.signer = self.signer

View File

@ -23,7 +23,10 @@ from chainlib.eth.contract import (
ABIContractEncoder, ABIContractEncoder,
ABIContractType, ABIContractType,
) )
from chainlib.eth.address import to_checksum_address from chainlib.eth.address import (
to_checksum_address,
is_same_address,
)
from hexathon import ( from hexathon import (
strip_0x, strip_0x,
add_0x, add_0x,
@ -43,8 +46,21 @@ class TxTestCase(EthTesterCase):
c = Gas(signer=self.signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle, chain_spec=self.chain_spec) 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_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) tx = unpack(bytes.fromhex(strip_0x(o)), self.chain_spec)
self.assertEqual(tx['from'], self.accounts[0]) self.assertTrue(is_same_address(tx['from'], self.accounts[0]))
self.assertEqual(tx['to'], self.accounts[1]) 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)
def test_tx_pack(self): def test_tx_pack(self):