Compare commits

...

65 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 7abce82eef
Fix wrong variable name in encode cli 2021-10-18 13:28:53 +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 b983938d80
Move all encoding steps to cliencoder 2021-10-06 07:52:19 +02:00
nolash 0e0dbf180e
Split cli helper classes to respective files 2021-10-06 07:44:53 +02:00
nolash e4d6b8d845
Add option to generate abi encoding without method 2021-10-06 07:30:07 +02:00
nolash 75c72b7828
Incorporate reset method for arg flags 2021-10-06 07:13:12 +02:00
nolash 55a72ed6d6
Add generic contract call/tx encoder tool 2021-10-06 06:57:51 +02:00
56 changed files with 1152 additions and 179 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
* 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,
uniform,
)
from crypto_dev_signer.encoding import (
from funga.eth.encoding import (
is_address,
is_checksum_address,
to_checksum_address,
@ -42,3 +42,7 @@ 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))

View File

@ -1,10 +1,11 @@
import sys
# external imports
from chainlib.jsonrpc import JSONRPCRequest
from chainlib.block import Block as BaseBlock
from hexathon import (
add_0x,
strip_0x,
even,
compact,
)
# 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):
"""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)
o = j.template()
o['method'] = 'eth_getBlockByNumber'
@ -60,6 +62,20 @@ 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):
"""Encapsulates an Ethereum block

View File

@ -0,0 +1,4 @@
from .arg import *
from .config import Config
from .rpc import Rpc
from .wallet import Wallet

10
chainlib/eth/cli/arg.py Normal file
View File

@ -0,0 +1,10 @@
# external imports
from chainlib.cli import (
ArgumentParser,
argflag_std_read,
argflag_std_write,
argflag_std_base,
argflag_std_base_read,
flag_reset as argflag_reset,
Flag,
)

View File

@ -0,0 +1,33 @@
# standard imports
import os
# external imports
from chainlib.cli import Config as BaseConfig
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
@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

103
chainlib/eth/cli/encode.py Normal file
View File

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

View File

@ -1,22 +1,8 @@
# standard imports
import os
import logging
# external imports
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
from chainlib.cli import Rpc as BaseRpc
from chainlib.eth.connection import EthHTTPConnection
# local imports
from chainlib.eth.address import AddressChecksum
from chainlib.eth.connection import EthHTTPConnection
from chainlib.eth.gas import (
OverrideGasOracle,
RPCGasOracle,
@ -26,20 +12,6 @@ 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):
@ -97,27 +69,3 @@ 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

View File

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

View File

@ -36,6 +36,7 @@ from chainlib.jsonrpc import (
from chainlib.eth.tx import (
unpack,
)
from potaahto.symbols import snake_and_camel
logg = logging.getLogger(__name__)
@ -88,11 +89,16 @@ class EthHTTPConnection(JSONRPCHTTPConnection):
e = jsonrpc_result(r, error_parser)
if e != None:
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
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
if timeout > 0.0:
delta = (datetime.datetime.utcnow() - t) + datetime.timedelta(seconds=delay)

View File

@ -1,13 +1,13 @@
[rpc]
http_provider = http://localhost:8545
provider = http://localhost:8545
auth =
credentials =
dialect = default
scheme = http
verify = 1
[chain]
spec = evm:ethereum:1
spec = evm:berlin:1:ethereum
[wallet]
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,
strip_0x,
)
from crypto_dev_signer.eth.transaction import EIP155Transaction
from funga.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(address)
o['params'].append(add_0x(address))
height = to_blockheight_param(height)
o['params'].append(height)
return j.finalize(o)

View File

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

View File

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

View File

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

View File

@ -24,7 +24,7 @@ from chainlib.eth.gas import (
balance,
)
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)
logg = logging.getLogger()

View File

