github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/validator/tests/test_responder/tests.py (about)

     1  # Copyright 2017 Intel Corporation
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #     http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  
    15  # pylint: disable=invalid-name
    16  
    17  import unittest
    18  
    19  from sawtooth_validator.protobuf import network_pb2
    20  from sawtooth_validator.protobuf import validator_pb2
    21  from sawtooth_validator.protobuf import block_pb2
    22  from sawtooth_validator.protobuf import batch_pb2
    23  from sawtooth_validator.protobuf import transaction_pb2
    24  from sawtooth_validator.journal.responder import Responder
    25  from sawtooth_validator.journal.responder import BlockResponderHandler
    26  from sawtooth_validator.journal.responder import BatchByBatchIdResponderHandler
    27  from sawtooth_validator.journal.responder import \
    28      BatchByTransactionIdResponderHandler
    29  from sawtooth_validator.journal.responder import ResponderBlockResponseHandler
    30  from sawtooth_validator.journal.responder import ResponderBatchResponseHandler
    31  from test_responder.mock import MockGossip
    32  from test_responder.mock import MockCompleter
    33  
    34  
    35  class TestResponder(unittest.TestCase):
    36      def setUp(self):
    37          self.gossip = MockGossip()
    38          self.completer = MockCompleter()
    39          self.responder = Responder(self.completer)
    40          self.block_request_handler = \
    41              BlockResponderHandler(self.responder, self.gossip)
    42          self.block_response_handler = \
    43              ResponderBlockResponseHandler(self.responder, self.gossip)
    44          self.batch_request_handler = \
    45              BatchByBatchIdResponderHandler(self.responder, self.gossip)
    46          self.batch_response_handler = \
    47              ResponderBatchResponseHandler(self.responder, self.gossip)
    48          self.batch_by_txn_request_handler = \
    49              BatchByTransactionIdResponderHandler(self.responder, self.gossip)
    50  
    51      # Tests
    52      def test_block_responder_handler(self):
    53          """
    54          Test that the BlockResponderHandler correctly broadcasts a received
    55          request that the Responder cannot respond to, or sends a
    56          GossipBlockResponse back to the connection_id the handler received
    57          the request from.
    58          """
    59          # The completer does not have the requested block
    60          before_message = network_pb2.GossipBlockRequest(
    61              block_id="ABC",
    62              nonce="1",
    63              time_to_live=1)
    64  
    65          after_message = network_pb2.GossipBlockRequest(
    66              block_id="ABC",
    67              nonce="1",
    68              time_to_live=0)
    69  
    70          self.block_request_handler.handle(
    71              "Connection_1", before_message.SerializeToString())
    72          # If we cannot respond to the request, broadcast the block request
    73          # and add to pending request
    74          self.assert_message_was_broadcasted(
    75              after_message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST)
    76  
    77          self.assert_request_pending(
    78              requested_id="ABC", connection_id="Connection_1")
    79          self.assert_message_not_sent(connection_id="Connection_1")
    80  
    81          # Add the block to the completer and resend the Block Request
    82          block = block_pb2.Block(header_signature="ABC")
    83          self.completer.add_block(block)
    84  
    85          message = network_pb2.GossipBlockRequest(
    86              block_id="ABC",
    87              nonce="2",
    88              time_to_live=1)
    89  
    90          self.block_request_handler.handle(
    91              "Connection_1", message.SerializeToString())
    92  
    93          # Check that the a Block Response was sent back to "Connection_1"
    94          self.assert_message_sent(
    95              connection_id="Connection_1",
    96              message_type=validator_pb2.Message.GOSSIP_BLOCK_RESPONSE
    97          )
    98  
    99      def test_block_responder_handler_requested(self):
   100          """
   101          Test that the BlockResponderHandler correctly broadcasts a received
   102          request that the Responder cannot respond to, and does not rebroadcast
   103          the same request.  If we have already recieved the
   104          request, do nothing.
   105          """
   106          before_message = network_pb2.GossipBlockRequest(
   107              block_id="ABC",
   108              nonce="1",
   109              time_to_live=1)
   110  
   111          after_message = network_pb2.GossipBlockRequest(
   112              block_id="ABC",
   113              nonce="1",
   114              time_to_live=0)
   115  
   116          self.block_request_handler.handle(
   117              "Connection_1", before_message.SerializeToString())
   118          # If we cannot respond to the request, broadcast the block request
   119          # and add to pending request
   120          self.assert_message_was_broadcasted(
   121              after_message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST)
   122  
   123          self.assert_request_pending(
   124              requested_id="ABC", connection_id="Connection_1")
   125          self.assert_message_not_sent(connection_id="Connection_1")
   126  
   127          self.gossip.clear()
   128  
   129          # Message should be dropped since the same message has already been
   130          # handled
   131          self.block_request_handler.handle(
   132              "Connection_2", before_message.SerializeToString())
   133  
   134          self.assert_message_was_not_broadcasted(
   135              before_message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST)
   136  
   137          self.assert_request_not_pending(
   138              requested_id="ABC", connection_id="Connection_2")
   139  
   140          message = network_pb2.GossipBlockRequest(
   141              block_id="ABC",
   142              nonce="2",
   143              time_to_live=1)
   144  
   145          self.block_request_handler.handle(
   146              "Connection_2", message.SerializeToString())
   147  
   148          self.assert_message_was_not_broadcasted(
   149              message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST)
   150  
   151          self.assert_request_pending(
   152              requested_id="ABC", connection_id="Connection_2")
   153          self.assert_message_not_sent(connection_id="Connection_2")
   154  
   155      def test_responder_block_response_handler(self):
   156          """
   157          Test that the ResponderBlockResponseHandler, after receiving a Block
   158          Response, checks to see if the responder has any pending request for
   159          that response and forwards the response on to the connection_id that
   160          had requested it.
   161          """
   162          # The Responder does not have any pending requests for block "ABC"
   163          block = block_pb2.Block(header_signature="ABC")
   164          response_message = network_pb2.GossipBlockResponse(
   165              content=block.SerializeToString())
   166  
   167          self.block_response_handler.handle(
   168              "Connection_1", (block, response_message.SerializeToString()))
   169  
   170          # ResponderBlockResponseHandler should not send any messages.
   171          self.assert_message_not_sent("Connection_1")
   172          self.assert_request_not_pending(requested_id="ABC")
   173  
   174          # Handle a request message for block "ABC". This adds it to the pending
   175          # request queue.
   176          request_message = \
   177              network_pb2.GossipBlockRequest(block_id="ABC", time_to_live=1)
   178  
   179          self.block_request_handler.handle(
   180              "Connection_2", request_message.SerializeToString())
   181  
   182          self.assert_request_pending(
   183              requested_id="ABC", connection_id="Connection_2")
   184  
   185          # Handle the the BlockResponse Message. Since Connection_2 had
   186          # requested the block but it could not be fulfilled at that time of the
   187          # request the received BlockResponse is forwarded to Connection_2
   188          self.block_response_handler.handle(
   189              "Connection_1", (block, response_message.SerializeToString()))
   190  
   191          self.assert_message_sent(
   192              connection_id="Connection_2",
   193              message_type=validator_pb2.Message.GOSSIP_BLOCK_RESPONSE
   194          )
   195          # The request for block "ABC" from "Connection_2" is no longer pending
   196          # it should be removed from the pending request cache.
   197          self.assert_request_not_pending(requested_id="ABC")
   198  
   199      def test_batch_by_id_responder_handler(self):
   200          """
   201          Test that the BatchByBatchIdResponderHandler correctly broadcasts a
   202          received request that the Responder cannot respond to, or sends a
   203          GossipBatchResponse back to the connection_id the handler received
   204          the request from.
   205          """
   206          # The completer does not have the requested batch
   207          before_message = network_pb2.GossipBatchByBatchIdRequest(
   208              id="abc",
   209              nonce="1",
   210              time_to_live=1)
   211  
   212          after_message = network_pb2.GossipBatchByBatchIdRequest(
   213              id="abc",
   214              nonce="1",
   215              time_to_live=0)
   216  
   217          self.batch_request_handler.handle(
   218              "Connection_1", before_message.SerializeToString())
   219          # If we cannot respond to the request broadcast batch request and add
   220          # to pending request
   221          self.assert_message_was_broadcasted(
   222              after_message,
   223              validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST)
   224          self.assert_request_pending(
   225              requested_id="abc", connection_id="Connection_1")
   226          self.assert_message_not_sent(connection_id="Connection_1")
   227  
   228          # Add the batch to the completer and resend the BatchByBatchIdRequest
   229          message = network_pb2.GossipBatchByBatchIdRequest(
   230              id="abc",
   231              nonce="2",
   232              time_to_live=1)
   233          batch = batch_pb2.Batch(header_signature="abc")
   234          self.completer.add_batch(batch)
   235          self.batch_request_handler.handle(
   236              "Connection_1", message.SerializeToString())
   237  
   238          # Check that the a Batch Response was sent back to "Connection_1"
   239          self.assert_message_sent(
   240              connection_id="Connection_1",
   241              message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE
   242          )
   243  
   244      def test_batch_by_id_responder_handler_requested(self):
   245          """
   246          Test that the BatchByBatchIdResponderHandler correctly broadcasts
   247          a received request that the Responder cannot respond to, and does not
   248          rebroadcast the same request again.  If we have already recieved the
   249          request, do nothing.
   250          """
   251          # The completer does not have the requested batch
   252          before_message = network_pb2.GossipBatchByBatchIdRequest(
   253              id="abc",
   254              nonce="1",
   255              time_to_live=1)
   256  
   257          after_message = network_pb2.GossipBatchByBatchIdRequest(
   258              id="abc",
   259              nonce="1",
   260              time_to_live=0)
   261          self.batch_request_handler.handle(
   262              "Connection_1", before_message.SerializeToString())
   263          # If we cannot respond to the request broadcast batch request and add
   264          # to pending request
   265          self.assert_message_was_broadcasted(
   266              after_message,
   267              validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST)
   268          self.assert_request_pending(
   269              requested_id="abc", connection_id="Connection_1")
   270          self.assert_message_not_sent(connection_id="Connection_1")
   271  
   272          self.gossip.clear()
   273  
   274          # Message should be dropped since the same message has already been
   275          # handled
   276          self.batch_request_handler.handle(
   277              "Connection_2", before_message.SerializeToString())
   278  
   279          self.assert_message_was_not_broadcasted(
   280              before_message,
   281              validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST)
   282  
   283          self.assert_request_not_pending(
   284              requested_id="abc", connection_id="Connection_2")
   285  
   286          message = network_pb2.GossipBatchByBatchIdRequest(
   287              id="abc",
   288              nonce="2",
   289              time_to_live=1)
   290  
   291          self.batch_request_handler.handle(
   292              "Connection_2", message.SerializeToString())
   293  
   294          self.assert_message_was_not_broadcasted(
   295              message, validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST)
   296  
   297          self.assert_request_pending(
   298              requested_id="abc", connection_id="Connection_2")
   299          self.assert_message_not_sent(connection_id="Connection_2")
   300  
   301      def test_batch_by_transaction_id_response_handler(self):
   302          """
   303          Test that the BatchByTransactionIdResponderHandler correctly broadcasts
   304          a received request that the Responder cannot respond to, or sends a
   305          GossipBatchResponse back to the connection_id the handler received
   306          the request from.
   307          """
   308          # The completer does not have the requested batch with the transaction
   309          before_message = network_pb2.GossipBatchByTransactionIdRequest(
   310              ids=["123"],
   311              nonce="1",
   312              time_to_live=1)
   313  
   314          after_message = network_pb2.GossipBatchByTransactionIdRequest(
   315              ids=["123"],
   316              nonce="1",
   317              time_to_live=0)
   318  
   319          self.batch_by_txn_request_handler.handle(
   320              "Connection_1", before_message.SerializeToString())
   321  
   322          # If we cannot respond to the request, broadcast batch request and add
   323          # to pending request
   324          self.assert_message_was_broadcasted(
   325              after_message,
   326              validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST
   327          )
   328          self.assert_request_pending(
   329              requested_id="123", connection_id="Connection_1")
   330          self.assert_message_not_sent(connection_id="Connection_1")
   331  
   332          # Add the batch to the completer and resend the
   333          # BatchByTransactionIdRequest
   334          message = network_pb2.GossipBatchByTransactionIdRequest(
   335              ids=["123"],
   336              nonce="2",
   337              time_to_live=1)
   338          transaction = transaction_pb2.Transaction(header_signature="123")
   339          batch = batch_pb2.Batch(
   340              header_signature="abc", transactions=[transaction])
   341          self.completer.add_batch(batch)
   342          self.batch_request_handler.handle(
   343              "Connection_1", message.SerializeToString())
   344  
   345          # Check that the a Batch Response was sent back to "Connection_1"
   346          self.assert_message_sent(
   347              connection_id="Connection_1",
   348              message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE
   349          )
   350  
   351      def test_batch_by_transaction_id_response_handler_requested(self):
   352          """
   353          Test that the BatchByTransactionIdResponderHandler correctly broadcasts
   354          a received request that the Responder cannot respond to, and does not
   355          rebroadcast the same request again. If we have already recieved the
   356          request, do nothing.
   357          """
   358          # The completer does not have the requested batch with the transaction
   359          before_message = network_pb2.GossipBatchByTransactionIdRequest(
   360              ids=["123"],
   361              time_to_live=1)
   362  
   363          after_message = network_pb2.GossipBatchByTransactionIdRequest(
   364              ids=["123"],
   365              time_to_live=0)
   366  
   367          self.batch_by_txn_request_handler.handle(
   368              "Connection_1", before_message.SerializeToString())
   369  
   370          # If we cannot respond to the request, broadcast batch request and add
   371          # to pending request
   372          self.assert_message_was_broadcasted(
   373              after_message,
   374              validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST
   375          )
   376          self.assert_request_pending(
   377              requested_id="123", connection_id="Connection_1")
   378          self.assert_message_not_sent(connection_id="Connection_1")
   379  
   380          self.gossip.clear()
   381  
   382          # Message should be dropped since the same message has already been
   383          # handled
   384          self.batch_by_txn_request_handler.handle(
   385              "Connection_2", before_message.SerializeToString())
   386  
   387          self.assert_message_was_not_broadcasted(
   388              after_message,
   389              validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST
   390          )
   391  
   392          self.assert_request_not_pending(
   393              requested_id="123", connection_id="Connection_2")
   394  
   395          message = network_pb2.GossipBatchByTransactionIdRequest(
   396              ids=["123"],
   397              nonce="2",
   398              time_to_live=1)
   399          self.batch_by_txn_request_handler.handle(
   400              "Connection_2", message.SerializeToString())
   401  
   402          self.assert_message_was_not_broadcasted(
   403              message,
   404              validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST
   405          )
   406          self.assert_request_pending(
   407              requested_id="123", connection_id="Connection_2")
   408          self.assert_message_not_sent(connection_id="Connection_2")
   409  
   410      def test_batch_by_transaction_id_multiple_txn_ids(self):
   411          """
   412          Test that the BatchByTransactionIdResponderHandler correctly broadcasts
   413          a new request with only the transaction_ids that the Responder cannot
   414          respond to, and sends a GossipBatchResponse for the transactions_id
   415          requests that can be satisfied.
   416          """
   417          # Add batch that has txn 123
   418          transaction = transaction_pb2.Transaction(header_signature="123")
   419          batch = batch_pb2.Batch(
   420              header_signature="abc", transactions=[transaction])
   421          self.completer.add_batch(batch)
   422          # Request transactions 123 and 456
   423          message = network_pb2.GossipBatchByTransactionIdRequest(
   424              ids=["123", "456"],
   425              time_to_live=1)
   426          self.batch_by_txn_request_handler.handle(
   427              "Connection_1", message.SerializeToString())
   428          self.batch_request_handler.handle(
   429              "Connection_1", message.SerializeToString())
   430  
   431          # Respond with a BatchResponse for transaction 123
   432          self.assert_message_sent(
   433              connection_id="Connection_1",
   434              message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE
   435          )
   436  
   437          # Broadcast a BatchByTransactionIdRequest for just 456
   438          after_message = \
   439              network_pb2.GossipBatchByTransactionIdRequest(
   440                  ids=["456"],
   441                  time_to_live=0)
   442  
   443          self.assert_message_was_broadcasted(
   444              after_message,
   445              validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST)
   446  
   447          # And set a pending request for 456
   448          self.assert_request_pending(
   449              requested_id="456", connection_id="Connection_1")
   450  
   451      def test_responder_batch_response_handler(self):
   452          """
   453          Test that the ResponderBatchResponseHandler, after receiving a Batch
   454          Response, checks to see if the responder has any pending request for
   455          that batch and forwards the response on to the connection_id that
   456          had requested it.
   457          """
   458          # The Responder does not have any pending requests for block "ABC"
   459          batch = batch_pb2.Batch(header_signature="abc")
   460  
   461          response_message = network_pb2.GossipBatchResponse(
   462              content=batch.SerializeToString())
   463  
   464          self.batch_response_handler.handle(
   465              "Connection_1", (batch, response_message.SerializeToString()))
   466  
   467          # ResponderBlockResponseHandler should not send any messages.
   468          self.assert_message_not_sent("Connection_1")
   469          self.assert_request_not_pending(requested_id="abc")
   470  
   471          # Handle a request message for batch "abc". This adds it to the pending
   472          # request queue.
   473          request_message = \
   474              network_pb2.GossipBatchByBatchIdRequest(id="abc", time_to_live=1)
   475  
   476          self.batch_request_handler.handle(
   477              "Connection_2", request_message.SerializeToString())
   478  
   479          self.assert_request_pending(
   480              requested_id="abc", connection_id="Connection_2")
   481  
   482          # Handle the the BatchResponse Message. Since Connection_2 had
   483          # requested the batch but it could not be fulfilled at that time of the
   484          # request the received BatchResponse is forwarded to Connection_2
   485          self.batch_response_handler.handle(
   486              "Connection_1", (batch, response_message.SerializeToString()))
   487  
   488          self.assert_message_sent(
   489              connection_id="Connection_2",
   490              message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE
   491          )
   492          # The request for batch "abc" from "Connection_2" is no longer pending
   493          # it should be removed from the pending request cache.
   494          self.assert_request_not_pending(requested_id="abc")
   495  
   496      def test_responder_batch_response_txn_handler(self):
   497          """
   498          Test that the ResponderBatchResponseHandler, after receiving a Batch
   499          Response, checks to see if the responder has any pending request for
   500          that transactions in the batch and forwards the response on to the
   501          connection_id that had them.
   502          """
   503          transaction = transaction_pb2.Transaction(header_signature="123")
   504          batch = batch_pb2.Batch(
   505              header_signature="abc", transactions=[transaction])
   506  
   507          response_message = network_pb2.GossipBatchResponse(
   508              content=batch.SerializeToString())
   509  
   510          request_message = \
   511              network_pb2.GossipBatchByTransactionIdRequest(
   512                  ids=["123"],
   513                  time_to_live=1)
   514  
   515          # Send BatchByTransaciontIdRequest for txn "123" and add it to the
   516          # pending request cache
   517          self.batch_request_handler.handle(
   518              "Connection_2", request_message.SerializeToString())
   519  
   520          self.assert_request_pending(
   521              requested_id="123", connection_id="Connection_2")
   522  
   523          # Send Batch Response that contains the batch that has txn "123"
   524          self.batch_response_handler.handle(
   525              "Connection_1", (batch, response_message.SerializeToString()))
   526  
   527          # Handle the the BatchResponse Message. Since Connection_2 had
   528          # requested the txn_id in the batch but it could not be fulfilled at
   529          # that time of the request the received BatchResponse is forwarded to
   530          # Connection_2
   531          self.assert_message_sent(
   532              connection_id="Connection_2",
   533              message_type=validator_pb2.Message.GOSSIP_BATCH_RESPONSE
   534          )
   535          # The request for transaction_id "123" from "Connection_2" is no
   536          # longer pending it should be removed from the pending request cache.
   537          self.assert_request_not_pending(requested_id="123")
   538  
   539      # assertions
   540      def assert_message_was_broadcasted(self, message, message_type):
   541          self.assertIn(message, self.gossip.broadcasted[message_type])
   542  
   543      def assert_message_was_not_broadcasted(self, message, message_type):
   544          if message_type in self.gossip.broadcasted:
   545              self.assertNotIn(message, self.gossip.broadcasted[message_type])
   546          else:
   547              self.assertIsNone(self.gossip.broadcasted.get(message_type))
   548  
   549      def assert_message_not_sent(self, connection_id):
   550          self.assertIsNone(self.gossip.sent.get(connection_id))
   551  
   552      def assert_message_sent(self, connection_id, message_type):
   553          self.assertIsNotNone(self.gossip.sent.get(connection_id))
   554          self.assertTrue(
   555              self.gossip.sent.get(connection_id)[0][0] == message_type)
   556  
   557      def assert_request_pending(self, requested_id, connection_id):
   558          self.assertIn(connection_id, self.responder.get_request(requested_id))
   559  
   560      def assert_request_not_pending(self, requested_id, connection_id=None):
   561          if self.responder.get_request(requested_id) is not None:
   562              self.assertFalse(
   563                  connection_id in self.responder.get_request(requested_id))
   564          else:
   565              self.assertIsNone(self.responder.get_request(requested_id))