Example #1
0
 def setUp(self):
     self.gossip = MockGossip()
     self.completer = MockCompleter()
     self.responder = Responder(self.completer)
     self.block_request_handler = \
         BlockResponderHandler(self.responder, self.gossip)
     self.block_response_handler = \
         ResponderBlockResponseHandler(self.responder, self.gossip)
     self.batch_request_handler = \
         BatchByBatchIdResponderHandler(self.responder, self.gossip)
     self.batch_response_handler = \
         ResponderBatchResponseHandler(self.responder, self.gossip)
     self.batch_by_txn_request_handler = \
         BatchByTransactionIdResponderHandler(self.responder, self.gossip)
Example #2
0
 def setUp(self):
     self.gossip = MockGossip()
     self.completer = MockCompleter()
     self.responder = Responder(self.completer)
     self.block_request_handler = \
         BlockResponderHandler(self.responder, self.gossip)
     self.block_response_handler = \
         ResponderBlockResponseHandler(self.responder, self.gossip)
     self.batch_request_handler = \
         BatchByBatchIdResponderHandler(self.responder, self.gossip)
     self.batch_response_handler = \
         ResponderBatchResponseHandler(self.responder, self.gossip)
     self.batch_by_txn_request_handler = \
         BatchByTransactionIdResponderHandler(self.responder, self.gossip)
