Esempio n. 1
0
    def receive_vote(self, json_data):
        '''
        Receive the vote message and make the update:
        (1) Update the inforamtion in given vote storage - 
        prepare certificate.(2) update the node in from_nodes.
        input: 
            json_data: the json_data received by view change vote broadcast:
                {
                    "index": self._index,
                    "view_number": self._follow_view.get_view(),
                    "checkpoint":self._ckpt.get_ckpt_info(),
                    "prepare_certificates":self.get_prepare_certificates(),
                }
        '''
        update_view = None

        prepare_certificates = json_data["prepare_certificates"]

        self._log.debug("%d update prepare_certificate for view %d. %s",
                        self._node_index, json_data['view_number'],
                        str(prepare_certificates))

        for slot in prepare_certificates:
            prepare_certificate = Status.Certificate(
                View(0, self._num_total_nodes))
            prepare_certificate.dumps_from_dict(prepare_certificates[slot])
            # Keep the prepare certificate who has the largest view number
            if slot not in self.prepare_certificate_by_slot or (
                    self.prepare_certificate_by_slot[slot]._view.get_view() <
                (prepare_certificate._view.get_view())):
                self.prepare_certificate_by_slot[slot] = prepare_certificate

        self.from_nodes.add(json_data['index'])
Esempio n. 2
0
    async def commit(self, request):
        '''
        Once receive more than 2f + 1 prepare message,
        send the commit message.
        input:
            request: prepare message from prepare:
                prepare_msg = {
                    'index': self._index,
                    'view': self._n,
                    'proposal': {
                        this_slot: json_data
                    }
                    'type': 'prepare'
                }
        '''
        json_data = await request.json()
        # self._log.info("%d: on commit", self._index)
        self._log.info("%d: receive prepare msg from %d", self._index,
                       json_data['index'])

        # print("\t--->node "+str(self._index)+": receive prepare msg from node "+str(json_data['index']))
        # print(json_data)

        if json_data['view'] < self._follow_view.get_view():
            # when receive message with view < follow_view, do nothing
            return web.Response()

        for slot in json_data['proposal']:
            if not self._legal_slot(slot):
                continue

            if slot not in self._status_by_slot:
                self._status_by_slot[slot] = Status(self._f)
            status = self._status_by_slot[slot]

            view = View(json_data['view'], self._node_cnt)

            status._update_sequence(json_data['type'], view,
                                    json_data['proposal'][slot],
                                    json_data['index'])

            if status._check_majority(json_data['type']):
                status.prepare_certificate = Status.Certificate(
                    view, json_data['proposal'][slot])
                commit_msg = {
                    'index': self._index,
                    'view': json_data['view'],
                    'proposal': {
                        slot: json_data['proposal'][slot]
                    },
                    'type': MessageType.COMMIT
                }
                await self._post(self._nodes, MessageType.REPLY, commit_msg)
        return web.Response()
Esempio n. 3
0
    async def receive_sync(self, request):
        '''
        Update the checkpoint and fill the bubble when receive sync messages.
        input:
            request: {
                'checkpoint': json_data = {
                    'next_slot': self._next_slot
                    'ckpt': json.dumps(ckpt)
                }
                'commit_certificates':commit_certificates
                    (Elements are commit_certificate.to_dict())
            }
        '''
        self._log.info("%d: on receive sync stage.", self._index)
        json_data = await request.json()

        try:
            # print(len(self._status_by_slot))
            # print(self._ckpt.next_slot, self._last_commit_slot + 1)
            # # print(len(json_data['checkpoint']))
            # print('node :' + str(self._index) +' > '+str(self._blockchain.commit_counter)+' : '+str(self._blockchain.length))
            # print()
            # print()
            self.committed_to_blockchain = False
        except Exception as e:
            traceback.print_exc()
            print('for i = ' + str(i))
            print(e)

        self._ckpt.update_checkpoint(json_data['checkpoint'])
        self._last_commit_slot = max(self._last_commit_slot,
                                     self._ckpt.next_slot - 1)
        # TODO: Only check bubble instead of all slots between lowerbound
        # and upperbound of the commit.

        for slot in json_data['commit_certificates']:
            # Skip those slot not qualified for update.
            if int(slot) >= self._ckpt.get_commit_upperbound() or (
                    int(slot) < self._ckpt.next_slot):
                continue

            certificate = json_data['commit_certificates'][slot]
            if slot not in self._status_by_slot:
                self._status_by_slot[slot] = Status(self._f)
                commit_certificate = Status.Certificate(View(
                    0, self._node_cnt))
                commit_certificate.dumps_from_dict(certificate)
                self._status_by_slot[
                    slot].commit_certificate = commit_certificate
            elif not self._status_by_slot[slot].commit_certificate:
                commit_certificate = Status.Certificate(View(
                    0, self._node_cnt))
                commit_certificate.dumps_from_dict(certificate)
                self._status_by_slot[
                    slot].commit_certificate = commit_certificate

        # Commit once the next slot of the last_commit_slot get commit certificate
        while (str(self._last_commit_slot + 1) in self._status_by_slot
               and self._status_by_slot[str(self._last_commit_slot +
                                            1)].commit_certificate):
            self._last_commit_slot += 1

            # When commit messages fill the next checkpoint,
            # propose a new checkpoint.
            if (self._last_commit_slot + 1) % self._checkpoint_interval == 0:
                await self._ckpt.propose_vote(self.get_commit_decisions())

                self._log.info(
                    "%d: During rev_sync, Propose checkpoint with l "
                    "ast slot: %d. In addition, current checkpoint's next_slot is: %d",
                    self._index, self._last_commit_slot, self._ckpt.next_slot)

        await self.dump_to_file()

        return web.Response()
