예제 #1
0
    def start_chain_resolution(self, peer_addr, chain):
        """
        Begin the chain resolution protocol for fetching all data associated with a higher cost chain in 
        the network to allow the current node to mine the correct chain.
        :param peer_addr: The address of the peer with the higher cost chain.
        :param chain: The incomplete higher cost chain that requires resolution.
        :return: None
        """
        # Connect to the peer with the higher cost chain
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            s.connect((peer_addr, Node.REQUEST_PORT))
        except socket.error:
            logging.debug(
                "Error: Unable to connect to peer for chain resolution.")
            return

        # Ask for the peer's block headers from the chain to find
        # the point where the current chain diverges from the higher
        # cost chain
        req = request_pb2.Request()
        req.request_type = request_pb2.RESOLUTION
        req_data = req.SerializeToString()
        msg = framing.frame_segment(req_data)

        logging.debug("Ask for resolution chain from: %s", peer_addr)
        s.sendall(msg)

        # Receive the resolution chain from the peer
        try:
            res_data = framing.receive_framed_segment(s)
        except RuntimeError:
            logging.error("Error receiving resolve chain")
            return
        logging.debug("Received resolution chain")

        # Decode the resolution chain's protocol buffer
        try:
            res_chain = Chain.decode(res_data, False)
        except message.DecodeError:
            logging.error("Error decoding resolve chain: %s", res_data)
            return

        # Notify the miner that the block headers for the longer chain
        # were received to verify if the chain has a higher cost than
        # the current chain and hashes correctly
        is_valid = self.miner.receive_resolution_chain(chain, res_chain)
        if not is_valid:
            logging.error("Invalid resolution chain")
            return

        self.start_block_resolution(s, chain)
예제 #2
0
def generate_request():
    request = request_pb2.Request()

    bits, client_gates = [], []
    for _ in range(1, 280):
        bits.append(float(random.randint(0, 1)))
        client_gates.append(Gate(random.choice('+x')))

    qubits = [x.to_protobuf() for x in send(bits, client_gates)]
    request.qubits.extend(qubits)
    request.gates.extend([x.to_protobuf() for x in client_gates])

    return request, bits, client_gates
예제 #3
0
    async def get_logins(self, request):
        request = request_pb2.Request().FromString(await request.read())
        server_gates, key = self._process_request(request)
        algo = ALGOS[request.algo]

        response = response_pb2.Response()
        response.gates.extend([x.to_protobuf() for x in server_gates])
        logins = []
        for login in await self._db.get_logins():
            logins.append(algo.encrypt(key, login))

        response.option.Extensions[logins_pb2.LOGINS].name.extend(logins)
        return web.Response(body=response.SerializeToString())
예제 #4
0
    def block_mined(self, block, chain_cost):
        """
        The block mined callback that is called when the miner has succeeded in mining a block and adding it
        to the end of the current chain.
        :param block: The block that was mined.
        :param chain_cost: The total cost of the currently mined chain.
        :return: None
        """
        msg = request_pb2.MinedBlockMessage()
        msg.chain_cost = chain_cost
        msg.block = block.encode()

        req = request_pb2.Request()
        req.request_type = request_pb2.MINED_BLOCK
        req.request_message = msg.SerializeToString()
        data = req.SerializeToString()

        self.node_pool.multicast(data, Node.REQUEST_PORT)
예제 #5
0
    async def get_msg(self, request):
        request = request_pb2.Request().FromString(await request.read())
        server_gates, key = self._process_request(request)
        algo = ALGOS[request.algo]

        login = request.option.Extensions[get_msg_pb2.GET_MSG_REQUEST].login

        if await self._db.check_login(login):
            msg = await self._db.get_msg(login)
            encrypted_msg = algo.encrypt(key, msg)

            response = response_pb2.Response()
            response.gates.extend([x.to_protobuf() for x in server_gates])
            get_msg_proto = response.option.Extensions[
                get_msg_pb2.GET_MSG_RESPONSE]
            get_msg_proto.msg = encrypted_msg
            return web.Response(body=response.SerializeToString())
        else:
            return web.Response(status=400)