@ -15,8 +15,8 @@ from chainlib.eth.connection import EthHTTPConnection
from chainlib.eth.tx import count
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 funga.eth.keystore.dict import DictKeystore
from funga.eth.signer import EIP155Signer
from hexathon import add_0x
logging.basicConfig(level=logging.WARNING)
@ -25,7 +25,7 @@ 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
arg_flags = chainlib.eth.cli.argflag_std_base_read | chainlib.eth.cli.Flag.WALLET
argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
argparser.add_positional('address', type=str, help='Ethereum address of recipient')
args = argparser.parse_args()
@ -43,7 +43,7 @@ conn = rpc.connect_by_config(config)
def main():
# 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)
count_result = None
try:

View File

@ -0,0 +1,205 @@
# 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.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')
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.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()
extra_args = {
'signature': None,
'contract_args': None,
}
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))
block_all = args.ww
block_last = args.w or block_all
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()

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.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
logging.basicConfig(level=logging.WARNING)
@ -62,8 +66,12 @@ send = config.true('_RPC_SEND')
def balance(address, id_generator):
o = gas_balance(address, id_generator=id_generator)
r = conn.do(o)
hx = strip_0x(r)
return int(hx, 16)
try:
balance = int(r)
except ValueError:
balance = strip_0x(r)
balance = int(balance, 16)
return balance
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())
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')
logg.info('gas transfer from {} to {} value {}'.format(signer_address, recipient, value))
if logg.isEnabledFor(logging.DEBUG):
try:
sender_balance = balance(signer_address, rpc.id_generator)
recipient_balance = balance(recipient, rpc.id_generator)
sender_balance = balance(add_0x(signer_address), rpc.id_generator)
recipient_balance = balance(add_0x(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(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:
conn.do(o)
if block_last:
r = conn.wait(tx_hash_hex)
if logg.isEnabledFor(logging.DEBUG):
sender_balance = balance(signer_address, rpc.id_generator)
recipient_balance = balance(recipient, rpc.id_generator)
sender_balance = balance(add_0x(signer_address), rpc.id_generator)
recipient_balance = balance(add_0x(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. Wish I could tell you more')
logg.critical('VM revert for {}. Wish I could tell you more'.format(tx_hash_hex))
sys.exit(1)
print(tx_hash_hex)
else:

View File

@ -48,7 +48,8 @@ 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
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.add_positional('item', type=str, help='Address or transaction to retrieve data for')
args = argparser.parse_args()
@ -63,6 +64,7 @@ item = add_0x(args.item)
def get_transaction(conn, tx_hash, id_generator):
tx_hash = add_0x(tx_hash)
j = JSONRPCRequest(id_generator=id_generator)
o = j.template()
o['method'] = 'eth_getTransactionByHash'
@ -97,13 +99,13 @@ def get_transaction(conn, 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):
address = add_0x(address)
j = JSONRPCRequest(id_generator=id_generator)
o = j.template()
o['method'] = 'eth_getCode'

View File

@ -16,7 +16,7 @@ from hexathon import (
even,
)
import sha3
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
from funga.eth.signer import EIP155Signer
# local imports
from chainlib.eth.address import AddressChecksum
@ -24,6 +24,7 @@ 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
@ -43,21 +44,35 @@ 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',
}
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_positional('entry', required=False, help='Output single item')
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
wallet = chainlib.eth.cli.Wallet()
wallet.from_config(config)
if wallet.get_signer_address() == None and holder_address != None:
wallet.from_address(holder_address)
if config.get('_ENTRY') != None:
if config.get('_ENTRY') not in results_translation.keys():
raise ValueError('Unknown entry {}'.format(config.get('_ENTRY')))
rpc = chainlib.eth.cli.Rpc(wallet=wallet)
rpc = chainlib.eth.cli.Rpc()
conn = rpc.connect_by_config(config)
token_symbol = 'eth'
@ -68,20 +83,37 @@ human = not config.true('_RAW')
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():
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))
if set_result(results, 'network_id', r):
return
o = block_latest(id_generator=rpc.id_generator)
r = conn.do(o)
n = int(r, 16)
try:
n = int(r, 16)
except ValueError:
n = int(r)
first_block_number = n
if human:
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)
r = conn.do(o)
@ -107,22 +139,31 @@ def main():
if human:
n = format(n, ',')
sys.stdout.write('Gaslimit: {}\n'.format(n))
sys.stdout.write('Blocktime: {}\n'.format(aggr_time / BLOCK_SAMPLES))
if set_result(results, 'gas_limit', n):
return
if set_result(results, 'block_time', aggr_time / BLOCK_SAMPLES):
return
o = price(id_generator=rpc.id_generator)
r = conn.do(o)
n = int(r, 16)
if human:
n = format(n, ',')
sys.stdout.write('Gasprice: {}\n'.format(n))
if set_result(results, 'gas_price', n):
return
if holder_address != None:
o = count(holder_address)
if config.get('_LOCAL'):
o = syncing()
r = conn.do(o)
n = int(r, 16)
sys.stdout.write('Address: {}\n'.format(holder_address))
sys.stdout.write('Nonce: {}\n'.format(n))
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 __name__ == '__main__':

View File

@ -11,8 +11,8 @@ import urllib
# external imports
import chainlib.eth.cli
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
from crypto_dev_signer.keystore.dict import DictKeystore
from funga.eth.signer import EIP155Signer
from funga.eth.keystore.dict import DictKeystore
from hexathon import (
add_0x,
strip_0x,
@ -50,6 +50,8 @@ config_dir = os.path.join(script_dir, '..', 'data', 'config')
arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC
argparser = chainlib.eth.cli.ArgumentParser(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_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)
@ -65,9 +67,6 @@ 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'))
@ -83,34 +82,37 @@ def main():
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 config.get('_EXEC_ADDRESS') != None or args.deploy:
exec_address = None
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):
if not args.u and exec_address != exec_address:
raise ValueError('invalid checksum address')
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
if signer_address == None:
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'.format(r))
sys.exit(1)
if signer_address != None:
else:
if chain_spec == None:
raise ValueError('chain spec must be specified')
g = TxFactory(chain_spec, signer=rpc.get_signer(), gas_oracle=rpc.get_gas_oracle(), nonce_oracle=rpc.get_nonce_oracle())
@ -124,13 +126,19 @@ def main():
r = conn.do(o)
print(r)
else:
if config.get('_RAW'):
o = strip_0x(o)
print(o)
print(tx_hash_hex)
else:
o = raw(args.data, id_generator=rpc.id_generator)
if send:
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)
else:
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 encode as rlp_encode
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 funga.eth.transaction import EIP155Transaction
from funga.eth.encoding import (
public_key_to_address,
chain_id_to_v,
)
from potaahto.symbols import snake_and_camel
from chainlib.hash import keccak256_hex_to_hex
from chainlib.status import Status
@ -93,7 +95,11 @@ def pack(tx_src, chain_spec):
tx_src['r'],
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
cursor += 1
@ -160,14 +166,14 @@ def __unpack_raw(tx_raw_bytes, chain_id=1):
vb = chain_id
if chain_id != 0:
v = int.from_bytes(d[6], 'big')
vb = v - (chain_id * 2) - 35
if v > 29:
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))
@ -395,11 +401,13 @@ class TxFactory:
"""
txe = EIP155Transaction(tx, tx['nonce'], tx['chainId'])
txes = txe.serialize()
gas_price = strip_0x(txes['gasPrice'])
gas = strip_0x(txes['gas'])
return {
'from': tx['from'],
'to': txes['to'],
'gasPrice': '0x' + compact(txes['gasPrice']),
'gas': '0x' + compact(txes['gas']),
'gasPrice': add_0x(compact(gas_price)),
'gas': add_0x(compact(gas)),
'data': txes['data'],
}
@ -419,6 +427,10 @@ class TxFactory:
return self.build(tx, id_generator=id_generator)
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
raise NotImplementedError('tx formatting {} not implemented'.format(tx_format))
@ -515,7 +527,7 @@ class Tx(BaseTx):
#: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
src = self.src_normalize(src)
@ -544,6 +556,9 @@ class Tx(BaseTx):
self.outputs = [to_checksum(address_from)]
self.contract = None
self.fee_limit = self.gas_limit
self.fee_price = self.gas_price
try:
inpt = src['input']
except KeyError:
@ -565,13 +580,14 @@ class Tx(BaseTx):
try:
self.wire = src['raw']
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.logs = None
self.tx_rcpt_src = None
if rcpt != None:
self.apply_receipt(rcpt)
self.apply_receipt(rcpt, strict=strict)
self.v = src.get('v')
self.r = src.get('r')
@ -614,7 +630,11 @@ class Tx(BaseTx):
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.
Effect is the same as passing a receipt at construction.
@ -624,6 +644,7 @@ class Tx(BaseTx):
"""
rcpt = self.src_normalize(rcpt)
logg.debug('rcpt {}'.format(rcpt))
self.tx_rcpt_src = rcpt
tx_hash = add_0x(rcpt['transaction_hash'])
if rcpt['transaction_hash'] != add_0x(self.hash):
@ -638,6 +659,12 @@ class Tx(BaseTx):
status_number = int(rcpt['status'], 16)
except TypeError:
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:
self.status = Status.PENDING
else:
@ -692,12 +719,12 @@ class Tx(BaseTx):
@staticmethod
def from_src(src, block=None, rcpt=None):
def from_src(src, block=None, rcpt=None, strict=False):
"""Creates a new Tx object.
Alias of constructor.
"""
return Tx(src, block=block, rcpt=rcpt)
return Tx(src, block=block, rcpt=rcpt, strict=strict)
def __str__(self):

