示例#1
0
    def do_batch_by_transaction_id_multiple_txn_ids():

        transaction = transaction_pb2.Transaction(header_signature="123")
        batch = batch_pb2.Batch(header_signature="abc",
                                transactions=[transaction])
        testResponder.completer.add_batch(batch)
        # Request transactions 123 and 456
        message = network_pb2.GossipBatchByTransactionIdRequest(
            ids=["123", "456"], time_to_live=1)
        testResponder.batch_by_txn_request_handler.handle(
            "Connection_1", message.SerializeToString())
        testResponder.batch_request_handler.handle("Connection_1",
                                                   message.SerializeToString())

        # Respond with a BatchResponse for transaction 123
        testResponder.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)

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

        # And set a pending request for 456
        testResponder.assert_request_pending(requested_id="456",
                                             connection_id="Connection_1")
示例#2
0
    def do_batch_by_transaction_id_response_handler():
        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)

        testResponder.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
        testResponder.assert_message_was_broadcasted(
            after_message,
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)
        testResponder.assert_request_pending(requested_id="123",
                                             connection_id="Connection_1")
        testResponder.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])
        testResponder.completer.add_batch(batch)
        testResponder.batch_request_handler.handle("Connection_1",
                                                   message.SerializeToString())

        # Check that the a Batch Response was sent back to "Connection_1"
        testResponder.assert_message_sent(
            connection_id="Connection_1",
            message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE)
示例#3
0
def test_batch_by_transaction_id_multiple_txn_ids():
    """
    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
    testResponder = TestResponder()

    transaction = transaction_pb2.Transaction(header_signature="123")
    batch = batch_pb2.Batch(header_signature="abc", transactions=[transaction])
    testResponder.completer.add_batch(batch)
    # Request transactions 123 and 456
    message = network_pb2.GossipBatchByTransactionIdRequest(ids=["123", "456"],
                                                            time_to_live=1)
    testResponder.batch_by_txn_request_handler.handle(
        "Connection_1", message.SerializeToString())
    testResponder.batch_request_handler.handle("Connection_1",
                                               message.SerializeToString())

    # Respond with a BatchResponse for transaction 123

    # Broadcast a BatchByTransactionIdRequest for just 456
    after_message = \
        network_pb2.GossipBatchByTransactionIdRequest(
            ids=["456"],
            time_to_live=0)
示例#4
0
def test_batch_by_transaction_id_response_handler_requested():
    """
    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
    testResponder = TestResponder()

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

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

    testResponder.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

    testResponder.gossip.clear()

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

    message = network_pb2.GossipBatchByTransactionIdRequest(ids=["123"],
                                                            nonce="2",
                                                            time_to_live=1)
    testResponder.batch_by_txn_request_handler.handle(
        "Connection_2", message.SerializeToString())
