Ejemplo n.º 1
0
    def __init__(self, identifier, verkey=None, rawVerkey=None):
        self.abbreviated = None
        if (verkey is None or verkey == '') and (rawVerkey is None
                                                 or rawVerkey == ''):
            if identifier:
                self._identifier = identifier
                if (verkey is None and rawVerkey is None):
                    self._verkey = None
                else:
                    self._verkey = ''
                return

        assert (verkey or rawVerkey) and not (verkey and rawVerkey)
        if identifier:
            self._identifier = identifier
            if rawVerkey:
                self._verkey = rawToFriendly(rawVerkey)
                self.abbreviated = False
            else:
                if verkey.startswith("~"):
                    self._verkey = verkey[1:]
                    self.abbreviated = True
                else:
                    self._verkey = verkey
                    self.abbreviated = False
        else:
            verraw = rawVerkey or friendlyToRaw(verkey)
            self._identifier = rawToFriendly(verraw[:16])
            self._verkey = rawToFriendly(verraw[16:])
            self.abbreviated = True
Ejemplo n.º 2
0
def add_agent_uids(agents: [WalletedAgent]) -> None:
    """
    Add various unique identifiers related to an agent from a list of agents, to the local database mapping those
    random looking values to friendly names.
    :param agents: List of instances of the WalletedAgent class.
    """
    logging.info("Start adding unique identifiers from agents {}".format(
        [agent.name for agent in agents]))
    for agent in agents:
        add_uid_to_dictionary(agent.client.name,
                              "{} {}".format(agent.name, "client name"), True)
        add_uid_to_dictionary(agent.client.alias,
                              "{} {}".format(agent.name, "client alias"), True)
        # Note that agent.client.nodestack.name == rawToFriendly(agent.client.nodestack.verKeyRaw)
        add_uid_to_dictionary(
            agent.client.nodestack.name,
            "{} {}".format(agent.name, "client nodestack verkey"), True)
        add_uid_to_dictionary(
            rawToFriendly(agent.client.nodestack.publicKeyRaw),
            "{} {}".format(agent.name, "client nodestack pubkey"), True)
        if agent.endpoint:
            add_uid_to_dictionary(
                rawToFriendly(agent.endpoint.verKeyRaw),
                "{} {}".format(agent.name, "endpoint verkey"), True)
            add_uid_to_dictionary(
                rawToFriendly(agent.endpoint.publicKeyRaw),
                "{} {}".format(agent.name, "endpoint pubkey"), True)
            add_uid_to_dictionary(
                rawToFriendly(z85decode(agent.endpoint.sigKey)),
                "{} {}".format(agent.name, "endpoint sigkey"), True)
        add_wallet_uids(agent.wallet, agent.name)
    logging.info("Finished adding unique identifiers from agents {}".format(
        [agent.name for agent in agents]))
Ejemplo n.º 3
0
    def __init__(self, identifier, verkey=None, rawVerkey=None):
        self.abbreviated = None
        if (verkey is None or verkey == '') and (rawVerkey is None or rawVerkey == ''):
            if identifier:
                self._identifier = identifier
                if (verkey is None and rawVerkey is None):
                    self._verkey = None
                else:
                    self._verkey = ''
                return

        if not ((verkey or rawVerkey) and not (verkey and rawVerkey)):
            raise ValueError(
                "Both verkey {} and rawVerkey {} can't be specified"
                .format(verkey, rawVerkey)
            )

        if identifier:
            self._identifier = identifier
            if rawVerkey:
                self._verkey = rawToFriendly(rawVerkey)
                self.abbreviated = False
            else:
                if verkey.startswith("~"):
                    self._verkey = verkey[1:]
                    self.abbreviated = True
                else:
                    self._verkey = verkey
                    self.abbreviated = False
        else:
            verraw = rawVerkey or friendlyToRaw(verkey)
            self._identifier = rawToFriendly(verraw[:16])
            self._verkey = rawToFriendly(verraw[16:])
            self.abbreviated = True
