Example #1
0
    def test_request_full_message(self, m_reactor, m_logger):
        """
        MessageReceipt is only for Blocks and Transactions, both of which have hashes.
        When you receive the MessageReceipt for them, if you find that you don't have that message corresponding to the
        hash, this is when you call request_full_message()

        If the local node already has the Message, its hash will be in self.master_mr._hash_msg (perhaps it got it
        from another peer). So in that case we check if we requested this hash from any other peer.
        if yes then delete that request and then we go through peer list, who broadcasted this same MR.

        and we request from any one of those peer, and we add that peer into our list, that we already have requested
        from this peer.

        We also make the callLater to the request_full_message, so that in a given interval of time,
        if peer doesn't respond, then we can request to next peer otherwise we can delete all the request, if we
        received it from the peer
        """
        # The local node does not already have this message.
        mrData = qrllegacy_pb2.MRData(type=qrllegacy_pb2.LegacyMessage.SL, hash=b'1234')

        # You can get this Message from channel_1. No, we have not requested this Message from channel_1 yet.
        message_request = MessageRequest()
        message_request.peers_connection_list.append(self.channel_1)
        message_request.already_requested_peers = []
        self.factory.master_mr.requested_hash[b'1234'] = message_request

        self.factory.request_full_message(mrData)

        self.channel_1.send.assert_called_once()

        # We use reactor.callLater() to schedule a call to request_full_message() again in the future.
        # So if this peer doesn't respond, when this function is next called again, it will ignore this peer
        # because of already_requested_peers and use the next one in peers_list.
        m_reactor.callLater.assert_called_once()
Example #2
0
    def test_request_full_message_already_requested_this_message_from_another_peer(
            self, m_reactor, m_logger):
        """
        If we have already requested this Message (from another peer), this function should still go ahead
        and request it from the peer we are currently dealing with.
        """
        # The local node does not already have this message.
        mrData = qrllegacy_pb2.MRData(type=qrllegacy_pb2.LegacyMessage.SL,
                                      hash=b'1234')

        # You can get this Message from channel_1. Also, we already requested this Message from channel_2.
        message_request = MessageRequest()
        message_request.peers_connection_list.append(self.channel_1)
        message_request.already_requested_peers = [self.channel_2]
        self.factory.master_mr.requested_hash[b'1234'] = message_request

        self.factory.request_full_message(mrData)

        # But, the code should ignore channel_2 and ask channel_1 anyway.
        self.channel_1.send.assert_called_once()

        # We use reactor.callLater() to schedule a call to request_full_message() again in the future.
        # So if this peer doesn't respond, when this function is next called again, it will ignore this peer
        # because of already_requested_peers and use the next one in peers_list.
        m_reactor.callLater.assert_called_once()
Example #3
0
 def test_broadcast_does_not_broadcast_to_peers_known_to_have_the_mr(self, m_reactor, m_logger):
     message_request = MessageRequest()
     message_request.peers_connection_list = [self.channel_2, self.channel_3]
     self.factory.master_mr.requested_hash[b'1234'] = message_request
     self.factory.broadcast(qrllegacy_pb2.LegacyMessage.SL, b'1234')
     self.channel_1.send.assert_called_once()
     self.channel_2.send.assert_not_called()
     self.channel_3.send.assert_not_called()
Example #4
0
    def test_request_full_message_no_peer_could_provide_full_message(self, m_reactor, m_logger):
        """
        If this happens, we should forget about the MessageReceipt and its hash completely.
        Optionally punish peers.
        """
        # The local node does not already have this message.
        mrData = qrllegacy_pb2.MRData(type=qrllegacy_pb2.LegacyMessage.SL, hash=b'1234')

        # No idea where we can get this Message from. We haven't requested this Message from anybody.
        message_request = MessageRequest()
        message_request.peers_connection_list = []
        message_request.already_requested_peers = []
        self.factory.master_mr.requested_hash[b'1234'] = message_request

        self.factory.request_full_message(mrData)

        self.channel_1.send.assert_not_called()
        self.assertIsNone(self.factory.master_mr.requested_hash.get(b'1234'))
