# Buggy code
def verify_node(
    self,
    network_middleware,
    certificate_filepath: str = None,
    accept_federated_only: bool = False,
    force: bool = False,
) -> bool:
    """
    Three things happening here:

    * Verify that the stamp matches the address (raises InvalidNode is it's not valid,
      or WrongMode if it's a federated mode and being verified as a decentralized node)

    * Verify the interface signature (raises InvalidNode if not valid)

    * Connect to the node, make sure that it's up, and that the signature and address we
      checked are the same ones this node is using now. (raises InvalidNode if not valid;
      also emits a specific warning depending on which check failed).

    """

    if force:
        self.verified_interface = False
        self.verified_node = False
        self.verified_stamp = False
        self.verified_worker = False

    if self.verified_node:
        return True

    # This is both the stamp's client signature and interface metadata check; May raise InvalidNode
    self.validate_metadata(accept_federated_only=accept_federated_only)

    # The node's metadata is valid; let's be sure the interface is in order.
    if not certificate_filepath:
        if self.certificate_filepath is CERTIFICATE_NOT_SAVED:
            raise TypeError("We haven't saved a certificate for this node yet.")
        else:
            certificate_filepath = self.certificate_filepath

    response_data = network_middleware.node_information(
        host=self.rest_interface.host,
        port=self.rest_interface.port,
        certificate_filepath=certificate_filepath,
    )

    version, node_bytes = self.version_splitter(response_data, return_remainder=True)
    node_details = self.internal_splitter(node_bytes)
    # TODO: #589 - check timestamp here.

    verifying_keys_match = node_details["verifying_key"] == self.public_keys(
        SigningPower
    )
    encrypting_keys_match = node_details["encrypting_key"] == self.public_keys(
        DecryptingPower
    )
    addresses_match = node_details["public_address"] == self.canonical_public_address
    evidence_matches = (
        node_details["decentralized_identity_evidence"]
        == self.__decentralized_identity_evidence
    )

    if not all(
        (encrypting_keys_match, verifying_keys_match, addresses_match, evidence_matches)
    ):
        # Failure
        if not addresses_match:
            self.log.warn(
                "Wallet address swapped out.  It appears that someone is trying to defraud this node."
            )
        if not verifying_keys_match:
            self.log.warn(
                "Verifying key swapped out.  It appears that someone is impersonating this node."
            )

        # TODO: #355 - Optional reporting.
        raise self.InvalidNode(
            "Wrong cryptographic material for this node - something fishy going on."
        )

    else:
        # Success
        self.verified_node = True


# Traceback (ValueError)
$ nucypher ursula confirm-activity



,ggg,         gg
dP""Y8a        88                                   ,dPYb,
Yb, `88        88                                   IP'`Yb
`"  88        88                                   I8  8I
88        88                                   I8  8'
88        88   ,gggggg,    ,g,     gg      gg  I8 dP    ,gggg,gg
88        88   dP""""8I   ,8'8,    I8      8I  I8dP    dP"  "Y8I
88        88  ,8'    8I  ,8'  Yb   I8,    ,8I  I8P    i8'    ,8I
Y8b,____,d88,,dP     Y8,,8'_   8) ,d8b,  ,d8b,,d8b,_ ,d8,   ,d8b,
"Y888888P"Y88P      `Y8P' "YY8P8P8P'"Y88P"`Y88P'"Y88P"Y8888P"`Y8


the Untrusted Re-Encryption Proxy.


