def handle(self, connection_id, message_content): block_request_message = network_pb2.GossipBlockRequest() block_request_message.ParseFromString(message_content) block_id = block_request_message.block_id node_id = block_request_message.node_id block = self._responder.check_for_block(block_id) if block is None: # No block found, broadcast original message to other peers # and add to pending requests if block_id == "HEAD": LOGGER.debug("No chain head available. Cannot respond to block" " requests.") else: self._responder.add_request(block_id, connection_id) self._gossip.broadcast( block_request_message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST, exclude=[connection_id]) else: LOGGER.debug("Responding to block requests: %s", block.get_block().header_signature) block_response = network_pb2.GossipBlockResponse( content=block.get_block().SerializeToString(), node_id=node_id) self._gossip.send(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, block_response.SerializeToString(), connection_id) return HandlerResult(status=HandlerStatus.PASS)
def handle(self, connection_id, message_content): block_response = network_pb2.GossipBlockResponse() block_response.ParseFromString(message_content) block = block_pb2.Block() block.ParseFromString(block_response.content) open_request = self._responder.get_request(block.header_signature) if open_request is None: return HandlerResult(status=HandlerStatus.PASS) for connection in open_request: LOGGER.debug("Responding to block request: Send %s to %s", block.header_signature, connection) try: self._gossip.send(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, message_content, connection) except ValueError: LOGGER.debug( "Can't send block response %s to closed " "connection %s", block.header_signature, connection) self._responder.remove_request(block.header_signature) ack = network_pb2.NetworkAcknowledgement() ack.status = ack.OK return HandlerResult(HandlerStatus.RETURN, message_out=ack, message_type=validator_pb2.Message.NETWORK_ACK)
def test_responder_block_response_handler(): """ 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" testResponder = TestResponder() block = block_pb2.Block(header_signature="ABC") response_message = network_pb2.GossipBlockResponse( content=block.SerializeToString()) testResponder.block_response_handler.handle( "Connection_1", (block, response_message.SerializeToString())) # ResponderBlockResponseHandler should not send any messages. # 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) testResponder.block_request_handler.handle( "Connection_2", request_message.SerializeToString()) # 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 testResponder.block_response_handler.handle( "Connection_1", (block, response_message.SerializeToString()))
def handle(self, connection_id, message_content): block_response_message = network_pb2.GossipBlockResponse() block_response_message.ParseFromString(message_content) block = Block() block.ParseFromString(block_response_message.content) self._completer.add_block(block) return HandlerResult(status=HandlerStatus.PASS)
def handle(self, connection_id, message_content): block_response_message = network_pb2.GossipBlockResponse() block_response_message.ParseFromString(message_content) block = Block() block.ParseFromString(block_response_message.content) LOGGER.debug("CompleterGossipBlockResponseHandler: BLOCK=%s nest=%s", block.header_signature[:8], block_response_message.nest) self._completer.add_block(block, nest=block_response_message.nest) return HandlerResult(status=HandlerStatus.PASS)
def handle(self, connection_id, message_content): block_request_message = network_pb2.GossipBlockRequest() block_request_message.ParseFromString(message_content) if block_request_message.nonce in self._seen_requests: LOGGER.debug("Received repeat GossipBlockRequest from %s", connection_id) ack = network_pb2.NetworkAcknowledgement() ack.status = ack.OK return HandlerResult( HandlerStatus.RETURN, message_out=ack, message_type=validator_pb2.Message.NETWORK_ACK) self._seen_requests[block_request_message.nonce] = \ block_request_message.block_id block_id = block_request_message.block_id node_id = block_request_message.node_id block = self._responder.check_for_block(block_id) if block is None: # No block found, broadcast original message to other peers # and add to pending requests if block_id == "HEAD": LOGGER.debug("No chain head available. Cannot respond to block" " requests.") else: if not self._responder.already_requested(block_id): self._gossip.broadcast( block_request_message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST, exclude=[connection_id]) else: LOGGER.debug("Block %s has already been requested", block_id) self._responder.add_request(block_id, connection_id) else: LOGGER.debug("Responding to block requests: %s", block.get_block().header_signature) block_response = network_pb2.GossipBlockResponse( content=block.get_block().SerializeToString(), node_id=node_id) self._gossip.send(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, block_response.SerializeToString(), connection_id) ack = network_pb2.NetworkAcknowledgement() ack.status = ack.OK return HandlerResult(HandlerStatus.RETURN, message_out=ack, message_type=validator_pb2.Message.NETWORK_ACK)
def handle(self, connection_id, message_content): block_request_message = network_pb2.GossipBlockRequest() block_request_message.ParseFromString(message_content) if block_request_message.nonce in self._seen_requests: LOGGER.debug("Received repeat GossipBlockRequest from %s", connection_id) return HandlerResult(HandlerStatus.DROP) block_id = block_request_message.block_id block = self._responder.check_for_block(block_id) if block is None: # No block found, broadcast original message to other peers # and add to pending requests if block_id == "HEAD": if not self._log_guard.chain_head_not_yet_set: LOGGER.debug("No chain head available; cannot respond to " "block requests") self._log_guard.chain_head_not_yet_set = True else: if not self._responder.already_requested(block_id): if block_request_message.time_to_live > 0: time_to_live = block_request_message.time_to_live block_request_message.time_to_live = time_to_live - 1 self._gossip.broadcast( block_request_message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST, exclude=[connection_id]) self._seen_requests[block_request_message.nonce] = \ block_request_message.block_id self._responder.add_request(block_id, connection_id) else: LOGGER.debug("Block %s has already been requested", block_id) self._responder.add_request(block_id, connection_id) else: LOGGER.debug("Responding to block requests: %s", block.header_signature) block_response = network_pb2.GossipBlockResponse( content=block.SerializeToString()) self._gossip.send(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, block_response.SerializeToString(), connection_id) return HandlerResult(HandlerStatus.PASS)
def handle(self, connection_id, message_content): block_response = network_pb2.GossipBlockResponse() block_response.ParseFromString(message_content) block = block_pb2.Block() block.ParseFromString(block_response.content) open_request = self._responder.get_request(block.header_signature) if open_request is None: return HandlerResult(status=HandlerStatus.PASS) for connection in open_request: LOGGER.debug("Responding to block request: Send %s to %s", block.header_signature, connection) self._gossip.send(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, message_content, connection) self._responder.remove_request(block.header_signature) self._responder.purge_requests() return HandlerResult(status=HandlerStatus.PASS)
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") 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 do_responder_block_response_handler(): block = block_pb2.Block(header_signature="ABC") response_message = network_pb2.GossipBlockResponse( content=block.SerializeToString()) testResponder.block_response_handler.handle( "Connection_1", (block, 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 block "ABC". This adds it to the pending # request queue. request_message = \ network_pb2.GossipBlockRequest(block_id="ABC", time_to_live=1) testResponder.block_request_handler.handle( "Connection_2", request_message.SerializeToString()) testResponder.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 testResponder.block_response_handler.handle( "Connection_1", (block, response_message.SerializeToString())) testResponder.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. testResponder.assert_request_not_pending(requested_id="ABC")
def handle(self, connection_id, message_content): block_request_message = network_pb2.GossipBlockRequest() block_request_message.ParseFromString(message_content) if block_request_message.nonce in self._seen_requests: LOGGER.debug("Received repeat GossipBlockRequest from %s", connection_id) return HandlerResult(HandlerStatus.DROP) """ block_id format - HEAD/ID/N<NUM>.ID """ block_id = block_request_message.block_id block_num = None if block_id[0] == 'N': # contain block number parts = block_id.split('.') block_id = parts[1] block_num = parts[0][1:] block = self._responder.check_for_block(block_id) LOGGER.debug("BlockResponderHandler:ID=%s NUM=%s nonce=%s BLOCK=%s.", block_id if block_id == "HEAD" else block_id[:8], block_num, block_request_message.nonce, block) if block is None: # No block found, broadcast original message to other peers # and add to pending requests if block_id == "HEAD": LOGGER.debug( "No chain head available. Cannot respond to block requests." ) else: if not self._responder.already_requested(block_id): if block_request_message.time_to_live > 0: time_to_live = block_request_message.time_to_live block_request_message.time_to_live = time_to_live - 1 self._gossip.broadcast( block_request_message, validator_pb2.Message.GOSSIP_BLOCK_REQUEST, exclude=[connection_id]) self._seen_requests[ block_request_message. nonce] = block_request_message.block_id self._responder.add_request(block_id, connection_id) else: LOGGER.debug("Block %s has already been requested", block_id[:8]) self._responder.add_request(block_id, connection_id) else: """ check if there is a GAP between block_num and block.block_num send block block_num-1 instead block peer as block """ if block_id != "HEAD": blocks = [] nest = False gap = Federation.gap_feder_num( block_num, block.block_num) if block_num else 0 LOGGER.debug("Responding to block requests: BLOCK=%s GAP=%s", block.get_block().header_signature[:8], gap) if gap > 1: # get block by number num = int(Federation.dec_feder_num(block_num)) # save request self._responder.add_request(block_id, connection_id) try: block = self._responder.get_block_by_num(num) blocks.append(block) LOGGER.debug("Responding BLOCK=%s", block) except KeyError: LOGGER.debug("THERE IS NO Responding BLOCK=%s", num) else: # check may be prev block already was asked blocks.append(block) while True: prev_num = int(Federation.dec_feder_num(block.block_num)) try: block = self._responder.get_block_by_num(prev_num) except KeyError: LOGGER.debug("THERE IS NO Responding BLOCK=%s", prev_num) break prev_block_id = block.get_block().header_signature if self._responder.already_requested(prev_block_id): self._responder.remove_request(prev_block_id) blocks.append(block) else: break else: blocks = block # list of heads nest = True for block in blocks: LOGGER.debug("Responding nest=%s SEND BLOCK=%s", nest, block) block_response = network_pb2.GossipBlockResponse( content=block.get_block().SerializeToString(), nest=nest) self._gossip.send(validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, block_response.SerializeToString(), connection_id) return HandlerResult(HandlerStatus.PASS)