Example #5
0
    def test_request_full_message_already_requested_this_message_from_same_peer(self, m_reactor, m_logger):
        # The local node does not already have this message.
        mrData = qrllegacy_pb2.MRData(type=qrllegacy_pb2.LegacyMessage.SL, hash=b'1234')

        # You can get this Message from channel_1 and channel_2. Also, we already requested this Message from channel_1.
        message_request = MessageRequest()
        message_request.peers_connection_list = [self.channel_1, self.channel_2]
        message_request.already_requested_peers = [self.channel_1]
        self.factory.master_mr.requested_hash[b'1234'] = message_request

        self.factory.request_full_message(mrData)

        # We should leave channel_1 alone, but we ask channel_2 for the Message.
        self.channel_1.send.assert_not_called()
        self.channel_2.send.assert_called_once()

        # We use reactor.callLater() to schedule a call to request_full_message() again in the future.
        # So if this peer doesn't respond, when this function is next called again, it will ignore this peer
        # because of already_requested_peers and use the next one in peers_list.
        m_reactor.callLater.assert_called_once()
Example #6
0
    def add_peer(self, msg_hash: bytes, msg_type, peer, data=None):
        # Filter
        if msg_type not in self.allowed_types:
            return

        # Limit amount
        if len(self.requested_hash) >= config.dev.message_q_size:
            self.__remove__(self.requested_hash)

        if msg_hash not in self.requested_hash:
            self.requested_hash[msg_hash] = MessageRequest()

        self.requested_hash[msg_hash].add_peer(msg_type, peer, data)
Example #7
0
    def test_request_full_message_we_already_have_this_message(self, m_reactor, m_logger):
        # The local node already has this message!
        mrData = qrllegacy_pb2.MRData(type=qrllegacy_pb2.LegacyMessage.SL, hash=b'1234')
        self.factory.master_mr._hash_msg[b'1234'] = Mock(autospec=Message)
        message_request = MessageRequest()
        message_request.peers_connection_list.append(self.channel_1)
        self.factory.master_mr.requested_hash[b'1234'] = message_request

        self.factory.request_full_message(mrData)

        # Because we already have this message, channel_1 is left alone.
        self.channel_1.send.assert_not_called()
        # Also, this hash should no longer appear in the Master MessageReceipt.
        self.assertIsNone(self.factory.master_mr.requested_hash.get(b'1234'))
Example #8
0
class TestMessageRequest(TestCase):
    def setUp(self):
        self.mr = MessageRequest()

        self.test_data = {"camel": "animal", "bitcoin": "cryptocoin"}

    def test_validate(self):
        # MessageRequest.validate() simply make sure self.params and an arg are the same dict.
        # MessageRequest.params is None
        result = self.mr.validate(self.test_data)
        self.assertFalse(result)

        # MessageRequest.params is the same as the argument
        self.mr.params = self.test_data
        result = self.mr.validate(self.test_data)
        self.assertTrue(result)

        # MessageRequest.params is missing a key compared to the argument
        self.mr.params = {"bitcoin": "cryptocoin"}
        result = self.mr.validate(self.test_data)
        self.assertTrue(result)
        self.mr.params = self.test_data

        # the argument is missing a key that MessageRequest.params has
        result = self.mr.validate({})
        self.assertFalse(result)

        # the argument has different data from MessageRequest.params
        result = self.mr.validate({"camel": "cryptocoin", "bitcoin": "animal"})
        self.assertFalse(result)

    def test_add_peer(self):
        msg_type = Mock(name='mock Message Type')
        peer = Mock(name='mock P2PProtocol')

        self.mr.add_peer(msg_type, peer, params=self.test_data)

        self.assertEqual(self.mr.params, self.test_data)
        self.assertEqual(self.mr.msg_type, msg_type)
        self.assertEqual(self.mr.peers_connection_list, [peer])
Example #9
0
    def setUp(self):
        self.mr = MessageRequest()

        self.test_data = {"camel": "animal", "bitcoin": "cryptocoin"}