示例#5
0
def test_batch_by_transaction_id_response_handler():
    """
    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
    testResponder = TestResponder()

    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)

    testResponder.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
    # 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])
    testResponder.completer.add_batch(batch)
    testResponder.batch_request_handler.handle("Connection_1",
                                               message.SerializeToString())
示例#6
0
    def handle(self, connection_id, message_content):
        batch_request_message = network_pb2.GossipBatchByTransactionIdRequest()
        batch_request_message.ParseFromString(message_content)
        node_id = batch_request_message.node_id
        batch = None
        batches = []
        unfound_txn_ids = []
        for txn_id in batch_request_message.ids:
            batch = self._responder.check_for_batch_by_transaction(
                txn_id)

            # The txn_id was not found.
            if batch is None:
                unfound_txn_ids.append(txn_id)

            # Check to see if a previous txn was in the same batch.
            elif batch not in batches:
                batches.append(batch)

            batch = None

        if batches == []:
            for txn_id in batch_request_message.ids:
                self._responder.add_request(txn_id, connection_id)
            self._gossip.broadcast(
                batch_request_message,
                validator_pb2.Message.
                GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST,
                exclude=[connection_id])

        elif unfound_txn_ids != []:
            new_request = network_pb2.GossipBatchByTransactionIdRequest()
            new_request.ids.extend(unfound_txn_ids)
            new_request.node_id = batch_request_message.node_id
            for txn_id in unfound_txn_ids:
                self._responder.add_request(txn_id, connection_id)
            self._gossip.broadcast(
                new_request,
                validator_pb2.Message.
                GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST,
                exclude=[connection_id])

        if batches != []:
            for batch in batches:
                LOGGER.debug("Responding to batch requests %s",
                             batch.header_signature)

                batch_response = network_pb2.GossipBatchResponse(
                    content=batch.SerializeToString(),
                    node_id=node_id)

                self._gossip.send(validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
                                  batch_response.SerializeToString(),
                                  connection_id)

        return HandlerResult(status=HandlerStatus.PASS)
示例#7
0
    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")
示例#8
0
    def do_responder_batch_response_txn_handler():
        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
        testResponder.batch_request_handler.handle(
            "Connection_2", request_message.SerializeToString())

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

        # Send Batch Response that contains the batch that has txn "123"
        testResponder.batch_response_handler.handle(
            "Connection_1", (batch, 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
        testResponder.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.
        testResponder.assert_request_not_pending(requested_id="123")
示例#9
0
    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)
示例#10
0
def test_responder_batch_response_txn_handler():
    """
    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.
    """

    testResponder = TestResponder()

    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
    testResponder.batch_request_handler.handle(
        "Connection_2", request_message.SerializeToString())

    # Send Batch Response that contains the batch that has txn "123"
    testResponder.batch_response_handler.handle(
        "Connection_1", (batch, response_message.SerializeToString()))
示例#11
0
    def do_batch_by_transaction_id_response_handler_requested():
        before_message = network_pb2.GossipBatchByTransactionIdRequest(
            ids=["123"], time_to_live=1)

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

        testResponder.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
        testResponder.assert_message_was_broadcasted(
            after_message,
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)
        testResponder.assert_request_pending(requested_id="123",
                                             connection_id="Connection_1")
        testResponder.assert_message_not_sent(connection_id="Connection_1")

        testResponder.gossip.clear()

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

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

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

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

        testResponder.assert_message_was_not_broadcasted(
            message,
            validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)
        testResponder.assert_request_pending(requested_id="123",
                                             connection_id="Connection_2")
        testResponder.assert_message_not_sent(connection_id="Connection_2")
示例#12
0
    def handle(self, identity, message_content):
        gossip_message = network_pb2.GossipBatchByTransactionIdRequest()
        gossip_message.ParseFromString(message_content)
        batch = None
        batches = []
        unfound_txn_ids = []
        for txn_id in gossip_message.ids:
            batch = self._responder.check_for_batch_by_transaction(
                txn_id)

            # The txn_id was not found.
            if batch is None:
                unfound_txn_ids.append(txn_id)

            # Check to see if a previous txn was in the same batch.
            elif batch not in batches:
                batches.append(batch)

            batch = None

        if batches == []:
            self._gossip.broadcast(
                gossip_message,
                validator_pb2.Message.
                GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)

        elif unfound_txn_ids != []:
            new_request = network_pb2.GossipBatchByTransactionIdRequest()
            new_request.ids.extend(unfound_txn_ids)
            new_request.node_id = gossip_message.node_id
            self._gossip.broadcast(
                new_request,
                validator_pb2.Message.
                GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)

        if batches != []:
            for batch in batches:
                LOGGER.debug("Responding to batch requests %s",
                             batch.header_signature)
                self._gossip.broadcast_batch(batch)

        return HandlerResult(
            status=HandlerStatus.PASS)
示例#13
0
    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")
示例#14
0
    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"])

        # 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")
示例#15
0
    def handle(self, connection_id, message_content):
        batch_request_message = network_pb2.GossipBatchByTransactionIdRequest()
        batch_request_message.ParseFromString(message_content)
        if batch_request_message.nonce in self._seen_requests:
            LOGGER.debug(
                "Received repeat GossipBatchByTransactionIdRequest"
                " from %s", connection_id)

            return HandlerResult(HandlerStatus.DROP)

        batch = None
        batches = []
        unfound_txn_ids = []
        not_requested = []
        for txn_id in batch_request_message.ids:
            batch = self._responder.check_for_batch_by_transaction(txn_id)

            # The txn_id was not found.
            if batch is None:
                unfound_txn_ids.append(txn_id)
                if not self._responder.already_requested(txn_id):
                    not_requested.append(txn_id)
                else:
                    LOGGER.debug(
                        "Batch containing Transaction %s has already "
                        "been requested", txn_id)

            # Check to see if a previous txn was in the same batch.
            elif batch not in batches:
                batches.append(batch)

            batch = None

        if batches == [] and len(not_requested) == \
                len(batch_request_message.ids):

            if batch_request_message.time_to_live > 0:
                time_to_live = batch_request_message.time_to_live
                batch_request_message.time_to_live = time_to_live - 1
                self._gossip.broadcast(batch_request_message,
                                       validator_pb2.Message.
                                       GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST,
                                       exclude=[connection_id])

                self._seen_requests[batch_request_message.nonce] = \
                    batch_request_message.ids

                for txn_id in batch_request_message.ids:
                    self._responder.add_request(txn_id, connection_id)

        elif unfound_txn_ids != []:
            if not_requested != []:
                if batch_request_message.time_to_live > 0:
                    self._seen_requests[batch_request_message.nonce] = \
                        batch_request_message.ids
                    new_request = \
                        network_pb2.GossipBatchByTransactionIdRequest()
                    # only request batches we have not requested already
                    new_request.ids.extend(not_requested)
                    # Keep same nonce as original message
                    new_request.nonce = batch_request_message.nonce
                    time_to_live = batch_request_message.time_to_live
                    new_request.time_to_live = time_to_live - 1

                    self._gossip.broadcast(
                        new_request,
                        validator_pb2.Message.
                        GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST,
                        exclude=[connection_id])
                    # Add all requests to responder
                    for txn_id in unfound_txn_ids:
                        self._responder.add_request(txn_id, connection_id)
            else:
                # Add all requests to responder
                for txn_id in unfound_txn_ids:
                    self._responder.add_request(txn_id, connection_id)

        if batches != []:
            for batch in batches:
                LOGGER.debug("Responding to batch requests %s",
                             batch.header_signature)

                batch_response = network_pb2.GossipBatchResponse(
                    content=batch.SerializeToString(), )

                self._gossip.send(validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
                                  batch_response.SerializeToString(),
                                  connection_id)

        return HandlerResult(HandlerStatus.PASS)