Ejemplo n.º 4
0
    def __init__(self, identifier, verkey=None, rawVerkey=None):
        self.abbreviated = None
        if (verkey is None or verkey == '') and (rawVerkey is None
                                                 or rawVerkey == ''):
            if identifier:
                self._identifier = identifier
                if (verkey is None and rawVerkey is None):
                    self._verkey = None
                else:
                    self._verkey = ''
                return

        if not ((verkey or rawVerkey) and not (verkey and rawVerkey)):
            raise ValueError(
                "Both verkey {} and rawVerkey {} can't be specified".format(
                    verkey, rawVerkey))

        if identifier:
            self._identifier = identifier
            if rawVerkey:
                self._verkey = rawToFriendly(rawVerkey)
                self.abbreviated = False
            else:
                if verkey.startswith("~"):
                    self._verkey = verkey[1:]
                    self.abbreviated = True
                else:
                    self._verkey = verkey
                    self.abbreviated = False
        else:
            verraw = rawVerkey or friendlyToRaw(verkey)
            self._identifier = rawToFriendly(verraw[:16])
            self._verkey = rawToFriendly(verraw[16:])
            self.abbreviated = True
Ejemplo n.º 5
0
    def __init__(self, identifier=None, seed=None, alias=None):
        """
        Initialize the signer with an identifier and a seed.

        :param identifier: some identifier that directly or indirectly
        references this client
        :param seed: the seed used to generate a signing key.
        """

        # should be stored securely/privately
        self.seed = seed if seed else randombytes(32)

        # generates key pair based on seed
        self.sk = SigningKey(seed=self.seed)

        # helper for signing
        self.naclSigner = NaclSigner(self.sk)

        verraw = self.naclSigner.verraw

        if identifier:
            self._identifier = identifier
            self._verkey = rawToFriendly(verraw)
            self.abbreviated = False
        else:
            self._identifier = rawToFriendly(verraw[:16])
            self._verkey = rawToFriendly(verraw[16:])
            self.abbreviated = True

        self._alias = alias
Ejemplo n.º 6
0
 def __init__(self, identifier, verkey=None, rawVerkey=None):
     assert (verkey or rawVerkey) and not (verkey and rawVerkey)
     if identifier:
         self._identifier = identifier
         self._verkey = verkey or rawToFriendly(rawVerkey)
         self.abbreviated = False
     else:
         verraw = rawVerkey or friendlyToRaw(verkey)
         self._identifier = rawToFriendly(verraw[:16])
         self._verkey = rawToFriendly(verraw[16:])
         self.abbreviated = True
Ejemplo n.º 7
0
def testSendNymFailsIfAbbrevVerkeySizeIs17Bytes(
        looper, sdk_pool_handle, txnPoolNodeSet, nym_request, sdk_wallet_trustee):
    parameters = {
        'dest': rawToFriendly(randombytes(16)),
        'verkey': '~' + rawToFriendly(randombytes(17)),
        'role': TRUST_ANCHOR
    }
    nym_request[OPERATION].update(parameters)
    request_couple = sdk_sign_and_send_prepared_request(looper, sdk_wallet_trustee,
                                                        sdk_pool_handle, json.dumps(nym_request))
    sdk_get_and_check_replies(looper, [request_couple])
Ejemplo n.º 8
0
def testSendNymFailsIfAbbrevVerkeySizeIs17Bytes(
        be, do, poolNodesStarted, trusteeCli):

    parameters = {
        'dest': rawToFriendly(randombytes(16)),
        'verkey': '~' + rawToFriendly(randombytes(17)),
        'role': Roles.TRUST_ANCHOR.name
    }

    be(trusteeCli)
    do('send NYM dest={dest} role={role}',
       mapper=parameters, expect=ERROR, within=2)
def testSendNymFailsIfAbbrevVerkeySizeIs17Bytes(
        be, do, poolNodesStarted, trusteeCli):

    parameters = {
        'dest': rawToFriendly(randombytes(16)),
        'verkey': '~' + rawToFriendly(randombytes(17)),
        'role': Roles.TRUST_ANCHOR.name
    }

    be(trusteeCli)
    do('send NYM dest={dest} role={role}',
       mapper=parameters, expect=ERROR, within=2)
