2021-08-21 09:31:59 +02:00
|
|
|
# standard imports
|
|
|
|
import logging
|
|
|
|
|
|
|
|
# external imports
|
|
|
|
from chainlib.chain import ChainSpec
|
|
|
|
from chainlib.connection import RPCConnection
|
|
|
|
from chainlib.jsonrpc import IntSequenceGenerator
|
2021-08-24 17:49:35 +02:00
|
|
|
from chainlib.nonce import NonceOracle
|
|
|
|
from chainlib.fee import FeeOracle
|
2021-08-21 09:31:59 +02:00
|
|
|
from chainlib.error import SignerMissingException
|
|
|
|
|
|
|
|
logg = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class Rpc:
|
2021-08-23 08:47:01 +02:00
|
|
|
"""Convenience wrapper to build rpc connection from processed configuration values.
|
|
|
|
|
|
|
|
:param cls: RPC connection class to instantiate
|
|
|
|
:type cls: chainlib.connection.RPCConnection implementation
|
|
|
|
:param wallet: Add wallet backend to instance
|
|
|
|
:type wallet: chainlib.cli.wallet.Wallet
|
|
|
|
"""
|
2021-08-21 09:31:59 +02:00
|
|
|
|
|
|
|
def __init__(self, cls, wallet=None):
|
|
|
|
self.constructor = cls
|
|
|
|
self.id_generator = None
|
|
|
|
self.conn = None
|
|
|
|
self.chain_spec = None
|
|
|
|
self.wallet = wallet
|
|
|
|
self.nonce_oracle = None
|
2021-08-23 08:47:01 +02:00
|
|
|
self.fee_oracle = None
|
2021-08-26 17:08:45 +02:00
|
|
|
self.error_parser = None
|
2021-08-21 09:31:59 +02:00
|
|
|
|
|
|
|
|
|
|
|
def connect_by_config(self, config):
|
2021-08-23 08:47:01 +02:00
|
|
|
"""Create a connection using the provided configuration, as rendered by chainlib.cli.config.Config.
|
|
|
|
|
|
|
|
The connection url string is fetched from the "RPC_HTTP_PROVIDER" configuration key. Currently only HTTP connection is supported. Basic HTTP auth is supported using the "RPC_HTTP_USERNAME" and "RPC_HTTP_PASSWORD" keys together with "RPC_HTTP_AUTHENTICATION" set to "basic".
|
|
|
|
|
|
|
|
The "CHAIN_SPEC" value is used for the chain context of the connection.
|
|
|
|
|
2021-08-24 17:49:35 +02:00
|
|
|
If the sequence flag was set in the configuration (which generates the configuration key "_SEQ"), a sequential integer generator will be used for rpc ids. Otherwise uuids will be used.
|
2021-08-23 08:47:01 +02:00
|
|
|
|
|
|
|
|
|
|
|
:param config: Processed configuration
|
|
|
|
:type config: confini.Config
|
|
|
|
:rtype: chainlib.connection.RPCConnection
|
|
|
|
:returns: An established rpc connection
|
|
|
|
"""
|
2021-09-13 08:47:00 +02:00
|
|
|
if config.get('RPC_SCHEME') != 'http':
|
|
|
|
raise NotImplementedError('Only http(s) scheme is implemented for RPC connections at this time')
|
|
|
|
|
2021-08-21 09:31:59 +02:00
|
|
|
auth = None
|
2021-09-01 09:38:24 +02:00
|
|
|
if config.get('RPC_AUTH') == 'basic':
|
2021-08-21 09:31:59 +02:00
|
|
|
from chainlib.auth import BasicAuth
|
2021-09-01 09:38:24 +02:00
|
|
|
auth_parts = config.get('RPC_CREDENTIALS').split(':')
|
|
|
|
auth = BasicAuth(auth_parts[0], auth_parts[1])
|
2021-08-21 09:31:59 +02:00
|
|
|
logg.debug('using basic http auth')
|
|
|
|
|
|
|
|
if config.get('_SEQ'):
|
|
|
|
self.id_generator = IntSequenceGenerator()
|
|
|
|
|
|
|
|
self.chain_spec = config.get('CHAIN_SPEC')
|
2021-09-13 08:47:00 +02:00
|
|
|
self.conn = self.constructor(url=config.get('RPC_PROVIDER'), chain_spec=self.chain_spec, auth=auth)
|
2021-08-21 09:31:59 +02:00
|
|
|
|
|
|
|
return self.conn
|
|
|
|
|
|
|
|
|
|
|
|
def get_nonce_oracle(self):
|
2021-08-23 08:47:01 +02:00
|
|
|
"""Nonce oracle getter.
|
|
|
|
|
|
|
|
:rtype: chainlib.nonce.NonceOracle
|
|
|
|
:returns: Nonce oracle
|
|
|
|
"""
|
2021-08-21 09:31:59 +02:00
|
|
|
return self.nonce_oracle
|
|
|
|
|
|
|
|
|
2021-08-23 08:47:01 +02:00
|
|
|
def get_fee_oracle(self):
|
|
|
|
"""Fee oracle getter.
|
|
|
|
|
|
|
|
:rtype: chainlib.fee.FeeOracle
|
|
|
|
:returns: Fee oracle
|
|
|
|
"""
|
|
|
|
return self.fee_oracle
|
2021-08-21 09:31:59 +02:00
|
|
|
|
|
|
|
|
|
|
|
def can_sign(self):
|
2021-08-23 08:47:01 +02:00
|
|
|
"""Check if instance has signer capability.
|
|
|
|
|
|
|
|
:rtype: bool
|
|
|
|
:returns: True if signing is possible
|
|
|
|
"""
|
2021-08-21 09:31:59 +02:00
|
|
|
return self.wallet != None and self.wallet.signer != None
|
|
|
|
|
|
|
|
|
|
|
|
def get_signer(self):
|
2021-08-23 08:47:01 +02:00
|
|
|
"""Signer getter.
|
|
|
|
|
|
|
|
:raises chainlib.error.SignerMissingException: Instance has no signer defined
|
|
|
|
:rtype: Signer implementation (todo: define base interface class)
|
|
|
|
:returns: Signer
|
|
|
|
"""
|
2021-08-21 09:31:59 +02:00
|
|
|
if self.wallet.signer == None:
|
|
|
|
raise SignerMissingException()
|
|
|
|
return self.wallet.signer
|
|
|
|
|
|
|
|
|
|
|
|
def get_sender_address(self):
|
2021-08-23 08:47:01 +02:00
|
|
|
"""Wallet address getter.
|
|
|
|
|
|
|
|
:raises AttributeError: Instance has no signed defined
|
|
|
|
:rtype: str
|
|
|
|
:returns: Wallet address in canonical string representation
|
|
|
|
"""
|
2021-08-21 09:31:59 +02:00
|
|
|
return self.wallet.signer_address
|
2021-10-06 07:14:31 +02:00
|
|
|
|
|
|
|
|
|
|
|
def get_signer_address(self):
|
|
|
|
return self.get_sender_address()
|