Example #3
0
    def __init__(self, network_endpoint, component_endpoint, peer_list,
                 data_dir, identity_signing_key):
        """Constructs a validator instance.

        Args:
            network_endpoint (str): the network endpoint
            component_endpoint (str): the component endpoint
            peer_list (list of str): a list of peer addresses
            data_dir (str): path to the data directory
            key_dir (str): path to the key directory
        """
        db_filename = os.path.join(
            data_dir, 'merkle-{}.lmdb'.format(network_endpoint[-2:]))
        LOGGER.debug('database file is %s', db_filename)

        merkle_db = LMDBNoLockDatabase(db_filename, 'c')

        context_manager = ContextManager(merkle_db)
        self._context_manager = context_manager

        state_view_factory = StateViewFactory(merkle_db)

        block_db_filename = os.path.join(
            data_dir, 'block-{}.lmdb'.format(network_endpoint[-2:]))
        LOGGER.debug('block store file is %s', block_db_filename)

        block_db = LMDBNoLockDatabase(block_db_filename, 'c')
        block_store = BlockStore(block_db)

        # setup network
        self._dispatcher = Dispatcher()

        thread_pool = ThreadPoolExecutor(max_workers=10)
        process_pool = ProcessPoolExecutor(max_workers=3)

        self._thread_pool = thread_pool
        self._process_pool = process_pool

        self._service = Interconnect(component_endpoint,
                                     self._dispatcher,
                                     secured=False,
                                     heartbeat=False,
                                     max_incoming_connections=20)

        executor = TransactionExecutor(service=self._service,
                                       context_manager=context_manager,
                                       config_view_factory=ConfigViewFactory(
                                           StateViewFactory(merkle_db)))
        self._executor = executor

        zmq_identity = hashlib.sha512(
            time.time().hex().encode()).hexdigest()[:23]

        network_thread_pool = ThreadPoolExecutor(max_workers=10)
        self._network_thread_pool = network_thread_pool

        self._network_dispatcher = Dispatcher()

        # Server public and private keys are hardcoded here due to
        # the decision to avoid having separate identities for each
        # validator's server socket. This is appropriate for a public
        # network. For a permissioned network with requirements for
        # server endpoint authentication at the network level, this can
        # be augmented with a local lookup service for side-band provided
        # endpoint, public_key pairs and a local configuration option
        # for 'server' side private keys.
        self._network = Interconnect(
            network_endpoint,
            dispatcher=self._network_dispatcher,
            zmq_identity=zmq_identity,
            secured=True,
            server_public_key=b'wFMwoOt>yFqI/ek.G[tfMMILHWw#vXB[Sv}>l>i)',
            server_private_key=b'r&oJ5aQDj4+V]p2:Lz70Eu0x#m%IwzBdP(}&hWM*',
            heartbeat=True,
            connection_timeout=30,
            max_incoming_connections=100)

        self._gossip = Gossip(self._network, initial_peer_endpoints=peer_list)

        completer = Completer(block_store, self._gossip)

        block_sender = BroadcastBlockSender(completer, self._gossip)
        batch_sender = BroadcastBatchSender(completer, self._gossip)
        chain_id_manager = ChainIdManager(data_dir)
        # Create and configure journal
        self._journal = Journal(
            block_store=block_store,
            state_view_factory=StateViewFactory(merkle_db),
            block_sender=block_sender,
            batch_sender=batch_sender,
            transaction_executor=executor,
            squash_handler=context_manager.get_squash_handler(),
            identity_signing_key=identity_signing_key,
            chain_id_manager=chain_id_manager,
            data_dir=data_dir,
            check_publish_block_frequency=0.1,
            block_cache_purge_frequency=30,
            block_cache_keep_time=300)

        self._genesis_controller = GenesisController(
            context_manager=context_manager,
            transaction_executor=executor,
            completer=completer,
            block_store=block_store,
            state_view_factory=state_view_factory,
            identity_key=identity_signing_key,
            data_dir=data_dir,
            chain_id_manager=chain_id_manager,
            batch_sender=batch_sender)

        responder = Responder(completer)

        completer.set_on_batch_received(self._journal.on_batch_received)
        completer.set_on_block_received(self._journal.on_block_received)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_STATE_GET_REQUEST,
            tp_state_handlers.TpStateGetHandler(context_manager), thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_STATE_SET_REQUEST,
            tp_state_handlers.TpStateSetHandler(context_manager), thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_REGISTER_REQUEST,
            processor_handlers.ProcessorRegisterHandler(executor.processors),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_UNREGISTER_REQUEST,
            processor_handlers.ProcessorUnRegisterHandler(executor.processors),
            thread_pool)

        # Set up base network handlers
        self._network_dispatcher.add_handler(
            validator_pb2.Message.NETWORK_PING, PingHandler(),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.NETWORK_CONNECT,
            ConnectHandler(network=self._network), network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.NETWORK_DISCONNECT,
            DisconnectHandler(network=self._network), network_thread_pool)

        # Set up gossip handlers
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_REGISTER,
            PeerRegisterHandler(gossip=self._gossip), network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_UNREGISTER,
            PeerUnregisterHandler(gossip=self._gossip), network_thread_pool)

        # GOSSIP_MESSAGE 1) Sends acknowledgement to the sender
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE, GossipMessageHandler(),
            network_thread_pool)

        # GOSSIP_MESSAGE 2) Verifies signature
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE,
            signature_verifier.GossipMessageSignatureVerifier(), process_pool)

        # GOSSIP_MESSAGE 3) Determines if we should broadcast the
        # message to our peers. It is important that this occur prior
        # to the sending of the message to the completer, as this step
        # relies on whether the  gossip message has previously been
        # seen by the validator to determine whether or not forwarding
        # should occur
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE,
            GossipBroadcastHandler(gossip=self._gossip, completer=completer),
            network_thread_pool)

        # GOSSIP_MESSAGE 4) Send message to completer
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE,
            CompleterGossipHandler(completer), network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BLOCK_REQUEST,
            BlockResponderHandler(responder, self._gossip),
            network_thread_pool)

        # GOSSIP_BLOCK_RESPONSE 1) Sends ack to the sender
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
            GossipBlockResponseHandler(), network_thread_pool)

        # GOSSIP_BLOCK_RESPONSE 2) Verifies signature
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
            signature_verifier.GossipBlockResponseSignatureVerifier(),
            process_pool)

        # GOSSIP_BLOCK_RESPONSE 3) Send message to completer
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
            CompleterGossipBlockResponseHandler(completer),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST,
            BatchByBatchIdResponderHandler(responder, self._gossip),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST,
            BatchByTransactionIdResponderHandler(responder, self._gossip),
            network_thread_pool)

        # GOSSIP_BATCH_RESPONSE 1) Sends ack to the sender
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
            GossipBatchResponseHandler(), network_thread_pool)

        # GOSSIP_BATCH_RESPONSE 2) Verifies signature
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
            signature_verifier.GossipBatchResponseSignatureVerifier(),
            process_pool)

        # GOSSIP_BATCH_RESPONSE 3) Send message to completer
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
            CompleterGossipBatchResponseHandler(completer),
            network_thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            signature_verifier.BatchListSignatureVerifier(), process_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            CompleterBatchListBroadcastHandler(completer, self._gossip),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            client_handlers.BatchSubmitFinisher(
                self._journal.get_block_store(), completer.batch_cache),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_STATUS_REQUEST,
            client_handlers.BatchStatusRequest(self._journal.get_block_store(),
                                               completer.batch_cache),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_STATE_LIST_REQUEST,
            client_handlers.StateListRequest(merkle_db,
                                             self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_STATE_GET_REQUEST,
            client_handlers.StateGetRequest(merkle_db,
                                            self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BLOCK_LIST_REQUEST,
            client_handlers.BlockListRequest(self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BLOCK_GET_REQUEST,
            client_handlers.BlockGetRequest(self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_LIST_REQUEST,
            client_handlers.BatchListRequest(self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_GET_REQUEST,
            client_handlers.BatchGetRequest(self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_STATE_CURRENT_REQUEST,
            client_handlers.StateCurrentRequest(
                self._journal.get_current_root), thread_pool)
Example #4
0
    def __init__(self, bind_network, bind_component, endpoint,
                 peering, seeds_list, peer_list, data_dir, config_dir,
                 identity_signing_key, scheduler_type,
                 network_public_key=None,
                 network_private_key=None):
        """Constructs a validator instance.

        Args:
            bind_network (str): the network endpoint
            bind_component (str): the component endpoint
            endpoint (str): the zmq-style URI of this validator's
                publically reachable endpoint
            peering (str): The type of peering approach. Either 'static'
                or 'dynamic'. In 'static' mode, no attempted topology
                buildout occurs -- the validator only attempts to initiate
                peering connections with endpoints specified in the
                peer_list. In 'dynamic' mode, the validator will first
                attempt to initiate peering connections with endpoints
                specified in the peer_list and then attempt to do a
                topology buildout starting with peer lists obtained from
                endpoints in the seeds_list. In either mode, the validator
                will accept incoming peer requests up to max_peers.
            seeds_list (list of str): a list of addresses to connect
                to in order to perform the initial topology buildout
            peer_list (list of str): a list of peer addresses
            data_dir (str): path to the data directory
            config_dir (str): path to the config directory
            identity_signing_key (str): key validator uses for signing
        """
        db_filename = os.path.join(data_dir,
                                   'merkle-{}.lmdb'.format(
                                       bind_network[-2:]))
        LOGGER.debug('database file is %s', db_filename)

        merkle_db = LMDBNoLockDatabase(db_filename, 'c')

        delta_db_filename = os.path.join(data_dir,
                                         'state-deltas-{}.lmdb'.format(
                                             bind_network[-2:]))
        LOGGER.debug('state delta store file is %s', delta_db_filename)
        state_delta_db = LMDBNoLockDatabase(delta_db_filename, 'c')

        state_delta_store = StateDeltaStore(state_delta_db)

        context_manager = ContextManager(merkle_db, state_delta_store)
        self._context_manager = context_manager

        state_view_factory = StateViewFactory(merkle_db)

        block_db_filename = os.path.join(data_dir, 'block-{}.lmdb'.format(
                                         bind_network[-2:]))
        LOGGER.debug('block store file is %s', block_db_filename)

        block_db = LMDBNoLockDatabase(block_db_filename, 'c')
        block_store = BlockStore(block_db)

        batch_tracker = BatchTracker(block_store)
        block_store.add_update_observer(batch_tracker)

        # setup network
        self._dispatcher = Dispatcher()

        thread_pool = ThreadPoolExecutor(max_workers=10)
        sig_pool = ThreadPoolExecutor(max_workers=3)

        self._thread_pool = thread_pool
        self._sig_pool = sig_pool

        self._service = Interconnect(bind_component,
                                     self._dispatcher,
                                     secured=False,
                                     heartbeat=False,
                                     max_incoming_connections=20,
                                     monitor=True)

        config_file = os.path.join(config_dir, "validator.toml")

        validator_config = {}
        if os.path.exists(config_file):
            with open(config_file) as fd:
                raw_config = fd.read()
            validator_config = toml.loads(raw_config)

        if scheduler_type is None:
            scheduler_type = validator_config.get("scheduler", "serial")

        executor = TransactionExecutor(
            service=self._service,
            context_manager=context_manager,
            settings_view_factory=SettingsViewFactory(
                                    StateViewFactory(merkle_db)),
            scheduler_type=scheduler_type,
            invalid_observers=[batch_tracker])

        self._executor = executor
        self._service.set_check_connections(executor.check_connections)

        state_delta_processor = StateDeltaProcessor(self._service,
                                                    state_delta_store,
                                                    block_store)

        zmq_identity = hashlib.sha512(
            time.time().hex().encode()).hexdigest()[:23]

        network_thread_pool = ThreadPoolExecutor(max_workers=10)
        self._network_thread_pool = network_thread_pool

        self._network_dispatcher = Dispatcher()

        secure = False
        if network_public_key is not None and network_private_key is not None:
            secure = True

        self._network = Interconnect(
            bind_network,
            dispatcher=self._network_dispatcher,
            zmq_identity=zmq_identity,
            secured=secure,
            server_public_key=network_public_key,
            server_private_key=network_private_key,
            heartbeat=True,
            public_endpoint=endpoint,
            connection_timeout=30,
            max_incoming_connections=100)

        self._gossip = Gossip(self._network,
                              endpoint=endpoint,
                              peering_mode=peering,
                              initial_seed_endpoints=seeds_list,
                              initial_peer_endpoints=peer_list,
                              minimum_peer_connectivity=3,
                              maximum_peer_connectivity=10,
                              topology_check_frequency=1)

        completer = Completer(block_store, self._gossip)

        block_sender = BroadcastBlockSender(completer, self._gossip)
        batch_sender = BroadcastBatchSender(completer, self._gossip)
        chain_id_manager = ChainIdManager(data_dir)
        # Create and configure journal
        self._journal = Journal(
            block_store=block_store,
            state_view_factory=StateViewFactory(merkle_db),
            block_sender=block_sender,
            batch_sender=batch_sender,
            transaction_executor=executor,
            squash_handler=context_manager.get_squash_handler(),
            identity_signing_key=identity_signing_key,
            chain_id_manager=chain_id_manager,
            state_delta_processor=state_delta_processor,
            data_dir=data_dir,
            config_dir=config_dir,
            check_publish_block_frequency=0.1,
            block_cache_purge_frequency=30,
            block_cache_keep_time=300,
            batch_observers=[batch_tracker]
        )

        self._genesis_controller = GenesisController(
            context_manager=context_manager,
            transaction_executor=executor,
            completer=completer,
            block_store=block_store,
            state_view_factory=state_view_factory,
            identity_key=identity_signing_key,
            data_dir=data_dir,
            config_dir=config_dir,
            chain_id_manager=chain_id_manager,
            batch_sender=batch_sender
        )

        responder = Responder(completer)

        completer.set_on_batch_received(self._journal.on_batch_received)
        completer.set_on_block_received(self._journal.on_block_received)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_STATE_GET_REQUEST,
            tp_state_handlers.TpStateGetHandler(context_manager),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_STATE_SET_REQUEST,
            tp_state_handlers.TpStateSetHandler(context_manager),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_REGISTER_REQUEST,
            processor_handlers.ProcessorRegisterHandler(executor.processors),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_UNREGISTER_REQUEST,
            processor_handlers.ProcessorUnRegisterHandler(executor.processors),
            thread_pool)

        # Set up base network handlers
        self._network_dispatcher.add_handler(
            validator_pb2.Message.NETWORK_PING,
            PingHandler(),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.NETWORK_CONNECT,
            ConnectHandler(network=self._network),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.NETWORK_DISCONNECT,
            DisconnectHandler(network=self._network),
            network_thread_pool)

        # Set up gossip handlers
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_GET_PEERS_REQUEST,
            GetPeersRequestHandler(gossip=self._gossip),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_GET_PEERS_RESPONSE,
            GetPeersResponseHandler(gossip=self._gossip),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_REGISTER,
            PeerRegisterHandler(gossip=self._gossip),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_UNREGISTER,
            PeerUnregisterHandler(gossip=self._gossip),
            network_thread_pool)

        # GOSSIP_MESSAGE 1) Sends acknowledgement to the sender
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE,
            GossipMessageHandler(),
            network_thread_pool)

        # GOSSIP_MESSAGE 2) Verifies signature
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE,
            signature_verifier.GossipMessageSignatureVerifier(),
            sig_pool)

        # GOSSIP_MESSAGE 3) Verifies batch structure
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE,
            structure_verifier.GossipHandlerStructureVerifier(),
            network_thread_pool)

        # GOSSIP_MESSAGE 4) Determines if we should broadcast the
        # message to our peers. It is important that this occur prior
        # to the sending of the message to the completer, as this step
        # relies on whether the  gossip message has previously been
        # seen by the validator to determine whether or not forwarding
        # should occur
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE,
            GossipBroadcastHandler(
                gossip=self._gossip,
                completer=completer),
            network_thread_pool)

        # GOSSIP_MESSAGE 5) Send message to completer
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE,
            CompleterGossipHandler(
                completer),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BLOCK_REQUEST,
            BlockResponderHandler(responder, self._gossip),
            network_thread_pool)

        # GOSSIP_BLOCK_RESPONSE 1) Sends ack to the sender
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
            GossipBlockResponseHandler(),
            network_thread_pool)

        # GOSSIP_BLOCK_RESPONSE 2) Verifies signature
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
            signature_verifier.GossipBlockResponseSignatureVerifier(),
            sig_pool)

        # GOSSIP_BLOCK_RESPONSE 3) Check batch structure
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
            structure_verifier.GossipBlockResponseStructureVerifier(),
            network_thread_pool)

        # GOSSIP_BLOCK_RESPONSE 4) Send message to completer
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
            CompleterGossipBlockResponseHandler(
                completer),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
            ResponderBlockResponseHandler(responder, self._gossip),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST,
            BatchByBatchIdResponderHandler(responder, self._gossip),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST,
            BatchByTransactionIdResponderHandler(responder, self._gossip),
            network_thread_pool)

        # GOSSIP_BATCH_RESPONSE 1) Sends ack to the sender
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
            GossipBatchResponseHandler(),
            network_thread_pool)

        # GOSSIP_BATCH_RESPONSE 2) Verifies signature
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
            signature_verifier.GossipBatchResponseSignatureVerifier(),
            sig_pool)

        # GOSSIP_BATCH_RESPONSE 3) Check batch structure
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
            structure_verifier.GossipBatchResponseStructureVerifier(),
            network_thread_pool)

        # GOSSIP_BATCH_RESPONSE 4) Send message to completer
        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
            CompleterGossipBatchResponseHandler(
                completer),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
            ResponderBatchResponseHandler(responder, self._gossip),
            network_thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            BatchListPermissionVerifier(
                settings_view_factory=SettingsViewFactory(
                    StateViewFactory(merkle_db)),
                current_root_func=self._journal.get_current_root,
            ),
            sig_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            signature_verifier.BatchListSignatureVerifier(),
            sig_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            structure_verifier.BatchListStructureVerifier(),
            network_thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            CompleterBatchListBroadcastHandler(
                completer, self._gossip),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            client_handlers.BatchSubmitFinisher(batch_tracker),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_STATUS_REQUEST,
            client_handlers.BatchStatusRequest(batch_tracker),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_STATE_LIST_REQUEST,
            client_handlers.StateListRequest(
                merkle_db,
                self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_STATE_GET_REQUEST,
            client_handlers.StateGetRequest(
                merkle_db,
                self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BLOCK_LIST_REQUEST,
            client_handlers.BlockListRequest(self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BLOCK_GET_REQUEST,
            client_handlers.BlockGetRequest(self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_LIST_REQUEST,
            client_handlers.BatchListRequest(self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_GET_REQUEST,
            client_handlers.BatchGetRequest(self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_TRANSACTION_LIST_REQUEST,
            client_handlers.TransactionListRequest(
                self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_TRANSACTION_GET_REQUEST,
            client_handlers.TransactionGetRequest(
                self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_STATE_CURRENT_REQUEST,
            client_handlers.StateCurrentRequest(
                self._journal.get_current_root), thread_pool)

        # State Delta Subscription Handlers
        self._dispatcher.add_handler(
            validator_pb2.Message.STATE_DELTA_SUBSCRIBE_REQUEST,
            StateDeltaSubscriberValidationHandler(state_delta_processor),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.STATE_DELTA_SUBSCRIBE_REQUEST,
            StateDeltaAddSubscriberHandler(state_delta_processor),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.STATE_DELTA_UNSUBSCRIBE_REQUEST,
            StateDeltaUnsubscriberHandler(state_delta_processor),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.STATE_DELTA_GET_EVENTS_REQUEST,
            StateDeltaGetEventsHandler(block_store, state_delta_store),
            thread_pool)
Example #5
0
class TestResponder(unittest.TestCase):
    def setUp(self):
        self.gossip = MockGossip()
        self.completer = MockCompleter()
        self.responder = Responder(self.completer)
        self.block_request_handler = \
            BlockResponderHandler(self.responder, self.gossip)
        self.block_response_handler = \
            ResponderBlockResponseHandler(self.responder, self.gossip)
        self.batch_request_handler = \
            BatchByBatchIdResponderHandler(self.responder, self.gossip)
        self.batch_response_handler = \
            ResponderBatchResponseHandler(self.responder, self.gossip)
        self.batch_by_txn_request_handler = \
            BatchByTransactionIdResponderHandler(self.responder, self.gossip)

    # Tests
    def test_block_responder_handler(self):
        """
        Test that the BlockResponderHandler correctly broadcasts a received
        request that the Responder cannot respond to, or sends a
        GossipBlockResponse back to the connection_id the handler received
        the request from.
        """
        # The completer does not have the requested block
        before_message = network_pb2.GossipBlockRequest(block_id="ABC",
                                                        nonce="1",
                                                        time_to_live=1)

        after_message = network_pb2.GossipBlockRequest(block_id="ABC",
                                                       nonce="1",
                                                       time_to_live=0)

        self.block_request_handler.handle("Connection_1",
                                          before_message.SerializeToString())
        # If we cannot respond to the request, broadcast the block request
        # and add to pending request
        self.assert_message_was_broadcasted(
            after_message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST)

        self.assert_request_pending(requested_id="ABC",
                                    connection_id="Connection_1")
        self.assert_message_not_sent(connection_id="Connection_1")

        # Add the block to the completer and resend the Block Request
        block = block_pb2.Block(header_signature="ABC")
        self.completer.add_block(block)

        message = network_pb2.GossipBlockRequest(block_id="ABC",
                                                 nonce="2",
                                                 time_to_live=1)

        self.block_request_handler.handle("Connection_1",
                                          message.SerializeToString())

        # Check that the a Block Response was sent back to "Connection_1"
        self.assert_message_sent(
            connection_id="Connection_1",
            message_type=validator_pb2.Message.GOSSIP_BLOCK_RESPONSE)

    def test_block_responder_handler_requested(self):
        """
        Test that the BlockResponderHandler correctly broadcasts a received
        request that the Responder cannot respond to, and does not rebroadcast
        the same request.  If we have already recieved the
        request, do nothing.
        """
        before_message = network_pb2.GossipBlockRequest(block_id="ABC",
                                                        nonce="1",
                                                        time_to_live=1)

        after_message = network_pb2.GossipBlockRequest(block_id="ABC",
                                                       nonce="1",
                                                       time_to_live=0)

        self.block_request_handler.handle("Connection_1",
                                          before_message.SerializeToString())
        # If we cannot respond to the request, broadcast the block request
        # and add to pending request
        self.assert_message_was_broadcasted(
            after_message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST)

        self.assert_request_pending(requested_id="ABC",
                                    connection_id="Connection_1")
        self.assert_message_not_sent(connection_id="Connection_1")

        self.gossip.clear()

        # Message should be dropped since the same message has already been
        # handled
        self.block_request_handler.handle("Connection_2",
                                          before_message.SerializeToString())

        self.assert_message_was_not_broadcasted(
            before_message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST)

        self.assert_request_not_pending(requested_id="ABC",
                                        connection_id="Connection_2")

        message = network_pb2.GossipBlockRequest(block_id="ABC",
                                                 nonce="2",
                                                 time_to_live=1)

        self.block_request_handler.handle("Connection_2",
                                          message.SerializeToString())

        self.assert_message_was_not_broadcasted(
            message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST)

        self.assert_request_pending(requested_id="ABC",
                                    connection_id="Connection_2")
        self.assert_message_not_sent(connection_id="Connection_2")

    def test_responder_block_response_handler(self):
        """
        Test that the ResponderBlockResponseHandler, after receiving a Block
        Response, checks to see if the responder has any pending request for
        that response and forwards the response on to the connection_id that
        had requested it.
        """
        # The Responder does not have any pending requests for block "ABC"
        block = block_pb2.Block(header_signature="ABC")
        response_message = network_pb2.GossipBlockResponse(
            content=block.SerializeToString())

        self.block_response_handler.handle(
            "Connection_1", response_message.SerializeToString())

        # ResponderBlockResponseHandler should not send any messages.
        self.assert_message_not_sent("Connection_1")
        self.assert_request_not_pending(requested_id="ABC")

        # Handle a request message for block "ABC". This adds it to the pending
        # request queue.
        request_message = \
            network_pb2.GossipBlockRequest(block_id="ABC", time_to_live=1)

        self.block_request_handler.handle("Connection_2",
                                          request_message.SerializeToString())

        self.assert_request_pending(requested_id="ABC",
                                    connection_id="Connection_2")

        # Handle the the BlockResponse Message. Since Connection_2 had
        # requested the block but it could not be fulfilled at that time of the
        # request the received BlockResponse is forwarded to Connection_2
        self.block_response_handler.handle(
            "Connection_1", response_message.SerializeToString())

        self.assert_message_sent(
            connection_id="Connection_2",
            message_type=validator_pb2.Message.GOSSIP_BLOCK_RESPONSE)
        # The request for block "ABC" from "Connection_2" is no longer pending
        # it should be removed from the pending request cache.
        self.assert_request_not_pending(requested_id="ABC")

    def test_batch_by_id_responder_handler(self):
        """
        Test that the BatchByBatchIdResponderHandler correctly broadcasts a
        received request that the Responder cannot respond to, or sends a
        GossipBatchResponse back to the connection_id the handler received
        the request from.
        """
        # The completer does not have the requested batch
        before_message = network_pb2.GossipBatchByBatchIdRequest(
            id="abc", nonce="1", time_to_live=1)

        after_message = network_pb2.GossipBatchByBatchIdRequest(id="abc",
                                                                nonce="1",
                                                                time_to_live=0)

        self.batch_request_handler.handle("Connection_1",
                                          before_message.SerializeToString())
        # If we cannot respond to the request broadcast batch request and add
        # to pending request
        self.assert_message_was_broadcasted(
            after_message,
            validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST)
        self.assert_request_pending(requested_id="abc",
                                    connection_id="Connection_1")
        self.assert_message_not_sent(connection_id="Connection_1")

        # Add the batch to the completer and resend the BatchByBatchIdRequest
        message = network_pb2.GossipBatchByBatchIdRequest(id="abc",
                                                          nonce="2",
                                                          time_to_live=1)
        batch = batch_pb2.Batch(header_signature="abc")
        self.completer.add_batch(batch)
        self.batch_request_handler.handle("Connection_1",
                                          message.SerializeToString())

        # Check that the a Batch Response was sent back to "Connection_1"
        self.assert_message_sent(
            connection_id="Connection_1",
            message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE)

    def test_batch_by_id_responder_handler_requested(self):
        """
        Test that the BatchByBatchIdResponderHandler correctly broadcasts
        a received request that the Responder cannot respond to, and does not
        rebroadcast the same request again.  If we have already recieved the
        request, do nothing.
        """
        # The completer does not have the requested batch
        before_message = network_pb2.GossipBatchByBatchIdRequest(
            id="abc", nonce="1", time_to_live=1)

        after_message = network_pb2.GossipBatchByBatchIdRequest(id="abc",
                                                                nonce="1",
                                                                time_to_live=0)
        self.batch_request_handler.handle("Connection_1",
                                          before_message.SerializeToString())
        # If we cannot respond to the request broadcast batch request and add
        # to pending request
        self.assert_message_was_broadcasted(
            after_message,
            validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST)
        self.assert_request_pending(requested_id="abc",
                                    connection_id="Connection_1")
        self.assert_message_not_sent(connection_id="Connection_1")

        self.gossip.clear()

        # Message should be dropped since the same message has already been
        # handled
        self.batch_request_handler.handle("Connection_2",
                                          before_message.SerializeToString())

        self.assert_message_was_not_broadcasted(
            before_message,
            validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST)

        self.assert_request_not_pending(requested_id="abc",
                                        connection_id="Connection_2")

        message = network_pb2.GossipBatchByBatchIdRequest(id="abc",
                                                          nonce="2",
                                                          time_to_live=1)

        self.batch_request_handler.handle("Connection_2",
                                          message.SerializeToString())

        self.assert_message_was_not_broadcasted(
            message, validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST)

        self.assert_request_pending(requested_id="abc",
                                    connection_id="Connection_2")
        self.assert_message_not_sent(connection_id="Connection_2")

    def test_batch_by_transaction_id_response_handler(self):
        """
        Test that the BatchByTransactionIdResponderHandler correctly broadcasts
        a received request that the Responder cannot respond to, or sends a
        GossipBatchResponse back to the connection_id the handler received
        the request from.
        """
        # The completer does not have the requested batch with the transaction
        before_message = network_pb2.GossipBatchByTransactionIdRequest(
            ids=["123"], nonce="1", time_to_live=1)

        after_message = network_pb2.GossipBatchByTransactionIdRequest(
            ids=["123"], nonce="1", time_to_live=0)

        self.batch_by_txn_request_handler.handle(
            "Connection_1", before_message.SerializeToString())

        # If we cannot respond to the request, broadcast batch request and add
        # to pending request
        self.assert_message_was_broadcasted(
            after_message,
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)
        self.assert_request_pending(requested_id="123",
                                    connection_id="Connection_1")
        self.assert_message_not_sent(connection_id="Connection_1")

        # Add the batch to the completer and resend the
        # BatchByTransactionIdRequest
        message = network_pb2.GossipBatchByTransactionIdRequest(ids=["123"],
                                                                nonce="2",
                                                                time_to_live=1)
        transaction = transaction_pb2.Transaction(header_signature="123")
        batch = batch_pb2.Batch(header_signature="abc",
                                transactions=[transaction])
        self.completer.add_batch(batch)
        self.batch_request_handler.handle("Connection_1",
                                          message.SerializeToString())

        # Check that the a Batch Response was sent back to "Connection_1"
        self.assert_message_sent(
            connection_id="Connection_1",
            message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE)

    def test_batch_by_transaction_id_response_handler_requested(self):
        """
        Test that the BatchByTransactionIdResponderHandler correctly broadcasts
        a received request that the Responder cannot respond to, and does not
        rebroadcast the same request again. If we have already recieved the
        request, do nothing.
        """
        # The completer does not have the requested batch with the transaction
        before_message = network_pb2.GossipBatchByTransactionIdRequest(
            ids=["123"], time_to_live=1)

        after_message = network_pb2.GossipBatchByTransactionIdRequest(
            ids=["123"], time_to_live=0)

        self.batch_by_txn_request_handler.handle(
            "Connection_1", before_message.SerializeToString())

        # If we cannot respond to the request, broadcast batch request and add
        # to pending request
        self.assert_message_was_broadcasted(
            after_message,
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)
        self.assert_request_pending(requested_id="123",
                                    connection_id="Connection_1")
        self.assert_message_not_sent(connection_id="Connection_1")

        self.gossip.clear()

        # Message should be dropped since the same message has already been
        # handled
        self.batch_by_txn_request_handler.handle(
            "Connection_2", before_message.SerializeToString())

        self.assert_message_was_not_broadcasted(
            after_message,
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)

        self.assert_request_not_pending(requested_id="123",
                                        connection_id="Connection_2")

        message = network_pb2.GossipBatchByTransactionIdRequest(ids=["123"],
                                                                nonce="2",
                                                                time_to_live=1)
        self.batch_by_txn_request_handler.handle("Connection_2",
                                                 message.SerializeToString())

        self.assert_message_was_not_broadcasted(
            message,
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)
        self.assert_request_pending(requested_id="123",
                                    connection_id="Connection_2")
        self.assert_message_not_sent(connection_id="Connection_2")

    def test_batch_by_transaction_id_multiple_txn_ids(self):
        """
        Test that the BatchByTransactionIdResponderHandler correctly broadcasts
        a new request with only the transaction_ids that the Responder cannot
        respond to, and sends a GossipBatchResponse for the transactions_id
        requests that can be satisfied.
        """
        # Add batch that has txn 123
        transaction = transaction_pb2.Transaction(header_signature="123")
        batch = batch_pb2.Batch(header_signature="abc",
                                transactions=[transaction])
        self.completer.add_batch(batch)
        # Request transactions 123 and 456
        message = network_pb2.GossipBatchByTransactionIdRequest(
            ids=["123", "456"], time_to_live=1)
        self.batch_by_txn_request_handler.handle("Connection_1",
                                                 message.SerializeToString())
        self.batch_request_handler.handle("Connection_1",
                                          message.SerializeToString())

        # Respond with a BatchResponse for transaction 123
        self.assert_message_sent(
            connection_id="Connection_1",
            message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE)

        # Broadcast a BatchByTransactionIdRequest for just 456
        after_message = \
            network_pb2.GossipBatchByTransactionIdRequest(
                ids=["456"],
                time_to_live=0)

        self.assert_message_was_broadcasted(
            after_message,
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)

        # And set a pending request for 456
        self.assert_request_pending(requested_id="456",
                                    connection_id="Connection_1")

    def test_responder_batch_response_handler(self):
        """
        Test that the ResponderBatchResponseHandler, after receiving a Batch
        Response, checks to see if the responder has any pending request for
        that batch and forwards the response on to the connection_id that
        had requested it.
        """
        # The Responder does not have any pending requests for block "ABC"
        batch = batch_pb2.Batch(header_signature="abc")

        response_message = network_pb2.GossipBatchResponse(
            content=batch.SerializeToString())

        self.batch_response_handler.handle(
            "Connection_1", response_message.SerializeToString())

        # ResponderBlockResponseHandler should not send any messages.
        self.assert_message_not_sent("Connection_1")
        self.assert_request_not_pending(requested_id="abc")

        # Handle a request message for batch "abc". This adds it to the pending
        # request queue.
        request_message = \
            network_pb2.GossipBatchByBatchIdRequest(id="abc", time_to_live=1)

        self.batch_request_handler.handle("Connection_2",
                                          request_message.SerializeToString())

        self.assert_request_pending(requested_id="abc",
                                    connection_id="Connection_2")

        # Handle the the BatchResponse Message. Since Connection_2 had
        # requested the batch but it could not be fulfilled at that time of the
        # request the received BatchResponse is forwarded to Connection_2
        self.batch_response_handler.handle(
            "Connection_1", response_message.SerializeToString())

        self.assert_message_sent(
            connection_id="Connection_2",
            message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE)
        # The request for batch "abc" from "Connection_2" is no longer pending
        # it should be removed from the pending request cache.
        self.assert_request_not_pending(requested_id="abc")

    def test_responder_batch_response_txn_handler(self):
        """
        Test that the ResponderBatchResponseHandler, after receiving a Batch
        Response, checks to see if the responder has any pending request for
        that transactions in the batch and forwards the response on to the
        connection_id that had them.
        """
        transaction = transaction_pb2.Transaction(header_signature="123")
        batch = batch_pb2.Batch(header_signature="abc",
                                transactions=[transaction])

        response_message = network_pb2.GossipBatchResponse(
            content=batch.SerializeToString())

        request_message = \
            network_pb2.GossipBatchByTransactionIdRequest(
                ids=["123"],
                time_to_live=1)

        # Send BatchByTransaciontIdRequest for txn "123" and add it to the
        # pending request cache
        self.batch_request_handler.handle("Connection_2",
                                          request_message.SerializeToString())

        self.assert_request_pending(requested_id="123",
                                    connection_id="Connection_2")

        # Send Batch Response that contains the batch that has txn "123"
        self.batch_response_handler.handle(
            "Connection_1", response_message.SerializeToString())

        # Handle the the BatchResponse Message. Since Connection_2 had
        # requested the txn_id in the batch but it could not be fulfilled at
        # that time of the request the received BatchResponse is forwarded to
        # Connection_2
        self.assert_message_sent(
            connection_id="Connection_2",
            message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE)
        # The request for transaction_id "123" from "Connection_2" is no
        # longer pending it should be removed from the pending request cache.
        self.assert_request_not_pending(requested_id="123")

    # assertions
    def assert_message_was_broadcasted(self, message, message_type):
        self.assertIn(message, self.gossip.broadcasted[message_type])

    def assert_message_was_not_broadcasted(self, message, message_type):
        if message_type in self.gossip.broadcasted:
            self.assertNotIn(message, self.gossip.broadcasted[message_type])
        else:
            self.assertIsNone(self.gossip.broadcasted.get(message_type))

    def assert_message_not_sent(self, connection_id):
        self.assertIsNone(self.gossip.sent.get(connection_id))

    def assert_message_sent(self, connection_id, message_type):
        self.assertIsNotNone(self.gossip.sent.get(connection_id))
        self.assertTrue(
            self.gossip.sent.get(connection_id)[0][0] == message_type)

    def assert_request_pending(self, requested_id, connection_id):
        self.assertIn(connection_id, self.responder.get_request(requested_id))

    def assert_request_not_pending(self, requested_id, connection_id=None):
        if self.responder.get_request(requested_id) is not None:
            self.assertFalse(
                connection_id in self.responder.get_request(requested_id))
        else:
            self.assertIsNone(self.responder.get_request(requested_id))
Example #6
0
def add(
    dispatcher,
    interconnect,
    gossip,
    completer,
    responder,
    thread_pool,
    sig_pool,
    has_block,
    has_batch,
    permission_verifier,
    consensus_notifier,
):

    # -- Basic Networking -- #
    dispatcher.add_handler(validator_pb2.Message.PING_REQUEST,
                           PingRequestHandler(network=interconnect),
                           thread_pool,
                           priority=Priority.HIGH)

    dispatcher.add_handler(validator_pb2.Message.PING_RESPONSE,
                           PingResponseHandler(), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.NETWORK_CONNECT,
                           ConnectHandler(network=interconnect), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.NETWORK_DISCONNECT,
                           DisconnectHandler(network=interconnect),
                           thread_pool)

    # -- Authorization -- #
    dispatcher.set_message_priority(
        validator_pb2.Message.AUTHORIZATION_CONNECTION_RESPONSE,
        Priority.MEDIUM)

    dispatcher.add_handler(
        validator_pb2.Message.AUTHORIZATION_VIOLATION,
        AuthorizationViolationHandler(network=interconnect, gossip=gossip),
        thread_pool)

    dispatcher.add_handler(validator_pb2.Message.AUTHORIZATION_TRUST_REQUEST,
                           AuthorizationTrustRequestHandler(
                               network=interconnect,
                               permission_verifier=permission_verifier,
                               gossip=gossip),
                           thread_pool,
                           priority=Priority.MEDIUM)

    challenge_request_handler = AuthorizationChallengeRequestHandler(
        network=interconnect)
    dispatcher.add_handler(
        validator_pb2.Message.AUTHORIZATION_CHALLENGE_REQUEST,
        challenge_request_handler,
        thread_pool,
        priority=Priority.MEDIUM)

    dispatcher.add_handler(
        validator_pb2.Message.AUTHORIZATION_CHALLENGE_SUBMIT,
        AuthorizationChallengeSubmitHandler(
            network=interconnect,
            permission_verifier=permission_verifier,
            gossip=gossip,
            cache=challenge_request_handler.get_challenge_payload_cache()),
        thread_pool,
        priority=Priority.MEDIUM)

    # -- Gossip -- #
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_GET_PEERS_REQUEST,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_GET_PEERS_REQUEST,
                           GetPeersRequestHandler(gossip=gossip), thread_pool)

    dispatcher.set_message_priority(
        validator_pb2.Message.GOSSIP_GET_PEERS_REQUEST, Priority.MEDIUM)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_GET_PEERS_RESPONSE,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_GET_PEERS_RESPONSE,
                           GetPeersResponseHandler(gossip=gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_REGISTER,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_REGISTER,
                           PeerRegisterHandler(gossip=gossip), thread_pool)

    dispatcher.set_message_priority(validator_pb2.Message.GOSSIP_REGISTER,
                                    Priority.MEDIUM)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_UNREGISTER,
                           PeerUnregisterHandler(gossip=gossip), thread_pool)

    # GOSSIP_MESSAGE ) Check if this is a block and if we already have it

    dispatcher.set_preprocessor(validator_pb2.Message.GOSSIP_MESSAGE,
                                gossip_message_preprocessor, thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_MESSAGE,
                           GossipMessageDuplicateHandler(), thread_pool)

    # GOSSIP_MESSAGE ) Verify Network Permissions
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_MESSAGE,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    # GOSSIP_MESSAGE ) Verifies signature
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_MESSAGE,
                           signature_verifier.GossipMessageSignatureVerifier(),
                           sig_pool)

    # GOSSIP_MESSAGE ) Verifies batch structure
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_MESSAGE,
                           structure_verifier.GossipHandlerStructureVerifier(),
                           thread_pool)

    # GOSSIP_MESSAGE ) Verifies that the node is allowed to publish a
    # block
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_MESSAGE,
        NetworkConsensusPermissionHandler(
            network=interconnect,
            permission_verifier=permission_verifier,
            gossip=gossip), thread_pool)

    # GOSSIP_MESSAGE ) Determines if this is a consensus message and notifies
    # the consensus engine if it is
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_MESSAGE,
        GossipConsensusHandler(gossip=gossip, notifier=consensus_notifier),
        thread_pool)

    # GOSSIP_MESSAGE ) Determines if we should broadcast the
    # message to our peers. It is important that this occur prior
    # to the sending of the message to the completer, as this step
    # relies on whether the  gossip message has previously been
    # seen by the validator to determine whether or not forwarding
    # should occur
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_MESSAGE,
                           GossipBroadcastHandler(gossip=gossip), thread_pool)

    # GOSSIP_MESSAGE ) Send message to completer
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_MESSAGE,
                           CompleterGossipHandler(completer), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BLOCK_REQUEST,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BLOCK_REQUEST,
                           BlockResponderHandler(responder, gossip),
                           thread_pool)

    dispatcher.set_preprocessor(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
                                gossip_block_response_preprocessor,
                                thread_pool)

    # GOSSIP_BLOCK_RESPONSE 1) Check for duplicate responses
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
                           GossipBlockResponseHandler(completer, responder),
                           thread_pool)

    # GOSSIP_MESSAGE 2) Verify Network Permissions
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    # GOSSIP_BLOCK_RESPONSE 3) Verifies signature
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
        signature_verifier.GossipBlockResponseSignatureVerifier(), sig_pool)

    # GOSSIP_BLOCK_RESPONSE 4) Check batch structure
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
        structure_verifier.GossipBlockResponseStructureVerifier(), thread_pool)

    # GOSSIP_BLOCK_RESPONSE 5) Send message to completer
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
                           CompleterGossipBlockResponseHandler(completer),
                           thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
                           ResponderBlockResponseHandler(responder, gossip),
                           thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST,
        BatchByBatchIdResponderHandler(responder, gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST,
        BatchByTransactionIdResponderHandler(responder, gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.set_preprocessor(validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
                                gossip_batch_response_preprocessor,
                                thread_pool)

    # GOSSIP_BATCH_RESPONSE 1) Check for duplicate responses
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
        GossipBatchResponseHandler(completer, responder, has_batch),
        thread_pool)

    # GOSSIP_BATCH_RESPONSE 2) Verifies signature
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
        signature_verifier.GossipBatchResponseSignatureVerifier(), sig_pool)

    # GOSSIP_BATCH_RESPONSE 3) Check batch structure
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
        structure_verifier.GossipBatchResponseStructureVerifier(), thread_pool)

    # GOSSIP_BATCH_RESPONSE 4) Send message to completer
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
                           CompleterGossipBatchResponseHandler(completer),
                           thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
                           ResponderBatchResponseHandler(responder, gossip),
                           thread_pool)