Ejemplo n.º 10
0
def find_z85_uid_in_record(record: logging.LogRecord) -> [(str, str)]:
    """
    Generate a list of z85 encoded unique identifiers.
    :param record: Log record to be analysed.
    :return: List of pairs of the original string with the decoded string.
    """
    matches = []
    for (method, search_string) in [
        (LedgerManager.processLedgerStatus,
         "(b'[{}]{{40}}')".format(Z85_CHARACTERS)),
        (Node.processClientInBox,
         "processing (b'[{}]{{40}}') request".format(Z85_CHARACTERS)),
        (Node.handleOneNodeMsg,
         "'{}': '([{}]{{40}})'".format(f.SENDER_CLIENT.nm, Z85_CHARACTERS)),
        (Node.send, "'{}': '([{}]+?)'".format(f.SENDER_CLIENT.nm,
                                              Z85_CHARACTERS)),
        (Node.validateNodeMsg,
         "'{}': '([{}]{{40}})'".format(f.SENDER_CLIENT.nm, Z85_CHARACTERS)),
        (Node.postToNodeInBox,
         "'{}': '([{}]{{40}})'".format(f.SENDER_CLIENT.nm, Z85_CHARACTERS)),
        (Node.processClientInBox,
         "processing (b'[{}]{{40}}') request".format(Z85_CHARACTERS)),
        (Node.processRequest, "from (b'[{}]{{40}}')$".format(Z85_CHARACTERS)),
        (Node.processPropagate,
         "'{}': '([{}]{{40}})'".format(f.SENDER_CLIENT.nm, Z85_CHARACTERS)),
        (Node.processPropagate,
         "from (b'[{}]{{40}}')$".format(f.SENDER_CLIENT.nm, Z85_CHARACTERS)),
        (Propagator.propagate,
         "from client ([{}]{{40}})$".format(Z85_CHARACTERS)),
        (Propagator.propagate,
         "from client (b'[{}]{{40}}')$".format(Z85_CHARACTERS)),
        (Walleted.handleEndpointMessage,
         "(b'[{}]{{40}}')".format(Z85_CHARACTERS)),
        (ZStack.handlePingPong,
         "got ping from (b'[{}]{{40}}')".format(Z85_CHARACTERS)),
        (ZStack.sendPingPong, "(b'[{}]{{40}}')".format(Z85_CHARACTERS))
    ]:
        if match_method(record, method):
            search_result = re.search(search_string, record.msg)
            if search_result:
                if search_result.group(1).startswith("b'"):
                    friendly_public_key = rawToFriendly(
                        z85decode(search_result.group(1)[2:42]))
                else:
                    friendly_public_key = rawToFriendly(
                        z85decode(search_result.group(1)))
                assert not friendly_public_key.startswith("b'")
                matches.append((search_result.group(1), friendly_public_key))

    return matches
Ejemplo n.º 11
0
 def full_verkey(self):
     if self.abbreviated:
         rtn = friendlyToRaw(self.identifier)
         rtn += friendlyToRaw(self.verkey[1:])
         return rawToFriendly(rtn)
     else:
         return self.verkey
Ejemplo n.º 12
0
 def full_verkey(self):
     if self.abbreviated:
         rtn = friendlyToRaw(self.identifier)
         rtn += friendlyToRaw(self.verkey[1:])
         return rawToFriendly(rtn)
     else:
         return self.verkey
Ejemplo n.º 13
0
def testSendNymFailsIfIdentifierSizeIs17Bytes(looper, sdk_pool_handle,
                                              txnPoolNodeSet, nym_request,
                                              sdk_wallet_trustee):
    parameters = {'dest': rawToFriendly(randombytes(17)), 'role': ENDORSER}
    nym_request[OPERATION].update(parameters)
    request_couple = sdk_sign_and_send_prepared_request(
        looper, sdk_wallet_trustee, sdk_pool_handle, json.dumps(nym_request))
    sdk_get_and_check_replies(looper, [request_couple])
Ejemplo n.º 14
0
def testSendNymFailsIfIdentifierSizeIs15Bytes(looper, sdk_pool_handle,
                                              txnPoolNodeSet, nym_request,
                                              sdk_wallet_trustee):
    parameters = {'dest': rawToFriendly(randombytes(15)), 'role': TRUST_ANCHOR}
    nym_request[OPERATION].update(parameters)
    request_couple = sdk_sign_and_send_prepared_request(
        looper, sdk_wallet_trustee, sdk_pool_handle, json.dumps(nym_request))
    sdk_get_bad_response(looper, [request_couple], RequestNackedException, '')
Ejemplo n.º 15
0
def testSendNymFailsIfIdentifierSizeIs15Bytes(
        be, do, poolNodesStarted, trusteeCli):

    parameters = {
        'dest': rawToFriendly(randombytes(15)),
        'role': Roles.TRUST_ANCHOR.name
    }

    be(trusteeCli)
    do('send NYM dest={dest} role={role}',
       mapper=parameters, expect=ERROR, within=2)
