From 418c54e9c75d5fa5cbd703a2dfc00958e807f9f8 Mon Sep 17 00:00:00 2001 From: nolash Date: Tue, 24 Aug 2021 17:55:01 +0200 Subject: [PATCH] Add generic wire methods for signer --- chainlib/eth/cli.py | 41 ++++++++++++++++++++++++++++++++++- chainlib/eth/connection.py | 10 ++++----- chainlib/eth/gas.py | 23 +++++++++++++------- chainlib/eth/nonce.py | 7 +++--- chainlib/eth/tx.py | 4 ++-- chainlib/eth/unittest/base.py | 6 ++--- requirements.txt | 4 ++-- setup.cfg | 2 +- 8 files changed, 71 insertions(+), 26 deletions(-) diff --git a/chainlib/eth/cli.py b/chainlib/eth/cli.py index 971b779..c959e03 100644 --- a/chainlib/eth/cli.py +++ b/chainlib/eth/cli.py @@ -17,9 +17,17 @@ from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer # local imports from chainlib.eth.address import AddressChecksum from chainlib.eth.connection import EthHTTPConnection - +from chainlib.eth.gas import ( + OverrideGasOracle, + RPCGasOracle, + ) +from chainlib.eth.nonce import ( + OverrideNonceOracle, + RPCNonceOracle, + ) script_dir = os.path.dirname(os.path.realpath(__file__)) + class Wallet(BaseWallet): """Convenience constructor to set Ethereum defaults for chainlib cli Wallet object @@ -32,10 +40,41 @@ class Wallet(BaseWallet): class Rpc(BaseRpc): """Convenience constructor to set Ethereum defaults for chainlib cli Rpc object + + """ def __init__(self, wallet=None): super(Rpc, self).__init__(EthHTTPConnection, wallet=wallet) + + def connect_by_config(self, config): + """ + + If the standard arguments for nonce and fee price/price have been defined (which generate the configuration keys "_NONCE", "_FEE_PRICE" and "_FEE_LIMIT" respectively) , the corresponding overrides for fee and nonce generators will be defined. + + """ + super(Rpc, self).connect_by_config(config) + + if self.can_sign(): + nonce = config.get('_NONCE') + if nonce != None: + self.nonce_oracle = OverrideNonceOracle(self.get_sender_address(), nonce, id_generator=self.id_generator) + else: + self.nonce_oracle = RPCNonceOracle(self.get_sender_address(), self.conn, id_generator=self.id_generator) + + fee_price = config.get('_FEE_PRICE') + fee_limit = config.get('_FEE_LIMIT') + if fee_price != None or fee_limit != None: + self.fee_oracle = OverrideGasOracle(price=fee_price, limit=fee_limit, conn=self.conn, id_generator=self.id_generator) + else: + self.fee_oracle = RPCGasOracle(self.conn, id_generator=self.id_generator) + + return self.conn + + + 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 diff --git a/chainlib/eth/connection.py b/chainlib/eth/connection.py index 6c30297..5397dfe 100644 --- a/chainlib/eth/connection.py +++ b/chainlib/eth/connection.py @@ -179,13 +179,13 @@ class EthUnixSignerConnection(EthUnixConnection): """Connects rpc signer methods to Unix socket connection interface """ - def sign_transaction_to_rlp(self, tx): + def sign_transaction_to_wire(self, tx): """Sign transaction using unix socket rpc. :param tx: Transaction object :type tx: dict - :rtype: See chainlin.eth.connection.sign_transaction_to_rlp - :returns: See chainlin.eth.connection.sign_transaction_to_rlp + :rtype: See chainlib.eth.connection.sign_transaction_to_rlp + :returns: Serialized signature """ return sign_transaction_to_rlp(self.chain_spec, self.do, tx) @@ -203,13 +203,13 @@ class EthUnixSignerConnection(EthUnixConnection): class EthHTTPSignerConnection(EthHTTPConnection): - def sign_transaction_to_rlp(self, tx): + def sign_transaction_to_wire(self, tx): """Sign transaction using http json-rpc. :param tx: Transaction object :type tx: dict :rtype: See chainlin.eth.connection.sign_transaction_to_rlp - :returns: See chainlin.eth.connection.sign_transaction_to_rlp + :returns: Serialized signature """ return sign_transaction_to_rlp(self.chain_spec, self.do, tx) diff --git a/chainlib/eth/gas.py b/chainlib/eth/gas.py index e56079b..da0c73f 100644 --- a/chainlib/eth/gas.py +++ b/chainlib/eth/gas.py @@ -9,6 +9,7 @@ from hexathon import ( from crypto_dev_signer.eth.transaction import EIP155Transaction # local imports +from chainlib.fee import FeeOracle from chainlib.hash import keccak256_hex_to_hex from chainlib.jsonrpc import JSONRPCRequest from chainlib.eth.tx import ( @@ -100,7 +101,7 @@ class Gas(TxFactory): if data != None: tx['data'] = data txe = EIP155Transaction(tx, tx['nonce'], tx['chainId']) - tx_raw = self.signer.sign_transaction_to_rlp(txe) + tx_raw = self.signer.sign_transaction_to_wire(txe) tx_raw_hex = add_0x(tx_raw.hex()) tx_hash_hex = add_0x(keccak256_hex_to_hex(tx_raw_hex)) @@ -114,7 +115,7 @@ class Gas(TxFactory): -class RPCGasOracle: +class RPCGasOracle(FeeOracle): """JSON-RPC only gas parameter helper. :param conn: RPC connection @@ -128,13 +129,13 @@ class RPCGasOracle: """ def __init__(self, conn, code_callback=None, min_price=1, id_generator=None): + super(RPCGasOracle, self).__init__(code_callback=code_callback) self.conn = conn - self.code_callback = code_callback self.min_price = min_price self.id_generator = id_generator - def get_gas(self, code=None, input_data=None): + def get_fee(self, code=None, input_data=None): """Retrieve gas parameters from node. If code is given, the set code callback will be used to estimate gas usage. @@ -162,6 +163,10 @@ class RPCGasOracle: gas_price = self.min_price return (gas_price, fee_units) + + def get_gas(self, code=None, input_data=None): + return self.get_fee(code=code, input_data=input_data) + class RPCPureGasOracle(RPCGasOracle): """Convenience constructor for rpc gas oracle without minimum price. @@ -213,14 +218,12 @@ class OverrideGasOracle(RPCGasOracle): super(OverrideGasOracle, self).__init__(price_conn, code_callback, id_generator=id_generator) - def get_gas(self, code=None): - """See chainlib.eth.gas.RPCGasOracle. - """ + def get_fee(self, code=None, input_data=None): r = None fee_units = None fee_price = None - rpc_results = super(OverrideGasOracle, self).get_gas(code) + rpc_results = super(OverrideGasOracle, self).get_fee(code) if self.limit != None: fee_units = self.limit @@ -245,4 +248,8 @@ class OverrideGasOracle(RPCGasOracle): return (fee_price, fee_units) + def get_gas(self, code=None, input_data=None): + return self.get_fee(code=code, input_data=input_data) + + DefaultGasOracle = RPCGasOracle diff --git a/chainlib/eth/nonce.py b/chainlib/eth/nonce.py index 46f2e79..f425318 100644 --- a/chainlib/eth/nonce.py +++ b/chainlib/eth/nonce.py @@ -5,6 +5,7 @@ from hexathon import ( ) # local imports +from chainlib.nonce import NonceOracle as BaseNonceOracle from chainlib.jsonrpc import JSONRPCRequest @@ -22,7 +23,6 @@ def nonce(address, confirmed=False, id_generator=None): o = j.template() o['method'] = 'eth_getTransactionCount' o['params'].append(address) - o['params'].append('pending') if confirmed: o['params'].append('latest') else: @@ -34,7 +34,7 @@ def nonce_confirmed(address, id_generator=None): return nonce(address, confirmed=True, id_generator=id_generator) -class NonceOracle: +class NonceOracle(BaseNonceOracle): """Base class for the nonce parameter helpers. :param address: Address to retireve nonce for, in hex @@ -43,9 +43,8 @@ class NonceOracle: :type id_generator: chainlib.connection.JSONRPCIdGenerator """ def __init__(self, address, id_generator=None): - self.address = address self.id_generator = id_generator - self.nonce = self.get_nonce() + super(NonceOracle, self).__init__(address) def get_nonce(self): diff --git a/chainlib/eth/tx.py b/chainlib/eth/tx.py index 9a7842a..7b0ee86 100644 --- a/chainlib/eth/tx.py +++ b/chainlib/eth/tx.py @@ -299,7 +299,7 @@ class TxFactory: :param chain_spec: Chain spec to use for signer. :type chain_spec: chainlib.chain.ChainSpec :param signer: Signer middleware. - :type param: Object implementing interface ofchainlib.eth.connection.sign_transaction_to_rlp. + :type param: Object implementing interface ofchainlib.eth.connection.sign_transaction_to_wire :param gas_oracle: Backend to generate gas parameters :type gas_oracle: Object implementing chainlib.eth.gas.GasOracle interface :param nonce_oracle: Backend to generate gas parameters @@ -328,7 +328,7 @@ class TxFactory: if tx['to'] == None or tx['to'] == '': tx['to'] = '0x' txe = EIP155Transaction(tx, tx['nonce'], tx['chainId']) - tx_raw = self.signer.sign_transaction_to_rlp(txe) + tx_raw = self.signer.sign_transaction_to_wire(txe) tx_raw_hex = add_0x(tx_raw.hex()) tx_hash_hex = add_0x(keccak256_hex_to_hex(tx_raw_hex)) return (tx_hash_hex, tx_raw_hex) diff --git a/chainlib/eth/unittest/base.py b/chainlib/eth/unittest/base.py index 48eb811..e10d11b 100644 --- a/chainlib/eth/unittest/base.py +++ b/chainlib/eth/unittest/base.py @@ -176,7 +176,7 @@ class TestRPCConnection(RPCConnection): tx_dict = p[0] tx = EIP155Transaction(tx_dict, tx_dict['nonce'], tx_dict['chainId']) passphrase = p[1] - r = self.signer.sign_transaction_to_rlp(tx, passphrase) + r = self.signer.sign_transaction_to_wire(tx, passphrase) return r @@ -192,9 +192,9 @@ class TestRPCConnection(RPCConnection): return self.signer.sign_transaction(tx, passphrase) - def sign_transaction_to_rlp(self, tx, passphrase=''): + def sign_transaction_to_wire(self, tx, passphrase=''): self.__verify_signer(tx, passphrase) - return self.signer.sign_transaction_to_rlp(tx, passphrase) + return self.signer.sign_transaction_to_wire(tx, passphrase) def disconnect(self): diff --git a/requirements.txt b/requirements.txt index 0ab89d1..4c58e30 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ -crypto-dev-signer>=0.4.14b7,<=0.4.14 +crypto-dev-signer>=0.4.15a1,<=0.4.15 pysha3==1.0.2 hexathon~=0.0.1a8 websocket-client==0.57.0 potaahto~=0.0.1a1 -chainlib==0.0.8a2 +chainlib==0.0.9a2 confini>=0.4.1a1,<0.5.0 diff --git a/setup.cfg b/setup.cfg index 8301435..b1346a5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = chainlib-eth -version = 0.0.8a2 +version = 0.0.9a2 description = Ethereum implementation of the chainlib interface author = Louis Holbrook author_email = dev@holbrook.no