Example #7
0
class TestResponder(unittest.TestCase):
    def setUp(self):
        self.gossip = MockGossip()
        self.completer = MockCompleter()
        self.responder = Responder(self.completer)
        self.block_request_handler = \
            BlockResponderHandler(self.responder, self.gossip)
        self.block_response_handler = \
            ResponderBlockResponseHandler(self.responder, self.gossip)
        self.batch_request_handler = \
            BatchByBatchIdResponderHandler(self.responder, self.gossip)
        self.batch_response_handler = \
            ResponderBatchResponseHandler(self.responder, self.gossip)
        self.batch_by_txn_request_handler = \
            BatchByTransactionIdResponderHandler(self.responder, self.gossip)

    # Tests
    def test_block_responder_handler(self):
        """
        Test that the BlockResponderHandler correctly broadcasts a received
        request that the Responder cannot respond to, or sends a
        GossipBlockResponse back to the connection_id the handler received
        the request from.
        """
        # The completer does not have the requested block
        message = network_pb2.GossipBlockRequest(block_id="ABC", node_id=b"1")
        self.block_request_handler.handle(
            "Connection_1", message.SerializeToString())
        # If we cannot respond to the request, broadcast the block request
        # and add to pending request
        self.assert_message_was_broadcasted(
            message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST)

        self.assert_request_pending(
            requested_id="ABC", connection_id="Connection_1")
        self.assert_message_not_sent(connection_id="Connection_1")

        # Add the block to the completer and resend the Block Request
        block = block_pb2.Block(header_signature="ABC")
        self.completer.add_block(block)
        self.block_request_handler.handle(
            "Connection_1", message.SerializeToString())

        # Check that the a Block Response was sent back to "Connection_1"
        self.assert_message_sent(
            connection_id="Connection_1",
            message_type=validator_pb2.Message.GOSSIP_BLOCK_RESPONSE
            )

    def test_responder_block_response_handler(self):
        """
        Test that the ResponderBlockResponseHandler, after receiving a Block
        Response, checks to see if the responder has any pending request for
        that response and forwards the response on to the connection_id that
        had requested it.
        """
        # The Responder does not have any pending requests for block "ABC"
        block = block_pb2.Block(header_signature="ABC")
        response_message = network_pb2.GossipBlockResponse(
            content=block.SerializeToString(), node_id=b"1")

        self.block_response_handler.handle(
            "Connection_1", response_message.SerializeToString())

        # ResponderBlockResponseHandler should not send any messages.
        self.assert_message_not_sent("Connection_1")
        self.assert_request_not_pending(requested_id="ABC")

        # Handle a request message for block "ABC". This adds it to the pending
        # request queue.
        request_message = \
            network_pb2.GossipBlockRequest(block_id="ABC", node_id=b"1")

        self.block_request_handler.handle(
            "Connection_2", request_message.SerializeToString())

        self.assert_request_pending(
            requested_id="ABC", connection_id="Connection_2")

        # Handle the the BlockResponse Message. Since Connection_2 had
        # requested the block but it could not be fulfilled at that time of the
        # request the received BlockResponse is forwarded to Connection_2
        self.block_response_handler.handle(
            "Connection_1", response_message.SerializeToString())

        self.assert_message_sent(
            connection_id="Connection_2",
            message_type=validator_pb2.Message.GOSSIP_BLOCK_RESPONSE
            )
        # The request for block "ABC" from "Connection_2" is no longer pending
        # it should be removed from the pending request cache.
        self.assert_request_not_pending(requested_id="ABC")

    def test_batch_by_id_responder_handler(self):
        """
        Test that the BatchByBatchIdResponderHandler correctly broadcasts a
        received request that the Responder cannot respond to, or sends a
        GossipBatchResponse back to the connection_id the handler received
        the request from.
        """
        # The completer does not have the requested batch
        message = network_pb2.GossipBatchByBatchIdRequest(
            id="abc", node_id=b"1")
        self.batch_request_handler.handle(
            "Connection_1", message.SerializeToString())
        # If we cannot respond to the request broadcast batch request and add
        # to pending request
        self.assert_message_was_broadcasted(
            message, validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST)
        self.assert_request_pending(
            requested_id="abc", connection_id="Connection_1")
        self.assert_message_not_sent(connection_id="Connection_1")

        # Add the batch to the completer and resend the BatchByBatchIdRequest
        batch = batch_pb2.Batch(header_signature="abc")
        self.completer.add_batch(batch)
        self.batch_request_handler.handle(
            "Connection_1", message.SerializeToString())

        # Check that the a Batch Response was sent back to "Connection_1"
        self.assert_message_sent(
            connection_id="Connection_1",
            message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE
            )

    def test_batch_by_transaction_id_response_handler(self):
        """
        Test that the BatchByTransactionIdResponderHandler correctly broadcasts
        a received request that the Responder cannot respond to, or sends a
        GossipBatchResponse back to the connection_id the handler received
        the request from.
        """
        # The completer does not have the requested batch with the transaction
        message = network_pb2.GossipBatchByTransactionIdRequest(
            ids=["123"], node_id=b"1")
        self.batch_by_txn_request_handler.handle(
            "Connection_1", message.SerializeToString())

        # If we cannot respond to the request, broadcast batch request and add
        # to pending request
        self.assert_message_was_broadcasted(
            message,
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST
            )
        self.assert_request_pending(
            requested_id="123", connection_id="Connection_1")
        self.assert_message_not_sent(connection_id="Connection_1")

        # Add the batch to the completer and resend the
        # BatchByTransactionIdRequest
        transaction = transaction_pb2.Transaction(header_signature="123")
        batch = batch_pb2.Batch(
            header_signature="abc", transactions=[transaction])
        self.completer.add_batch(batch)
        self.batch_request_handler.handle(
            "Connection_1", message.SerializeToString())

        # Check that the a Batch Response was sent back to "Connection_1"
        self.assert_message_sent(
            connection_id="Connection_1",
            message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE
            )

    def test_batch_by_transaction_id_multiple_txn_ids(self):
        """
        Test that the BatchByTransactionIdResponderHandler correctly broadcasts
        a new request with only the transaction_ids that the Responder cannot
        respond to, and sends a GossipBatchResponse for the transactions_id
        requests that can be satisfied.
        """
        # Add batch that has txn 123
        transaction = transaction_pb2.Transaction(header_signature="123")
        batch = batch_pb2.Batch(
            header_signature="abc", transactions=[transaction])
        self.completer.add_batch(batch)
        # Request transactions 123 and 456
        message = network_pb2.GossipBatchByTransactionIdRequest(
            ids=["123", "456"], node_id=b"1")
        self.batch_by_txn_request_handler.handle(
            "Connection_1", message.SerializeToString())
        self.batch_request_handler.handle(
            "Connection_1", message.SerializeToString())

        # Respond with a BatchResponse for transaction 123
        self.assert_message_sent(
            connection_id="Connection_1",
            message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE
            )

        # Broadcast a BatchByTransactionIdRequest for just 456
        request_message = \
            network_pb2.GossipBatchByTransactionIdRequest(
                ids=["456"], node_id=b"1")
        self.assert_message_was_broadcasted(
            request_message,
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)

        # And set a pending request for 456
        self.assert_request_pending(
            requested_id="456", connection_id="Connection_1")

    def test_responder_batch_response_handler(self):
        """
        Test that the ResponderBatchResponseHandler, after receiving a Batch
        Response, checks to see if the responder has any pending request for
        that batch and forwards the response on to the connection_id that
        had requested it.
        """
        # The Responder does not have any pending requests for block "ABC"
        batch = batch_pb2.Batch(header_signature="abc")

        response_message = network_pb2.GossipBatchResponse(
            content=batch.SerializeToString(), node_id=b"1")

        self.batch_response_handler.handle(
            "Connection_1", response_message.SerializeToString())

        # ResponderBlockResponseHandler should not send any messages.
        self.assert_message_not_sent("Connection_1")
        self.assert_request_not_pending(requested_id="abc")

        # Handle a request message for batch "abc". This adds it to the pending
        # request queue.
        request_message = \
            network_pb2.GossipBatchByBatchIdRequest(id="abc", node_id=b"1")

        self.batch_request_handler.handle(
            "Connection_2", request_message.SerializeToString())

        self.assert_request_pending(
            requested_id="abc", connection_id="Connection_2")

        # Handle the the BatchResponse Message. Since Connection_2 had
        # requested the batch but it could not be fulfilled at that time of the
        # request the received BatchResponse is forwarded to Connection_2
        self.batch_response_handler.handle(
            "Connection_1", response_message.SerializeToString())

        self.assert_message_sent(
            connection_id="Connection_2",
            message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE
            )
        # The request for batch "abc" from "Connection_2" is no longer pending
        # it should be removed from the pending request cache.
        self.assert_request_not_pending(requested_id="abc")

    def test_responder_batch_response_txn_handler(self):
        """
        Test that the ResponderBatchResponseHandler, after receiving a Batch
        Response, checks to see if the responder has any pending request for
        that transactions in the batch and forwards the response on to the
        connection_id that had them.
        """
        transaction = transaction_pb2.Transaction(header_signature="123")
        batch = batch_pb2.Batch(
            header_signature="abc", transactions=[transaction])

        response_message = network_pb2.GossipBatchResponse(
            content=batch.SerializeToString(), node_id=b"1")

        request_message = \
            network_pb2.GossipBatchByTransactionIdRequest(
                ids=["123"], node_id=b"1")

        # Send BatchByTransaciontIdRequest for txn "123" and add it to the
        # pending request cache
        self.batch_request_handler.handle(
            "Connection_2", request_message.SerializeToString())

        self.assert_request_pending(
            requested_id="123", connection_id="Connection_2")

        # Send Batch Response that contains the batch that has txn "123"
        self.batch_response_handler.handle(
            "Connection_1", response_message.SerializeToString())

        # Handle the the BatchResponse Message. Since Connection_2 had
        # requested the txn_id in the batch but it could not be fulfilled at
        # that time of the request the received BatchResponse is forwarded to
        # Connection_2
        self.assert_message_sent(
            connection_id="Connection_2",
            message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE
            )
        # The request for transaction_id "123" from "Connection_2" is no
        # longer pending it should be removed from the pending request cache.
        self.assert_request_not_pending(requested_id="123")

    # assertions
    def assert_message_was_broadcasted(self, message, message_type):
        self.assertIn(message, self.gossip.broadcasted[message_type])

    def assert_message_not_sent(self, connection_id):
        self.assertIsNone(self.gossip.sent.get(connection_id))

    def assert_message_sent(self, connection_id, message_type):
        self.assertIsNotNone(self.gossip.sent.get(connection_id))
        self.assertTrue(self.gossip.sent.get(connection_id)[0][0] == \
            message_type)

    def assert_request_pending(self, requested_id, connection_id):
        self.assertIn(connection_id, self.responder.get_request(requested_id))

    def assert_request_not_pending(self, requested_id):
        self.assertIsNone(self.responder.get_request(requested_id))
