Compare commits
37 Commits
6474a2399a
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
a71b3d6388 | ||
|
2dd92fe74b | ||
|
129e25bbf5 | ||
|
a76020b13b | ||
|
3cfeb9ce84 | ||
|
601db731d9 | ||
|
c954f4d1b4 | ||
|
b59eebe181 | ||
|
2f906037a9 | ||
|
1362c9aac6 | ||
|
e5e8680fc6 | ||
|
90d4c4eb95 | ||
|
edf8c4b604 | ||
|
f61ac91205 | ||
|
7e6daa0be3 | ||
|
a3081367db | ||
|
d49e3dd6ec | ||
|
d3f2b1f1fa | ||
|
79a1123dc8 | ||
|
5c09630b6e | ||
|
e9f31ed7f1 | ||
|
7f2c32975d | ||
|
109666ba1d | ||
|
8ac349f092 | ||
|
677b742690 | ||
|
96a0f3beb0 | ||
|
1fbd94d382 | ||
|
1a73c0d1ed | ||
|
e9b7d27670 | ||
|
f688cba5cc | ||
|
700e668a4b | ||
|
7832071512 | ||
|
f618a5c9d7 | ||
|
6bc0caaad7 | ||
|
2ef596df86 | ||
|
bfbb1dea26 | ||
|
5cfb6a7dda |
25
CHANGELOG
25
CHANGELOG
@ -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
16
Makefile
Normal 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
|
@ -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'
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
@ -4,6 +4,7 @@ auth =
|
|||||||
credentials =
|
credentials =
|
||||||
dialect = default
|
dialect = default
|
||||||
scheme = http
|
scheme = http
|
||||||
|
verify = 1
|
||||||
|
|
||||||
[chain]
|
[chain]
|
||||||
spec = evm:berlin:1:ethereum
|
spec = evm:berlin:1:ethereum
|
||||||
|
2
chainlib/eth/data/env/env.ini
vendored
Normal file
2
chainlib/eth/data/env/env.ini
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[rpc]
|
||||||
|
provider = Fully-qualified URL to EVM node's RPC endpoint.
|
@ -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()
|
||||||
|
@ -11,8 +11,7 @@ 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 funga.eth.signer import EIP155Signer
|
||||||
from funga.eth.keystore.dict import DictKeystore
|
from funga.eth.keystore.dict import DictKeystore
|
||||||
from hexathon import (
|
from hexathon import (
|
||||||
@ -21,6 +20,8 @@ from hexathon import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 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,21 +46,20 @@ 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('--notx', type=str, help='Network send is not a transaction')
|
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()
|
||||||
extra_args = {
|
extra_args = {
|
||||||
'signature': None,
|
'signature': None,
|
||||||
'contract_args': None,
|
'contract_args': None,
|
||||||
'notx': 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
|
||||||
@ -105,35 +97,91 @@ 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 or config.true('_NOTX'):
|
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)
|
||||||
r = conn.do(o)
|
|
||||||
try:
|
if config.get('_RPC_SEND'):
|
||||||
print(strip_0x(r))
|
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
|
return
|
||||||
except ValueError:
|
|
||||||
sys.stderr.write('query returned an empty value ({})\n'.format(r))
|
if signer == None:
|
||||||
sys.exit(1)
|
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')
|
||||||
|
23
chainlib/eth/runnable/flags.py
Normal file
23
chainlib/eth/runnable/flags.py
Normal 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)))
|
@ -81,7 +81,7 @@ 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 is_checksum_address(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))
|
||||||
@ -106,7 +106,7 @@ def main():
|
|||||||
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:
|
||||||
|
@ -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()
|
||||||
@ -98,7 +99,6 @@ 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
|
||||||
|
|
||||||
|
@ -105,7 +105,10 @@ def main():
|
|||||||
|
|
||||||
o = block_latest(id_generator=rpc.id_generator)
|
o = block_latest(id_generator=rpc.id_generator)
|
||||||
r = conn.do(o)
|
r = conn.do(o)
|
||||||
n = int(r, 16)
|
try:
|
||||||
|
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, ',')
|
||||||
|
@ -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)
|
||||||
|
@ -95,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
|
||||||
|
|
||||||
@ -162,7 +166,8 @@ 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')
|
||||||
vb = v - (chain_id * 2) - 35
|
if v > 29:
|
||||||
|
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]
|
||||||
s = bytearray(32)
|
s = bytearray(32)
|
||||||
@ -396,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'],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,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))
|
||||||
|
|
||||||
|
|
||||||
@ -516,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)
|
||||||
@ -545,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:
|
||||||
@ -566,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')
|
||||||
@ -615,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.
|
||||||
@ -625,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):
|
||||||
@ -639,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:
|
||||||
@ -693,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):
|
||||||
|
16
man/eth-balance.head.groff
Normal file
16
man/eth-balance.head.groff
Normal 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
|
1
man/eth-balance.overrides
Normal file
1
man/eth-balance.overrides
Normal file
@ -0,0 +1 @@
|
|||||||
|
a Address to get balance for. -a, --address
|
7
man/eth-checksum.custom.groff
Normal file
7
man/eth-checksum.custom.groff
Normal 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.
|
11
man/eth-checksum.head.groff
Normal file
11
man/eth-checksum.head.groff
Normal 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
15
man/eth-count.head.groff
Normal 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
1
man/eth-count.overrides
Normal file
@ -0,0 +1 @@
|
|||||||
|
a Address to count transactions for. -a, --address
|
14
man/eth-decode.head.groff
Normal file
14
man/eth-decode.head.groff
Normal 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
|
31
man/eth-encode.custom.groff
Normal file
31
man/eth-encode.custom.groff
Normal 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
|
22
man/eth-encode.examples.groff
Normal file
22
man/eth-encode.examples.groff
Normal 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
17
man/eth-encode.head.groff
Normal 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
1
man/eth-encode.overrides
Normal 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
|
75
man/eth-gas.examples.groff
Normal file
75
man/eth-gas.examples.groff
Normal 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
19
man/eth-gas.head.groff
Normal 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
1
man/eth-gas.overrides
Normal file
@ -0,0 +1 @@
|
|||||||
|
a Beneficiary of the gas token transaction.
|
19
man/eth-get.head.groff
Normal file
19
man/eth-get.head.groff
Normal 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
27
man/eth-info.head.groff
Normal 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
|
8
man/eth-raw.examples.groff
Normal file
8
man/eth-raw.examples.groff
Normal 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
26
man/eth-raw.head.groff
Normal 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
|
4
man/eth-raw.seealso.groff
Normal file
4
man/eth-raw.seealso.groff
Normal 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
17
man/eth-wait.head.groff
Normal 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
2
man/eth-wait.overrides
Normal 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
|
@ -1,7 +1,7 @@
|
|||||||
funga-eth~=0.5.1
|
funga-eth~=0.6.0
|
||||||
pysha3==1.0.2
|
pysha3==1.0.2
|
||||||
hexathon~=0.1.0
|
hexathon~=0.1.5
|
||||||
websocket-client==0.57.0
|
websocket-client==0.57.0
|
||||||
potaahto~=0.1.0
|
potaahto~=0.1.1
|
||||||
chainlib~=0.0.12
|
chainlib~=0.1.0
|
||||||
confini~=0.5.1
|
confini~=0.6.0
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = chainlib-eth
|
name = chainlib-eth
|
||||||
version = 0.0.13a1
|
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
|
||||||
@ -48,4 +48,3 @@ console_scripts =
|
|||||||
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-wait = chainlib.eth.runnable.wait:main
|
eth-wait = chainlib.eth.runnable.wait:main
|
||||||
eth = chainlib.eth.runnable.info:main
|
|
||||||
|
@ -50,6 +50,19 @@ class TxTestCase(EthTesterCase):
|
|||||||
self.assertTrue(is_same_address(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):
|
||||||
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||||
gas_oracle = RPCGasOracle(self.rpc)
|
gas_oracle = RPCGasOracle(self.rpc)
|
||||||
|
Loading…
Reference in New Issue
Block a user