Implement chainlib cli util

This commit is contained in:
nolash 2021-07-30 08:13:47 +02:00
parent 3fd2f1d6b7
commit c02ad2404d
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
6 changed files with 119 additions and 199 deletions

1
python/MANIFEST.in Normal file
View File

@ -0,0 +1 @@
include *requirements.txt **/data/*.json **/data/*.bin

View File

@ -13,17 +13,8 @@ import argparse
import logging import logging
# external imports # external imports
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer import chainlib.eth.cli
from crypto_dev_signer.keystore.dict import DictKeystore
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from chainlib.eth.nonce import (
RPCNonceOracle,
OverrideNonceOracle,
)
from chainlib.eth.gas import (
RPCGasOracle,
OverrideGasOracle,
)
from chainlib.eth.connection import EthHTTPConnection from chainlib.eth.connection import EthHTTPConnection
from chainlib.eth.tx import receipt from chainlib.eth.tx import receipt
@ -33,80 +24,39 @@ from eth_contract_registry.registry import ContractRegistry
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger() logg = logging.getLogger()
script_dir = os.path.dirname(__file__) arg_flags = chainlib.eth.cli.argflag_std_write
data_dir = os.path.join(script_dir, '..', 'data') argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
argparser = argparse.ArgumentParser()
argparser.add_argument('-p', '--provider', dest='p', default='http://localhost:8545', type=str, help='Web3 provider url (http only)')
argparser.add_argument('-w', action='store_true', help='Wait for the last transaction to be confirmed')
argparser.add_argument('-ww', action='store_true', help='Wait for every transaction to be confirmed')
argparser.add_argument('-i', '--chain-spec', dest='i', type=str, default='evm:ethereum:1', help='Chain specification string')
argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing')
argparser.add_argument('-v', action='store_true', help='Be verbose')
argparser.add_argument('-vv', action='store_true', help='Be more verbose')
argparser.add_argument('-d', action='store_true', help='Dump RPC calls to terminal and do not send')
argparser.add_argument('--gas-price', type=int, dest='gas_price', help='Override gas price')
argparser.add_argument('--nonce', type=int, help='Override transaction nonce')
argparser.add_argument('--identifier', type=str, action='append', default=[], help='Add contract identifier') argparser.add_argument('--identifier', type=str, action='append', default=[], help='Add contract identifier')
argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration')
args = argparser.parse_args() args = argparser.parse_args()
if args.vv: extra_args = {
logg.setLevel(logging.DEBUG) 'identifier': None,
elif args.v: }
logg.setLevel(logging.INFO) config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args=extra_args, default_fee_limit=ContractRegistry.gas())
block_all = args.ww wallet = chainlib.eth.cli.Wallet()
block_last = args.w or block_all wallet.from_config(config)
passphrase_env = 'ETH_PASSPHRASE' rpc = chainlib.eth.cli.Rpc(wallet=wallet)
if args.env_prefix != None: conn = rpc.connect_by_config(config)
passphrase_env = args.env_prefix + '_' + passphrase_env
passphrase = os.environ.get(passphrase_env)
if passphrase == None:
logg.warning('no passphrase given')
passphrase=''
signer_address = None chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
keystore = DictKeystore()
if args.y != None:
logg.debug('loading keystore file {}'.format(args.y))
signer_address = keystore.import_keystore_file(args.y, password=passphrase)
logg.debug('now have key for signer address {}'.format(signer_address))
signer = EIP155Signer(keystore)
chain_spec = ChainSpec.from_chain_str(args.i)
rpc = EthHTTPConnection(args.p)
nonce_oracle = None
if args.nonce != None:
nonce_oracle = OverrideNonceOracle(signer_address, args.nonce)
else:
nonce_oracle = RPCNonceOracle(signer_address, rpc)
gas_oracle = None
if args.gas_price !=None:
gas_oracle = OverrideGasOracle(price=args.gas_price, conn=rpc, code_callback=ContractRegistry.gas)
else:
gas_oracle = RPCGasOracle(rpc, code_callback=ContractRegistry.gas)
dummy = args.d
identifiers = args.identifier
if 'ContractRegistry' not in identifiers:
identifiers = ['ContractRegistry'] + identifiers
logg.debug('adding identifiers {}'.format(identifiers))
def main(): def main():
signer = rpc.get_signer()
signer_address = rpc.get_sender_address()
gas_oracle = rpc.get_gas_oracle()
nonce_oracle = rpc.get_nonce_oracle()
c = ContractRegistry(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle) c = ContractRegistry(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle)
(tx_hash_hex, o) = c.constructor(signer_address, identifiers) (tx_hash_hex, o) = c.constructor(signer_address, config.get('_IDENTIFIER'))
if dummy:
print(tx_hash_hex) if config.get('_RPC_SEND'):
print(o) conn.do(o)
else: if config.get('_WAIT'):
rpc.do(o) r = conn.wait(tx_hash_hex)
if block_last:
r = rpc.wait(tx_hash_hex)
if r['status'] == 0: if r['status'] == 0:
sys.stderr.write('EVM revert while deploying contract. Wish I had more to tell you') sys.stderr.write('EVM revert while deploying contract. Wish I had more to tell you')
sys.exit(1) sys.exit(1)
@ -116,6 +66,8 @@ def main():
print(address) print(address)
else: else:
print(tx_hash_hex) print(tx_hash_hex)
else:
print(o)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -12,16 +12,18 @@ import json
import argparse import argparse
import logging import logging
# third-party imports # external imports
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer import chainlib.eth.cli
from crypto_dev_signer.keystore.dict import DictKeystore
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.gas import RPCGasOracle
from chainlib.eth.connection import EthHTTPConnection from chainlib.eth.connection import EthHTTPConnection
from chainlib.eth.tx import receipt from chainlib.eth.tx import receipt
from chainlib.eth.constant import ZERO_CONTENT from chainlib.eth.constant import ZERO_CONTENT
from chainlib.error import JSONRPCException from chainlib.error import JSONRPCException
from chainlib.eth.address import to_checksum_address
from hexathon import (
add_0x,
strip_0x,
)
# local imports # local imports
from eth_contract_registry.registry import ContractRegistry from eth_contract_registry.registry import ContractRegistry
@ -29,58 +31,44 @@ from eth_contract_registry.registry import ContractRegistry
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger() logg = logging.getLogger()
script_dir = os.path.dirname(__file__) arg_flags = chainlib.eth.cli.argflag_std_read | chainlib.eth.cli.Flag.EXEC
data_dir = os.path.join(script_dir, '..', 'data') argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
default_format = 'terminal'
argparser = argparse.ArgumentParser()
argparser.add_argument('-p', '--provider', dest='p', default='http://localhost:8545', type=str, help='RPC provider url (http only)')
argparser.add_argument('-i', '--chain-spec', dest='i', type=str, default='evm:ethereum:1', help='Chain specification string')
argparser.add_argument('-r', '--registry', dest='r', required=True, type=str, help='Contract registry address')
argparser.add_argument('-f', '--format', dest='f', type=str, default=default_format, help='Output format [human, brief]')
argparser.add_argument('-v', action='store_true', help='Be verbose')
argparser.add_argument('-vv', action='store_true', help='Be more verbose')
argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration')
argparser.add_argument('identifier', type=str, nargs='?', help='Token symbol to return address for') argparser.add_argument('identifier', type=str, nargs='?', help='Token symbol to return address for')
args = argparser.parse_args() args = argparser.parse_args()
if args.vv: extra_args = {
logg.setLevel(logging.DEBUG) 'identifier': None,
elif args.v: }
logg.setLevel(logging.INFO) config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args=extra_args, default_fee_limit=ContractRegistry.gas())
chain_spec = ChainSpec.from_chain_str(args.i) wallet = chainlib.eth.cli.Wallet()
wallet.from_config(config)
rpc = EthHTTPConnection(args.p) rpc = chainlib.eth.cli.Rpc(wallet=wallet)
registry_address = args.r conn = rpc.connect_by_config(config)
identifier = args.identifier
fmt = args.f chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
def out_element(e, fmt=default_format, w=sys.stdout): def out_element(e, w=sys.stdout):
logg.debug('format {}'.format(fmt)) w.write(e[0] + '\t' + e[1] + '\n')
if fmt == 'brief':
w.write(e[1] + '\n')
else:
w.write('{} {}\n'.format(e[0], e[1]))
def element(ifc, identifier, fmt=default_format, w=sys.stdout): def element(ifc, conn, registry_address, identifier, w=sys.stdout):
o = ifc.address_of(registry_address, identifier) o = ifc.address_of(registry_address, identifier)
r = rpc.do(o) r = conn.do(o)
address = ifc.parse_address_of(r) address = ifc.parse_address_of(r)
out_element((identifier, address), fmt, w) out_element((identifier, address), w)
def ls(ifc, fmt=default_format, w=sys.stdout): def ls(ifc, conn, registry_address, w=sys.stdout):
i = 0 i = 0
while True: while True:
o = ifc.identifier(registry_address, i) o = ifc.identifier(registry_address, i)
try: try:
r = rpc.do(o) r = conn.do(o)
identifier = ifc.parse_identifier(r) identifier = ifc.parse_identifier(r)
element(ifc, identifier, fmt, w) element(ifc, conn, registry_address, identifier, w)
i += 1 i += 1
except JSONRPCException: except JSONRPCException:
break break
@ -88,10 +76,17 @@ def ls(ifc, fmt=default_format, w=sys.stdout):
def main(): def main():
c = ContractRegistry(chain_spec) c = ContractRegistry(chain_spec)
identifier = config.get('_IDENTIFIER')
registry_address = to_checksum_address(config.get('_EXEC_ADDRESS'))
if not config.true('_UNSAFE') and registry_address != add_0x(config.get('_EXEC_ADDRESS')):
raise ValueError('invalid checksum address for contract')
if identifier != None: if identifier != None:
element(c, identifier, fmt=fmt, w=sys.stdout) element(c, conn, identifier, registry_address, w=sys.stdout)
else: else:
ls(c, fmt=fmt, w=sys.stdout) ls(c, conn, registry_address, w=sys.stdout)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -13,20 +13,16 @@ import argparse
import logging import logging
# external imports # external imports
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer import chainlib.eth.cli
from crypto_dev_signer.keystore.dict import DictKeystore
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from chainlib.eth.nonce import (
RPCNonceOracle,
OverrideNonceOracle,
)
from chainlib.eth.gas import (
RPCGasOracle,
OverrideGasOracle,
)
from chainlib.eth.connection import EthHTTPConnection from chainlib.eth.connection import EthHTTPConnection
from chainlib.eth.tx import receipt from chainlib.eth.tx import receipt
from chainlib.eth.constant import ZERO_CONTENT from chainlib.eth.constant import ZERO_CONTENT
from chainlib.eth.address import to_checksum_address
from hexathon import (
add_0x,
strip_0x,
)
# local imports # local imports
from eth_contract_registry.registry import ContractRegistry from eth_contract_registry.registry import ContractRegistry
@ -34,89 +30,65 @@ from eth_contract_registry.registry import ContractRegistry
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger() logg = logging.getLogger()
script_dir = os.path.dirname(__file__) arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC
data_dir = os.path.join(script_dir, '..', 'data') argparser = chainlib.eth.cli.ArgumentParser(arg_flags)
argparser.add_argument('--chain-hash', type=str, dest='chain_hash', default=ZERO_CONTENT, help='Chain config hash to use for entry')
argparser = argparse.ArgumentParser() argparser.add_argument('--identifier', required=True, type=str, help='Contract identifier to set')
argparser.add_argument('-p', '--provider', dest='p', default='http://localhost:8545', type=str, help='Web3 provider url (http only)') argparser.add_positional('address', type=str, help='Contract address to set for identifier')
argparser.add_argument('-w', action='store_true', help='Wait for the last transaction to be confirmed')
argparser.add_argument('-ww', action='store_true', help='Wait for every transaction to be confirmed')
argparser.add_argument('-i', '--chain-spec', dest='i', type=str, default='evm:ethereum:1', help='Chain specification string')
argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing')
argparser.add_argument('-r', '--registry', dest='r', type=str, help='Contract registry address')
argparser.add_argument('-v', action='store_true', help='Be verbose')
argparser.add_argument('-vv', action='store_true', help='Be more verbose')
argparser.add_argument('-d', action='store_true', help='Dump RPC calls to terminal and do not send')
argparser.add_argument('--gas-price', type=int, dest='gas_price', help='Override gas price')
argparser.add_argument('--nonce', type=int, help='Override transaction nonce')
argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration')
argparser.add_argument('identifier', type=str, help='Contract registry identifier')
argparser.add_argument('address', type=str, help='Address to set for identifier')
args = argparser.parse_args() args = argparser.parse_args()
if args.vv: extra_args = {
logg.setLevel(logging.DEBUG) 'chain_hash': None,
elif args.v: 'identifier': None,
logg.setLevel(logging.INFO) 'address': None,
}
config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args=extra_args, default_fee_limit=ContractRegistry.gas())
block_all = args.ww wallet = chainlib.eth.cli.Wallet()
block_last = args.w or block_all wallet.from_config(config)
passphrase_env = 'ETH_PASSPHRASE' rpc = chainlib.eth.cli.Rpc(wallet=wallet)
if args.env_prefix != None: conn = rpc.connect_by_config(config)
passphrase_env = args.env_prefix + '_' + passphrase_env
passphrase = os.environ.get(passphrase_env)
if passphrase == None:
logg.warning('no passphrase given')
passphrase=''
signer_address = None chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
keystore = DictKeystore()
if args.y != None:
logg.debug('loading keystore file {}'.format(args.y))
signer_address = keystore.import_keystore_file(args.y, password=passphrase)
logg.debug('now have key for signer address {}'.format(signer_address))
signer = EIP155Signer(keystore)
chain_spec = ChainSpec.from_chain_str(args.i)
rpc = EthHTTPConnection(args.p)
nonce_oracle = None
if args.nonce != None:
nonce_oracle = OverrideNonceOracle(signer_address, args.nonce)
else:
nonce_oracle = RPCNonceOracle(signer_address, rpc)
gas_oracle = None
if args.gas_price !=None:
gas_oracle = OverrideGasOracle(price=args.gas_price, conn=rpc, code_callback=ContractRegistry.gas)
else:
gas_oracle = RPCGasOracle(rpc, code_callback=ContractRegistry.gas)
dummy = args.d
registry_address = args.r
if registry_address == None:
raise ValueError('Registry address must be set')
identifier = args.identifier
address = args.address
def main(): def main():
signer = rpc.get_signer()
signer_address = rpc.get_sender_address()
gas_oracle = rpc.get_gas_oracle()
nonce_oracle = rpc.get_nonce_oracle()
c = ContractRegistry(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle) c = ContractRegistry(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle)
(tx_hash_hex, o) = c.set(registry_address, signer_address, identifier, address, chain_spec, ZERO_CONTENT)
if dummy: subject_address = to_checksum_address(config.get('_ADDRESS'))
print(tx_hash_hex) if not config.true('_UNSAFE') and subject_address != add_0x(config.get('_ADDRESS')):
print(o) raise ValueError('invalid checksum address for subject_address')
else:
rpc.do(o) registry_address = to_checksum_address(config.get('_EXEC_ADDRESS'))
if block_last: if not config.true('_UNSAFE') and registry_address != add_0x(config.get('_EXEC_ADDRESS')):
r = rpc.wait(tx_hash_hex) raise ValueError('invalid checksum address for contract')
chain_config_hash = config.get('_CHAIN_HASH')
chain_config_hash_bytes = bytes.fromhex(strip_0x(chain_config_hash))
if len(chain_config_hash_bytes) != 32:
raise ValueError('chain config hash must be 32 bytes')
chain_config_hash = add_0x(chain_config_hash)
(tx_hash_hex, o) = c.set(registry_address, signer_address, config.get('_IDENTIFIER'), subject_address, chain_spec, chain_config_hash)
if config.get('_RPC_SEND'):
conn.do(o)
if config.get('_WAIT'):
r = conn.wait(tx_hash_hex)
if r['status'] == 0: if r['status'] == 0:
sys.stderr.write('EVM revert while deploying contract. Wish I had more to tell you') sys.stderr.write('EVM revert while deploying contract. Wish I had more to tell you')
sys.exit(1) sys.exit(1)
print(tx_hash_hex) print(tx_hash_hex)
else:
print(o)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -1,3 +1,3 @@
confini~=0.3.6rc3 confini>=0.3.6rc3,<0.5.0
crypto-dev-signer~=0.4.14b6 crypto-dev-signer>=0.4.14b7,<0.4.14
chainlib-eth~=0.0.5a1 chainlib-eth>=0.0.7a4,<=0.1.0

View File

@ -1,6 +1,6 @@
[metadata] [metadata]
name = eth-contract-registry name = eth-contract-registry
version = 0.5.6a1 version = 0.6.1a1
description = Ethereum Smart Contract key-value registry description = Ethereum Smart Contract key-value registry
author = Louis Holbrook author = Louis Holbrook
author_email = dev@holbrook.no author_email = dev@holbrook.no