def testSendNymFailsIfIdentifierSizeIs15Bytes(
        be, do, poolNodesStarted, trusteeCli):

    parameters = {
        'dest': rawToFriendly(randombytes(15)),
        'role': Roles.TRUST_ANCHOR.name
    }

    be(trusteeCli)
    do('send NYM dest={dest} role={role}',
       mapper=parameters, expect=ERROR, within=2)
Ejemplo n.º 17
0
def add_steward_uids(steward: Steward) -> None:
    """
    Add various unique identifiers related to a Sovrin steward, to the local database mapping those
    random looking values to friendly names
    :param steward: An instance of the Steward class.
    """
    add_uid_to_dictionary(steward.nym, "{} {}".format(steward.name, "NYM"),
                          True)
    add_wallet_uids(steward.wallet, steward.name)
    add_uid_to_dictionary(rawToFriendly(unhexlify(steward.node.verkey)),
                          "{} {}".format(steward.node.name, "verkey"),
                          True)  # See ZStack.initLocalKeys
Ejemplo n.º 18
0
def testSendAttribFailsForBase58Hash(
        looper, sdk_pool_handle, sdk_wallet_trustee):
    raw = json.dumps({
        'name': 'Alice'
    })
    hash = sha256(raw.encode()).digest()

    new_wallet = sdk_add_new_nym(looper, sdk_pool_handle, sdk_wallet_trustee)
    parameters = None
    with pytest.raises(RequestNackedException) as e:
        sdk_add_attribute_and_check(looper, sdk_pool_handle, new_wallet, parameters,
                                    xhash=rawToFriendly(hash))
    e.match('not a valid hash')
Ejemplo n.º 19
0
def testSendAttribFailsForBase58Hash(be, do, poolNodesStarted, trusteeCli):

    uuidIdentifier = createUuidIdentifier()
    addNym(be, do, trusteeCli, idr=uuidIdentifier)

    raw = json.dumps({'name': 'Alice'})

    hash = sha256(raw.encode()).digest()

    parameters = {'dest': uuidIdentifier, 'hash': rawToFriendly(hash)}

    be(trusteeCli)
    do('send ATTRIB dest={dest} hash={hash}',
       mapper=parameters,
       expect=INVALID_SYNTAX,
       within=2)
def testSendAttribFailsForBase58Hash(
        be, do, poolNodesStarted, trusteeCli):

    uuidIdentifier = createUuidIdentifier()
    addNym(be, do, trusteeCli, idr=uuidIdentifier)

    raw = json.dumps({
        'name': 'Alice'
    })

    hash = sha256(raw.encode()).digest()

    parameters = {
        'dest': uuidIdentifier,
        'hash': rawToFriendly(hash)
    }

    be(trusteeCli)
    do('send ATTRIB dest={dest} hash={hash}',
       mapper=parameters, expect=INVALID_SYNTAX, within=2)
Ejemplo n.º 21
0
def createUuidIdentifier():
    return rawToFriendly(randombytes(16))
Ejemplo n.º 22
0
def friendlyVerkeyToPubkey(verkey):
    vkRaw = friendlyToRaw(verkey)
    pkraw = ed25519PkToCurve25519(vkRaw)
    return rawToFriendly(pkraw)
Ejemplo n.º 23
0
def createUuidIdentifier():
    return rawToFriendly(randombytes(16))