Example #8
0
    def __init__(self, network_endpoint, component_endpoint, peer_list,
                 data_dir, key_dir):
        """Constructs a validator instance.

        Args:
            network_endpoint (str): the network endpoint
            component_endpoint (str): the component endpoint
            peer_list (list of str): a list of peer addresses
            data_dir (str): path to the data directory
            key_dir (str): path to the key directory
        """
        db_filename = os.path.join(
            data_dir, 'merkle-{}.lmdb'.format(network_endpoint[-2:]))
        LOGGER.debug('database file is %s', db_filename)

        merkle_db = LMDBNoLockDatabase(db_filename, 'n')
        context_manager = ContextManager(merkle_db)
        state_view_factory = StateViewFactory(merkle_db)

        block_db_filename = os.path.join(
            data_dir, 'block-{}.lmdb'.format(network_endpoint[-2:]))
        LOGGER.debug('block store file is %s', block_db_filename)

        block_db = LMDBNoLockDatabase(block_db_filename, 'n')
        block_store = BlockStore(block_db)

        # setup network
        self._dispatcher = Dispatcher()

        thread_pool = ThreadPoolExecutor(max_workers=10)
        process_pool = ProcessPoolExecutor(max_workers=3)

        self._service = Interconnect(component_endpoint,
                                     self._dispatcher,
                                     secured=False)
        executor = TransactionExecutor(service=self._service,
                                       context_manager=context_manager,
                                       config_view_factory=ConfigViewFactory(
                                           StateViewFactory(merkle_db)))

        identity = hashlib.sha512(time.time().hex().encode()).hexdigest()[:23]

        identity_signing_key = Validator.load_identity_signing_key(
            key_dir, DEFAULT_KEY_NAME)

        network_thread_pool = ThreadPoolExecutor(max_workers=10)

        self._network_dispatcher = Dispatcher()

        # Server public and private keys are hardcoded here due to
        # the decision to avoid having separate identities for each
        # validator's server socket. This is appropriate for a public
        # network. For a permissioned network with requirements for
        # server endpoint authentication at the network level, this can
        # be augmented with a local lookup service for side-band provided
        # endpoint, public_key pairs and a local configuration option
        # for 'server' side private keys.
        self._network = Interconnect(
            network_endpoint,
            dispatcher=self._network_dispatcher,
            identity=identity,
            peer_connections=peer_list,
            secured=True,
            server_public_key=b'wFMwoOt>yFqI/ek.G[tfMMILHWw#vXB[Sv}>l>i)',
            server_private_key=b'r&oJ5aQDj4+V]p2:Lz70Eu0x#m%IwzBdP(}&hWM*')

        self._gossip = Gossip(self._network)

        completer = Completer(block_store, self._gossip)

        block_sender = BroadcastBlockSender(completer, self._gossip)
        chain_id_manager = ChainIdManager(data_dir)
        # Create and configure journal
        self._journal = Journal(
            block_store=block_store,
            state_view_factory=StateViewFactory(merkle_db),
            block_sender=block_sender,
            transaction_executor=executor,
            squash_handler=context_manager.get_squash_handler(),
            identity_signing_key=identity_signing_key,
            chain_id_manager=chain_id_manager)

        self._genesis_controller = GenesisController(
            context_manager=context_manager,
            transaction_executor=executor,
            completer=completer,
            block_store=block_store,
            state_view_factory=state_view_factory,
            identity_key=identity_signing_key,
            data_dir=data_dir,
            chain_id_manager=chain_id_manager)

        responder = Responder(completer)

        completer.set_on_batch_received(self._journal.on_batch_received)
        completer.set_on_block_received(self._journal.on_block_received)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_STATE_GET_REQUEST,
            tp_state_handlers.TpStateGetHandler(context_manager), thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_STATE_SET_REQUEST,
            tp_state_handlers.TpStateSetHandler(context_manager), thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_REGISTER_REQUEST,
            processor_handlers.ProcessorRegisterHandler(executor.processors),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.TP_UNREGISTER_REQUEST,
            processor_handlers.ProcessorUnRegisterHandler(executor.processors),
            thread_pool)

        self._network_dispatcher.add_handler(validator_pb2.Message.GOSSIP_PING,
                                             PingHandler(),
                                             network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_REGISTER,
            PeerRegisterHandler(gossip=self._gossip), network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_UNREGISTER,
            PeerUnregisterHandler(gossip=self._gossip), network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE, GossipMessageHandler(),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE,
            signature_verifier.GossipMessageSignatureVerifier(), process_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE,
            GossipBroadcastHandler(gossip=self._gossip), network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_MESSAGE,
            CompleterGossipHandler(completer), network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BLOCK_REQUEST,
            BlockResponderHandler(responder, self._gossip),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST,
            BatchByBatchIdResponderHandler(responder, self._gossip),
            network_thread_pool)

        self._network_dispatcher.add_handler(
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST,
            BatchByTransactionIdResponderHandler(responder, self._gossip),
            network_thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            signature_verifier.BatchListSignatureVerifier(), process_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            CompleterBatchListBroadcastHandler(completer, self._gossip),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BATCH_STATUS_REQUEST,
            client_handlers.BatchStatusRequest(self._journal.get_block_store(),
                                               completer.batch_cache),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_STATE_LIST_REQUEST,
            client_handlers.StateListRequest(merkle_db,
                                             self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_STATE_GET_REQUEST,
            client_handlers.StateGetRequest(merkle_db,
                                            self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BLOCK_GET_REQUEST,
            client_handlers.BlockGetRequest(self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_BLOCK_LIST_REQUEST,
            client_handlers.BlockListRequest(self._journal.get_block_store()),
            thread_pool)

        self._dispatcher.add_handler(
            validator_pb2.Message.CLIENT_STATE_CURRENT_REQUEST,
            client_handlers.StateCurrentRequest(
                self._journal.get_current_root), thread_pool)
Example #9
0
def add(
    dispatcher,
    interconnect,
    gossip,
    completer,
    responder,
    thread_pool,
    sig_pool,
    permission_verifier,
):

    # -- Basic Networking -- #
    dispatcher.add_handler(validator_pb2.Message.PING_REQUEST,
                           PingHandler(network=interconnect), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.NETWORK_CONNECT,
                           ConnectHandler(network=interconnect), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.NETWORK_DISCONNECT,
                           DisconnectHandler(network=interconnect),
                           thread_pool)

    # -- Authorization -- #
    dispatcher.add_handler(
        validator_pb2.Message.AUTHORIZATION_VIOLATION,
        AuthorizationViolationHandler(network=interconnect, gossip=gossip),
        thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.AUTHORIZATION_TRUST_REQUEST,
        AuthorizationTrustRequestHandler(
            network=interconnect,
            permission_verifier=permission_verifier,
            gossip=gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.AUTHORIZATION_CHALLENGE_REQUEST,
        AuthorizationChallengeRequestHandler(network=interconnect),
        thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.AUTHORIZATION_CHALLENGE_SUBMIT,
        AuthorizationChallengeSubmitHandler(
            network=interconnect,
            permission_verifier=permission_verifier,
            gossip=gossip), thread_pool)

    # -- Gossip -- #
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_GET_PEERS_REQUEST,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_GET_PEERS_REQUEST,
                           GetPeersRequestHandler(gossip=gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_GET_PEERS_RESPONSE,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_GET_PEERS_RESPONSE,
                           GetPeersResponseHandler(gossip=gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_REGISTER,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_REGISTER,
                           PeerRegisterHandler(gossip=gossip), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_UNREGISTER,
                           PeerUnregisterHandler(gossip=gossip), thread_pool)

    # GOSSIP_MESSAGE 1) Sends acknowledgement to the sender
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_MESSAGE,
                           GossipMessageHandler(), thread_pool)

    # GOSSIP_MESSAGE 2) Verify Network Permissions
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_MESSAGE,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    # GOSSIP_MESSAGE 3) Verifies signature
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_MESSAGE,
                           signature_verifier.GossipMessageSignatureVerifier(),
                           sig_pool)

    # GOSSIP_MESSAGE 4) Verifies batch structure
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_MESSAGE,
                           structure_verifier.GossipHandlerStructureVerifier(),
                           thread_pool)

    # GOSSIP_MESSAGE 4) Verifies that the node is allowed to publish a
    # block
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_MESSAGE,
        NetworkConsensusPermissionHandler(
            network=interconnect,
            permission_verifier=permission_verifier,
            gossip=gossip), thread_pool)

    # GOSSIP_MESSAGE 5) Determines if we should broadcast the
    # message to our peers. It is important that this occur prior
    # to the sending of the message to the completer, as this step
    # relies on whether the  gossip message has previously been
    # seen by the validator to determine whether or not forwarding
    # should occur
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_MESSAGE,
        GossipBroadcastHandler(gossip=gossip, completer=completer),
        thread_pool)

    # GOSSIP_MESSAGE 6) Send message to completer
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_MESSAGE,
                           CompleterGossipHandler(completer), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BLOCK_REQUEST,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BLOCK_REQUEST,
                           BlockResponderHandler(responder, gossip),
                           thread_pool)

    # GOSSIP_BLOCK_RESPONSE 1) Sends ack to the sender
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
                           GossipBlockResponseHandler(), thread_pool)

    # GOSSIP_MESSAGE 2) Verify Network Permissions
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    # GOSSIP_BLOCK_RESPONSE 3) Verifies signature
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
        signature_verifier.GossipBlockResponseSignatureVerifier(), sig_pool)

    # GOSSIP_BLOCK_RESPONSE 4) Check batch structure
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
        structure_verifier.GossipBlockResponseStructureVerifier(), thread_pool)

    # GOSSIP_BLOCK_RESPONSE 5) Send message to completer
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
                           CompleterGossipBlockResponseHandler(completer),
                           thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE,
                           ResponderBlockResponseHandler(responder, gossip),
                           thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST,
        BatchByBatchIdResponderHandler(responder, gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST,
        BatchByTransactionIdResponderHandler(responder, gossip), thread_pool)

    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
        NetworkPermissionHandler(network=interconnect,
                                 permission_verifier=permission_verifier,
                                 gossip=gossip), thread_pool)

    # GOSSIP_BATCH_RESPONSE 1) Sends ack to the sender
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
                           GossipBatchResponseHandler(), thread_pool)

    # GOSSIP_BATCH_RESPONSE 2) Verifies signature
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
        signature_verifier.GossipBatchResponseSignatureVerifier(), sig_pool)

    # GOSSIP_BATCH_RESPONSE 3) Check batch structure
    dispatcher.add_handler(
        validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
        structure_verifier.GossipBatchResponseStructureVerifier(), thread_pool)

    # GOSSIP_BATCH_RESPONSE 4) Send message to completer
    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
                           CompleterGossipBatchResponseHandler(completer),
                           thread_pool)

    dispatcher.add_handler(validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
                           ResponderBatchResponseHandler(responder, gossip),
                           thread_pool)