Пример #1
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",
            nonce="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
        message = network_pb2.GossipBatchByTransactionIdRequest(
            ids=["123"],
            node_id=b"1",
            nonce="2")
        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
            )
Пример #2
0
def _create_batch(signer, transactions):
    """Creates a batch from a list of transactions and a signer, and signs
    the resulting batch with the given signing key.

    Args:
        signer (:obj:`Signer`): Cryptographic signer to sign the batch
        transactions (list of `Transaction`): The transactions to add to the
            batch.

    Returns:
        `Batch`: The constructed and signed batch.
    """
    txn_ids = [txn.header_signature for txn in transactions]
    batch_header = batch_pb.BatchHeader(
        signer_public_key=signer.get_public_key().as_hex(),
        transaction_ids=txn_ids).SerializeToString()

    return batch_pb.Batch(header=batch_header,
                          header_signature=signer.sign(batch_header),
                          transactions=transactions)
Пример #3
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"],
                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")
Пример #4
0
def _create_batch(pubkey, signing_key, transactions):
    """Creates a batch from a list of transactions and a public key, and signs
    the resulting batch with the given signing key.

    Args:
        pubkey (str): The public key associated with the signing key.
        signing_key (str): The private key for signing the batch.
        transactions (list of `Transaction`): The transactions to add to the
            batch.

    Returns:
        `Batch`: The constructed and signed batch.
    """
    txn_ids = [txn.header_signature for txn in transactions]
    batch_header = batch_pb.BatchHeader(
        signer_pubkey=pubkey, transaction_ids=txn_ids).SerializeToString()

    return batch_pb.Batch(header=batch_header,
                          header_signature=signing.sign(
                              batch_header, signing_key),
                          transactions=transactions)
Пример #5
0
    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)
Пример #6
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")
Пример #7
0
    def do_responder_batch_response_handler():

        batch = batch_pb2.Batch(header_signature="abc")

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

        testResponder.batch_response_handler.handle(
            "Connection_1", (batch, response_message.SerializeToString()))

        # ResponderBlockResponseHandler should not send any messages.
        testResponder.assert_message_not_sent("Connection_1")
        testResponder.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)

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

        testResponder.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
        testResponder.batch_response_handler.handle(
            "Connection_1", (batch, response_message.SerializeToString()))

        testResponder.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.
        testResponder.assert_request_not_pending(requested_id="abc")
Пример #8
0
    def handle(self, connection_id, message_content):
        batch_response = network_pb2.GossipBatchResponse()
        batch_response.ParseFromString(message_content)
        batch = batch_pb2.Batch()
        batch.ParseFromString(batch_response.content)
        open_request = self._responder.get_request(batch.header_signature)

        if open_request is None:
            open_request = []

        requests_to_remove = [batch.header_signature]
        for txn in batch.transactions:
            requests_by_txn = self._responder.get_request(txn.header_signature)
            if requests_by_txn is not None:
                open_request += requests_by_txn
                requests_to_remove += [txn.header_signature]

        for connection in open_request:
            LOGGER.debug("Responding to batch requests: Send %s to %s",
                         batch.header_signature, connection)
            try:
                self._gossip.send(validator_pb2.Message.GOSSIP_BATCH_RESPONSE,
                                  message_content, connection)
            except ValueError:
                LOGGER.debug(
                    "Can't send batch response %s to closed "
                    "connection %s", batch.header_signature, connection)

        for requested_id in requests_to_remove:
            self._responder.remove_request(requested_id)

        ack = network_pb2.NetworkAcknowledgement()
        ack.status = ack.OK

        return HandlerResult(HandlerStatus.RETURN,
                             message_out=ack,
                             message_type=validator_pb2.Message.NETWORK_ACK)
Пример #9
0
def make_batch(batch_id, txn_id):
    transaction = transaction_pb2.Transaction(header_signature=txn_id)
    batch = batch_pb2.Batch(header_signature=batch_id,
                            transactions=[transaction])

    return batch