Ejemplo n.º 24
0
    def __init__(self,
                 name: str,
                 nodeReg: Dict[str, HA]=None,
                 ha: Union[HA, Tuple[str, int]]=None,
                 basedirpath: str=None,
                 config=None,
                 sighex: str=None):
        """
        Creates a new client.

        :param name: unique identifier for the client
        :param nodeReg: names and host addresses of all nodes in the pool
        :param ha: tuple of host and port
        """
        self.config = config or getConfig()
        basedirpath = self.config.baseDir if not basedirpath else basedirpath
        self.basedirpath = basedirpath

        signer = Signer(sighex)
        sighex = signer.keyhex
        verkey = rawToFriendly(signer.verraw)

        self.name = name
        self.stackName = verkey

        cha = None
        # If client information already exists is RAET then use that
        if self.exists(self.stackName, basedirpath):
            cha = getHaFromLocalEstate(self.stackName, basedirpath)
            if cha:
                cha = HA(*cha)
                logger.debug("Client {} ignoring given ha {} and using {}".
                             format(self.name, ha, cha))
        if not cha:
            cha = ha if isinstance(ha, HA) else HA(*ha)

        self.reqRepStore = self.getReqRepStore()
        self.txnLog = self.getTxnLogStore()

        self.dataDir = self.config.clientDataDir or "data/clients"
        HasFileStorage.__init__(self, self.name, baseDir=self.basedirpath,
                                dataDir=self.dataDir)

        self._ledger = None

        if not nodeReg:
            self.mode = None
            HasPoolManager.__init__(self)
            self.ledgerManager = LedgerManager(self, ownedByNode=False)
            self.ledgerManager.addLedger(0, self.ledger,
                postCatchupCompleteClbk=self.postPoolLedgerCaughtUp,
                postTxnAddedToLedgerClbk=self.postTxnFromCatchupAddedToLedger)
        else:
            cliNodeReg = OrderedDict()
            for nm, (ip, port) in nodeReg.items():
                cliNodeReg[nm] = HA(ip, port)
            self.nodeReg = cliNodeReg
            self.mode = Mode.discovered

        HasActionQueue.__init__(self)

        self.setF()

        stackargs = dict(name=self.stackName,
                         ha=cha,
                         main=False,  # stops incoming vacuous joins
                         auto=AutoMode.always)
        stackargs['basedirpath'] = basedirpath
        self.created = time.perf_counter()

        # noinspection PyCallingNonCallable
        self.nodestack = self.nodeStackClass(stackargs,
                                             self.handleOneNodeMsg,
                                             self.nodeReg,
                                             sighex)
        self.nodestack.onConnsChanged = self.onConnsChanged

        if self.nodeReg:
            logger.info("Client {} initialized with the following node registry:"
                        .format(self.name))
            lengths = [max(x) for x in zip(*[
                (len(name), len(host), len(str(port)))
                for name, (host, port) in self.nodeReg.items()])]
            fmt = "    {{:<{}}} listens at {{:<{}}} on port {{:>{}}}".format(
                *lengths)
            for name, (host, port) in self.nodeReg.items():
                logger.info(fmt.format(name, host, port))
        else:
            logger.info(
                "Client {} found an empty node registry:".format(self.name))

        Motor.__init__(self)

        self.inBox = deque()

        self.nodestack.connectNicelyUntil = 0  # don't need to connect
        # nicely as a client

        # TODO: Need to have couple of tests around `reqsPendingConnection`
        # where we check with and without pool ledger

        # Stores the requests that need to be sent to the nodes when the client
        # has made sufficient connections to the nodes.
        self.reqsPendingConnection = deque()

        # Tuple of identifier and reqId as key and value as tuple of set of
        # nodes which are expected to send REQACK
        self.expectingAcksFor = {}

        # Tuple of identifier and reqId as key and value as tuple of set of
        # nodes which are expected to send REPLY
        self.expectingRepliesFor = {}

        tp = loadPlugins(self.basedirpath)
        logger.debug("total plugins loaded in client: {}".format(tp))
Ejemplo n.º 25
0
def friendlyVerkeyToPubkey(verkey):
    vkRaw = friendlyToRaw(verkey)
    pkraw = ed25519PkToCurve25519(vkRaw)
    return rawToFriendly(pkraw)