Decrypting NuCypher keyring...
WARNING - No Bootnodes Available
Traceback (most recent call last):
File "/home/ubuntu/.local/share/virtualenvs/nucypher-fvStivKV/bin/nucypher", line 11, in <module>
load_entry_point('nucypher', 'console_scripts', 'nucypher')()
File "/home/ubuntu/.local/share/virtualenvs/nucypher-fvStivKV/lib/python3.6/site-packages/click/core.py", line 764, in __call__
return self.main(*args, **kwargs)
File "/home/ubuntu/.local/share/virtualenvs/nucypher-fvStivKV/lib/python3.6/site-packages/click/core.py", line 717, in main
rv = self.invoke(ctx)
File "/home/ubuntu/.local/share/virtualenvs/nucypher-fvStivKV/lib/python3.6/site-packages/click/core.py", line 1137, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/ubuntu/.local/share/virtualenvs/nucypher-fvStivKV/lib/python3.6/site-packages/click/core.py", line 956, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/ubuntu/.local/share/virtualenvs/nucypher-fvStivKV/lib/python3.6/site-packages/click/core.py", line 555, in invoke
return callback(*args, **kwargs)
File "/home/ubuntu/.local/share/virtualenvs/nucypher-fvStivKV/lib/python3.6/site-packages/click/decorators.py", line 64, in new_func
return ctx.invoke(f, obj, *args, **kwargs)
File "/home/ubuntu/.local/share/virtualenvs/nucypher-fvStivKV/lib/python3.6/site-packages/click/core.py", line 555, in invoke
return callback(*args, **kwargs)
File "/home/ubuntu/nucypher/nucypher/cli/config.py", line 219, in wrapper
return func(config, *args, **kwargs)
File "/home/ubuntu/nucypher/nucypher/cli/characters/ursula.py", line 268, in ursula
client_password=client_password)
File "/home/ubuntu/nucypher/nucypher/cli/actions.py", line 288, in make_cli_character
**config_args)
File "/home/ubuntu/nucypher/nucypher/config/node.py", line 215, in __call__
return self.produce(**character_kwargs)
File "/home/ubuntu/nucypher/nucypher/config/characters.py", line 103, in produce
merged_parameters = self.generate_parameters(**overrides)
File "/home/ubuntu/nucypher/nucypher/config/node.py", line 284, in generate_parameters
merged_parameters = {**self.static_payload(), **self.dynamic_payload, **overrides}
File "/home/ubuntu/nucypher/nucypher/config/characters.py", line 98, in dynamic_payload
return {**super().dynamic_payload, **payload}
File "/home/ubuntu/nucypher/nucypher/config/node.py", line 385, in dynamic_payload
self.read_known_nodes()   # Requires a connected blockchain to init Ursulas.
File "/home/ubuntu/nucypher/nucypher/config/node.py", line 260, in read_known_nodes
known_nodes = self.node_storage.all(federated_only=self.federated_only)
File "/home/ubuntu/nucypher/nucypher/config/storages.py", line 415, in all
federated_only=federated_only)  # TODO: 466
File "/home/ubuntu/nucypher/nucypher/config/storages.py", line 384, in __read_metadata
node = Ursula.from_bytes(node_bytes, registry=registry, federated_only=federated_only)
File "/home/ubuntu/nucypher/nucypher/characters/lawful.py", line 1175, in from_bytes
ursula = cls.from_public_keys(registry=registry, federated_only=federated_only, **node_info)
File "/home/ubuntu/nucypher/nucypher/characters/base.py", line 310, in from_public_keys
return cls(is_me=False, federated_only=federated_only, crypto_power=crypto_power, *args, **kwargs)
File "/home/ubuntu/nucypher/nucypher/characters/lawful.py", line 831, in __init__
**character_kwargs)
File "/home/ubuntu/nucypher/nucypher/characters/base.py", line 116, in __init__
raise ValueError(f"Pass either federated only or registry.  Got '{federated_only}'. '{registry}'")
ValueError: Pass either federated only or registry.  Got 'None'. 'None'
Sentry is attempting to send 0 pending error messages
Waiting up to 2.0 seconds
Press Ctrl-C to quit

# Fixed code
def verify_node(
    self,
    network_middleware,
    certificate_filepath: str = None,
    force: bool = False,
    registry: BaseContractRegistry = None,
) -> bool:
    """
    Three things happening here:

    * Verify that the stamp matches the address (raises InvalidNode is it's not valid,
      or WrongMode if it's a federated mode and being verified as a decentralized node)

    * Verify the interface signature (raises InvalidNode if not valid)

    * Connect to the node, make sure that it's up, and that the signature and address we
      checked are the same ones this node is using now. (raises InvalidNode if not valid;
      also emits a specific warning depending on which check failed).

    """

    if force:
        self.verified_interface = False
        self.verified_node = False
        self.verified_stamp = False
        self.verified_worker = False

    if self.verified_node:
        return True

    if not registry and not self.federated_only:  # TODO: # 466
        self.log.debug(
            "No registry provided for decentralized stranger node verification - "
            "on-chain Staking verification will not be performed."
        )

    # This is both the stamp's client signature and interface metadata check; May raise InvalidNode
    self.validate_metadata(registry=registry)

    # The node's metadata is valid; let's be sure the interface is in order.
    if not certificate_filepath:
        if self.certificate_filepath is CERTIFICATE_NOT_SAVED:
            raise TypeError("We haven't saved a certificate for this node yet.")
        else:
            certificate_filepath = self.certificate_filepath

    response_data = network_middleware.node_information(
        host=self.rest_interface.host,
        port=self.rest_interface.port,
        certificate_filepath=certificate_filepath,
    )

    version, node_bytes = self.version_splitter(response_data, return_remainder=True)
    node_details = self.internal_splitter(node_bytes)
    # TODO: #589 - check timestamp here.

    verifying_keys_match = node_details["verifying_key"] == self.public_keys(
        SigningPower
    )
    encrypting_keys_match = node_details["encrypting_key"] == self.public_keys(
        DecryptingPower
    )
    addresses_match = node_details["public_address"] == self.canonical_public_address
    evidence_matches = (
        node_details["decentralized_identity_evidence"]
        == self.__decentralized_identity_evidence
    )

    if not all(
        (encrypting_keys_match, verifying_keys_match, addresses_match, evidence_matches)
    ):
        # Failure
        if not addresses_match:
            self.log.warn(
                "Wallet address swapped out.  It appears that someone is trying to defraud this node."
            )
        if not verifying_keys_match:
            self.log.warn(
                "Verifying key swapped out.  It appears that someone is impersonating this node."
            )

        # TODO: #355 - Optional reporting.
        raise self.InvalidNode(
            "Wrong cryptographic material for this node - something fishy going on."
        )

    else:
        # Success
        self.verified_node = True