View File

@ -25,8 +25,8 @@ from hexathon import (
)
from chainlib.eth.tx import receipt
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
from crypto_dev_signer.encoding import private_key_to_address
from funga.eth.signer import EIP155Signer
from funga.eth.encoding import private_key_to_address
logg = logging.getLogger().getChild(__name__)

View File

@ -5,8 +5,8 @@ import logging
# external imports
import eth_tester
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
from crypto_dev_signer.keystore.dict import DictKeystore
from funga.eth.signer import EIP155Signer
from funga.eth.keystore.dict import DictKeystore
from hexathon import (
strip_0x,
add_0x,
@ -26,7 +26,8 @@ from chainlib.connection import (
from chainlib.eth.address import to_checksum_address
from chainlib.chain import ChainSpec
logg = logging.getLogger(__name__)
#logg = logging.getLogger(__name__)
logg = logging.getLogger()
test_address = bytes.fromhex('Eb3907eCad74a0013c259D5874AE7f22DcBcC95C')
@ -63,6 +64,7 @@ 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)))
@ -73,7 +75,6 @@ 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):

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.15a4,<=0.4.15
funga-eth~=0.6.0
pysha3==1.0.2
hexathon~=0.0.1a8
hexathon~=0.1.5
websocket-client==0.57.0
potaahto~=0.0.1a1
chainlib==0.0.9rc1
confini>=0.4.1a1,<0.5.0
potaahto~=0.1.1
chainlib~=0.1.0
confini~=0.6.0

View File

@ -1,6 +1,6 @@
[metadata]
name = chainlib-eth
version = 0.0.9rc3
version = 0.1.1
description = Ethereum implementation of the chainlib interface
author = Louis Holbrook
author_email = dev@holbrook.no
@ -14,6 +14,7 @@ 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+)
@ -32,15 +33,18 @@ packages =
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 = 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
rlp==2.0.1
pytest==6.0.1
coverage==5.5

View File

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

View File

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

View File

@ -23,7 +23,10 @@ from chainlib.eth.contract import (
ABIContractEncoder,
ABIContractType,
)
from chainlib.eth.address import to_checksum_address
from chainlib.eth.address import (
to_checksum_address,
is_same_address,
)
from hexathon import (
strip_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)
(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.assertEqual(tx['from'], self.accounts[0])
self.assertEqual(tx['to'], self.accounts[1])
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)
def test_tx_pack(self):