Ejemplo n.º 26
0
    def __init__(self,
                 name: str,
                 nodeReg: Dict[str, HA] = None,
                 ha: Union[HA, Tuple[str, int]] = None,
                 basedirpath: str = None,
                 genesis_dir: str = None,
                 ledger_dir: str = None,
                 keys_dir: str = None,
                 plugins_dir: str = None,
                 config=None,
                 sighex: str = None):
        """
        Creates a new client.

        :param name: unique identifier for the client
        :param nodeReg: names and host addresses of all nodes in the pool
        :param ha: tuple of host and port
        """
        self.config = config or getConfig()

        dataDir = self.config.clientDataDir or "data/clients"
        self.basedirpath = basedirpath or self.config.CLI_BASE_DIR
        self.basedirpath = os.path.expanduser(self.basedirpath)

        signer = Signer(sighex)
        sighex = signer.keyraw
        verkey = rawToFriendly(signer.verraw)

        self.stackName = verkey
        # TODO: Have a way for a client to have a user friendly name. Does it
        # matter now, it used to matter in some CLI exampples in the past.
        # self.name = name
        self.name = self.stackName or 'Client~' + str(id(self))

        self.genesis_dir = genesis_dir or self.basedirpath
        self.ledger_dir = ledger_dir or os.path.join(self.basedirpath, dataDir, self.name)
        self.plugins_dir = plugins_dir or self.basedirpath
        _keys_dir = keys_dir or self.basedirpath
        self.keys_dir = os.path.join(_keys_dir, "keys")

        cha = None
        if self.exists(self.stackName, self.keys_dir):
            cha = self.nodeStackClass.getHaFromLocal(
                self.stackName, self.keys_dir)
            if cha:
                cha = HA(*cha)
                logger.debug("Client {} ignoring given ha {} and using {}".
                             format(self.name, ha, cha))
        if not cha:
            cha = ha if isinstance(ha, HA) else HA(*ha)

        self.reqRepStore = self.getReqRepStore()
        self.txnLog = self.getTxnLogStore()

        HasFileStorage.__init__(self, self.ledger_dir)

        # TODO: Find a proper name
        self.alias = name

        if not nodeReg:
            self.mode = None
            HasPoolManager.__init__(self)
            self.ledgerManager = LedgerManager(self, ownedByNode=False)
            self.ledgerManager.addLedger(
                POOL_LEDGER_ID,
                self.ledger,
                preCatchupStartClbk=self.prePoolLedgerCatchup,
                postCatchupCompleteClbk=self.postPoolLedgerCaughtUp,
                postTxnAddedToLedgerClbk=self.postTxnFromCatchupAddedToLedger)
        else:
            cliNodeReg = OrderedDict()
            for nm, (ip, port) in nodeReg.items():
                cliNodeReg[nm] = HA(ip, port)
            self.nodeReg = cliNodeReg
            self.mode = Mode.discovered

        HasActionQueue.__init__(self)

        self.setPoolParams()

        stackargs = dict(name=self.stackName,
                         ha=cha,
                         main=False,  # stops incoming vacuous joins
                         auth_mode=AuthMode.ALLOW_ANY.value)
        stackargs['basedirpath'] = self.keys_dir
        self.created = time.perf_counter()

        # noinspection PyCallingNonCallable
        # TODO I think this is a bug here, sighex is getting passed in the seed
        # parameter
        self.nodestack = self.nodeStackClass(stackargs,
                                             self.handleOneNodeMsg,
                                             self.nodeReg,
                                             sighex)
        self.nodestack.onConnsChanged = self.onConnsChanged

        if self.nodeReg:
            logger.info(
                "Client {} initialized with the following node registry:".format(
                    self.alias))
            lengths = [max(x) for x in zip(*[
                (len(name), len(host), len(str(port)))
                for name, (host, port) in self.nodeReg.items()])]
            fmt = "    {{:<{}}} listens at {{:<{}}} on port {{:>{}}}".format(
                *lengths)
            for name, (host, port) in self.nodeReg.items():
                logger.info(fmt.format(name, host, port))
        else:
            logger.info(
                "Client {} found an empty node registry:".format(self.alias))

        Motor.__init__(self)

        self.inBox = deque()

        self.nodestack.connectNicelyUntil = 0  # don't need to connect
        # nicely as a client

        # TODO: Need to have couple of tests around `reqsPendingConnection`
        # where we check with and without pool ledger

        # Stores the requests that need to be sent to the nodes when the client
        # has made sufficient connections to the nodes.
        self.reqsPendingConnection = deque()

        # Tuple of identifier and reqId as key and value as tuple of set of
        # nodes which are expected to send REQACK
        self.expectingAcksFor = {}

        # Tuple of identifier and reqId as key and value as tuple of set of
        # nodes which are expected to send REPLY
        self.expectingRepliesFor = {}

        self._observers = {}  # type Dict[str, Callable]
        self._observerSet = set()  # makes it easier to guard against duplicates

        plugins_to_load = self.config.PluginsToLoad if hasattr(self.config, "PluginsToLoad") else None
        tp = loadPlugins(self.plugins_dir, plugins_to_load)

        logger.debug("total plugins loaded in client: {}".format(tp))

        self._multi_sig_verifier = self._create_multi_sig_verifier()
        self._read_only_requests = set()