예제 #6
0
    def handle_blob(self, data, handler):
        """
        Handle a binary object that has been submitted to the block chain network by an outside client. This
        data will be forwarded to this nodes peers.
        :param data: The binary data that has been submitted to be added to the block chain.
        :param handler: The handler that received the message.
        :return: 
        """
        logging.debug("Got a blob " + str(data))

        if self.miner.add(data):
            logging.debug("forward blob to peers")
            req = request_pb2.Request()
            req.request_type = request_pb2.BLOB
            req.request_message = data
            msg = req.SerializeToString()

            self.node_pool.multicast(msg, Node.REQUEST_PORT)
        else:
            logging.debug("received duplicate blob")
예제 #7
0
    def broadcast_thread(self):
        """
        The thread that broadcasts the heartbeat to all peers in the network.
        :return: None
        """
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        msg = request_pb2.DiscoveryMessage()
        msg.node_id = self.node_id

        req = request_pb2.Request()
        req.request_type = request_pb2.DISOVERY
        req.request_message = msg.SerializeToString()
        msg = req.SerializeToString()

        while True:
            sock.sendto(msg, ('255.255.255.255', self.broadcast_port))
            logging.debug("Sent heartbeat")
            time.sleep(self.heartbeat)
예제 #8
0
    def route(self, data, handler):
        """
        Parse the message and route its data to its corresponding handler.
        :param data: The message data as an encoded Request protocol buffer containing the routing 
        information and message body.
        :param handler: The TCP or UDP handler that received the message to be routed.
        :return: None
        """

        # Try to parse the Request using the protocol buffer
        req = request_pb2.Request()
        try:
            req.ParseFromString(data)
        except message.DecodeError:
            logging.error("Error decoding request: %s", data)
            return

        # Call the corresponding request handler
        if req.request_type in self.handlers:
            self.handlers[req.request_type](req.request_message, handler)
        else:
            logging.error("Unsupported request type: %s",
                          request_pb2.RequestType.Name(req.request_type))
예제 #9
0
    def start_block_resolution(self, sock, chain):
        """
        Start the block resolution process for the resolution chain. This involves fetching the block data for 
        any blocks in the chain that are missing their body data. The miner will be notified once the chain has 
        all of its data complete.
        :param sock: The socket to communicate with the peer who has the data.
        :param chain: The chain that has missing block body data.
        :return: None
        """
        res_block_indices = self.miner.get_resolution_block_indices(chain)

        # If all the blocks have both their header and body data
        # then the chain is complete and no block data needs resolving
        if len(res_block_indices) == 0:
            self.miner.receive_complete_chain(chain)
            sock.close()
            return

        logging.debug("Ask for block bodies to populate the resolution chain")

        # Fetch the bodies for any blocks in the chain that are missing them
        msg = request_pb2.BlockResolutionMessage()
        for idx in res_block_indices:
            msg.indices.append(idx)
        msg_data = msg.SerializeToString()

        req = request_pb2.Request()
        req.request_type = request_pb2.BLOCK_RESOLUTION
        req.request_message = msg_data
        req_data = req.SerializeToString()

        data = framing.frame_segment(req_data)
        sock.sendall(data)

        try:
            # Receive the block's body data in order by index
            for idx in res_block_indices:

                block_data = framing.receive_framed_segment(sock)

                # The segment was empty meaning the connection was closed
                # The peer will close the connection if an out of bounds block
                # was requested
                if block_data == b'':
                    logging.error(
                        "Error: Connection closed due to out of bounds index while resolving block data."
                    )
                    self.miner.remove_floating_chain(chain)
                    return

                block = Block.decode(block_data)

                # Bail if adding the received block's data to the chain caused the block's chain of hashes to fail
                if not self.miner.receive_resolution_block(block, idx, chain):
                    logging.error(
                        "Error: Invalid resolution block hash for chain..")
                    self.miner.remove_floating_chain(chain)
                    return

        # Unknown TCP error from the connection failing in the middle of receiving a message
        # Stop block resolution due to losing connection with the peer
        except RuntimeError:
            logging.error(
                "Error: Connection closed while resolving block data.")
            self.miner.remove_floating_chain(chain)
            return

        # Stop block resolution due to a block failing to decode meaning an error occurred with the peer
        except message.DecodeError:
            logging.error("Error: Failed decoding resolution block.")
            self.miner.remove_floating_chain(chain)
            return
        logging.debug("Received block resolution data and completed the chain")

        self.miner.receive_complete_chain(chain)