Esempio n. 4
0
    async def reply(self, request):
        '''
        Once receive more than 2f + 1 commit message, append the commit 
        certificate and cannot change anymore. In addition, if there is 
        no bubbles ahead, commit the given slots and update the last_commit_slot.
        input:
            request: commit message from commit:
                preprepare_msg = {
                    'index': self._index,
                    'n': self._n,
                    'proposal': {
                        this_slot: json_data
                    }
                    'type': 'commit'
                }
        '''

        json_data = await request.json()
        # self._log.info(" %d: on reply", self._index)
        # print("\t--->node "+str(self._index)+": on reply ")

        if json_data['view'] < self._follow_view.get_view():
            # when receive message with view < follow_view, do nothing
            return web.Response()

        self._log.info(" %d: receive commit msg from %d", self._index,
                       json_data['index'])

        for slot in json_data['proposal']:
            if not self._legal_slot(slot):
                self._log.error("%d: message %s not in valid slot",
                                self._index, json_data)
                continue

            if slot not in self._status_by_slot:
                self._status_by_slot[slot] = Status(self._f)
            status = self._status_by_slot[slot]

            view = View(json_data['view'], self._node_cnt)

            status._update_sequence(json_data['type'], view,
                                    json_data['proposal'][slot],
                                    json_data['index'])

            # Commit only when no commit certificate and got more than 2f + 1
            if not status.commit_certificate and status._check_majority(
                    json_data['type']):
                status.commit_certificate = Status.Certificate(
                    view, json_data['proposal'][slot])

                self._log.debug("Add commit certifiacte to slot %d", int(slot))

                # Reply only once and only when no bubble ahead
                if self._last_commit_slot == int(
                        slot) - 1 and not status.is_committed:

                    status.is_committed = True
                    self._last_commit_slot += 1
                    if not self._is_leader:
                        self._next_propose_slot += 1

                    #    When commit messages fill the next checkpoint, propose a new checkpoint.
                    if (self._last_commit_slot +
                            1) % self._checkpoint_interval == 0:
                        self._log.info(
                            "%d: Propose checkpoint with last slot: %d. "
                            "In addition, current checkpoint's next_slot is: %d",
                            self._index, self._last_commit_slot,
                            self._ckpt.next_slot)
                        await self._ckpt.propose_vote(
                            self.get_commit_decisions())

                    if (self._last_commit_slot + 1) % self._dump_interval == 0:
                        await self.dump_to_file()

                    reply_msg = {
                        'index': self._index,
                        'view': json_data['view'],
                        'proposal': json_data['proposal'][slot],
                        'type': MessageType.REPLY
                    }
                    try:
                        await self._session.post(
                            json_data['proposal'][slot]['client_url'],
                            json=reply_msg)
                    except:
                        self._log.error(
                            "Send message failed to %s",
                            json_data['proposal'][slot]['client_url'])
                        pass
                    else:
                        self._log.info(
                            "%d reply to %s successfully!!", self._index,
                            json_data['proposal'][slot]['client_url'])

        return web.Response()