Ejemplo n.º 27
0
    def __init__(self,
                 name: str,
                 nodeReg: Dict[str, HA] = None,
                 ha: Union[HA, Tuple[str, int]] = None,
                 basedirpath: str = None,
                 config=None,
                 sighex: str = None):
        """
        Creates a new client.

        :param name: unique identifier for the client
        :param nodeReg: names and host addresses of all nodes in the pool
        :param ha: tuple of host and port
        """
        self.config = config or getConfig()
        basedirpath = self.config.baseDir if not basedirpath else basedirpath
        self.basedirpath = basedirpath

        signer = Signer(sighex)
        sighex = signer.keyraw
        verkey = rawToFriendly(signer.verraw)

        self.stackName = verkey
        # TODO: Have a way for a client to have a user friendly name. Does it
        # matter now, it used to matter in some CLI exampples in the past.
        # self.name = name
        self.name = self.stackName

        cha = None
        # If client information already exists is RAET then use that
        if self.exists(self.stackName, basedirpath):
            cha = getHaFromLocalEstate(self.stackName, basedirpath)
            if cha:
                cha = HA(*cha)
                logger.debug(
                    "Client {} ignoring given ha {} and using {}".format(
                        self.name, ha, cha))
        if not cha:
            cha = ha if isinstance(ha, HA) else HA(*ha)

        self.reqRepStore = self.getReqRepStore()
        self.txnLog = self.getTxnLogStore()

        self.dataDir = self.config.clientDataDir or "data/clients"
        HasFileStorage.__init__(self,
                                self.name,
                                baseDir=self.basedirpath,
                                dataDir=self.dataDir)

        # TODO: Find a proper name
        self.alias = name

        self._ledger = None

        if not nodeReg:
            self.mode = None
            HasPoolManager.__init__(self)
            self.ledgerManager = LedgerManager(self, ownedByNode=False)
            self.ledgerManager.addLedger(
                0,
                self.ledger,
                postCatchupCompleteClbk=self.postPoolLedgerCaughtUp,
                postTxnAddedToLedgerClbk=self.postTxnFromCatchupAddedToLedger)
        else:
            cliNodeReg = OrderedDict()
            for nm, (ip, port) in nodeReg.items():
                cliNodeReg[nm] = HA(ip, port)
            self.nodeReg = cliNodeReg
            self.mode = Mode.discovered

        HasActionQueue.__init__(self)

        self.setF()

        stackargs = dict(
            name=self.stackName,
            ha=cha,
            main=False,  # stops incoming vacuous joins
            auto=2)
        stackargs['basedirpath'] = basedirpath
        self.created = time.perf_counter()

        # noinspection PyCallingNonCallable
        self.nodestack = self.nodeStackClass(stackargs, self.handleOneNodeMsg,
                                             self.nodeReg, sighex)
        self.nodestack.onConnsChanged = self.onConnsChanged

        if self.nodeReg:
            logger.info(
                "Client {} initialized with the following node registry:".
                format(self.alias))
            lengths = [
                max(x)
                for x in zip(*[(len(name), len(host), len(str(port)))
                               for name, (host, port) in self.nodeReg.items()])
            ]
            fmt = "    {{:<{}}} listens at {{:<{}}} on port {{:>{}}}".format(
                *lengths)
            for name, (host, port) in self.nodeReg.items():
                logger.info(fmt.format(name, host, port))
        else:
            logger.info("Client {} found an empty node registry:".format(
                self.alias))

        Motor.__init__(self)

        self.inBox = deque()

        self.nodestack.connectNicelyUntil = 0  # don't need to connect
        # nicely as a client

        # TODO: Need to have couple of tests around `reqsPendingConnection`
        # where we check with and without pool ledger

        # Stores the requests that need to be sent to the nodes when the client
        # has made sufficient connections to the nodes.
        self.reqsPendingConnection = deque()

        # Tuple of identifier and reqId as key and value as tuple of set of
        # nodes which are expected to send REQACK
        self.expectingAcksFor = {}

        # Tuple of identifier and reqId as key and value as tuple of set of
        # nodes which are expected to send REPLY
        self.expectingRepliesFor = {}

        tp = loadPlugins(self.basedirpath)
        logger.debug("total plugins loaded in client: {}".format(tp))