Esempio n. 1
0
 async def _vote(self, unconfirmed_block: Block):
     exc = None
     try:
         block_version = self.__blockchain.block_versioner.get_version(
             unconfirmed_block.header.height)
         block_verifier = BlockVerifier.new(block_version,
                                            self.__blockchain.tx_versioner)
         block_verifier.invoke_func = self.__channel_service.score_invoke
         reps = self.__channel_service.get_rep_ids()
         logging.debug(
             f"unconfirmed_block.header({unconfirmed_block.header})")
         invoke_results = block_verifier.verify(
             unconfirmed_block,
             self.__blockchain.last_block,
             self.__blockchain,
             self.__blockchain.last_block.header.next_leader,
             reps=reps)
     except Exception as e:
         exc = e
         logging.error(e)
         traceback.print_exc()
     else:
         self.set_invoke_results(unconfirmed_block.header.hash.hex(),
                                 invoke_results)
         self.candidate_blocks.add_block(unconfirmed_block)
     finally:
         self.vote_unconfirmed_block(unconfirmed_block.header.hash,
                                     exc is None)
Esempio n. 2
0
    def __confirm_prev_block_by_sync(self, block_):
        prev_block = self.__blockchain.last_unconfirmed_block
        confirm_info = block_.body.confirm_prev_block

        logging.debug(
            f"block_manager.py >> block_height_sync :: height({prev_block.header.height})"
        )

        block_version = self.get_blockchain().block_versioner.get_version(
            prev_block.header.height)
        block_verifier = BlockVerifier.new(block_version,
                                           self.get_blockchain().tx_versioner)
        if prev_block.header.height == 0:
            block_verifier.invoke_func = self.__channel_service.genesis_invoke
        else:
            block_verifier.invoke_func = self.__channel_service.score_invoke

        reps = self.__channel_service.get_rep_ids()
        invoke_results = block_verifier.verify_loosely(
            prev_block,
            self.__blockchain.last_block,
            self.__blockchain,
            reps=reps)
        self.__blockchain.set_invoke_results(prev_block.header.hash.hex(),
                                             invoke_results)
        return self.__blockchain.add_block(prev_block, confirm_info)
Esempio n. 3
0
    async def node_ws_PublishNewBlock(self, **kwargs):
        if 'error' in kwargs:
            if kwargs.get('code') in CONNECTION_FAIL_CONDITIONS:
                self._exception = ConnectionError(kwargs['error'])
                return
            else:
                return ObjectManager().channel_service.shutdown_peer(
                    message=kwargs.get('error'))

        block_dict, confirm_info_str = kwargs.get('block'), kwargs.get(
            'confirm_info')
        confirm_info = confirm_info_str.encode(
            "utf-8") if confirm_info_str else None
        blockchain = ObjectManager(
        ).channel_service.block_manager.get_blockchain()

        new_block_height = blockchain.block_versioner.get_height(block_dict)
        if new_block_height > blockchain.block_height:
            block_version = blockchain.block_versioner.get_version(
                new_block_height)
            block_serializer = BlockSerializer.new(block_version,
                                                   blockchain.tx_versioner)
            confirmed_block = block_serializer.deserialize(block_dict)

            block_verifier = BlockVerifier.new(block_version,
                                               blockchain.tx_versioner)
            block_verifier.invoke_func = ObjectManager(
            ).channel_service.score_invoke
            reps = ObjectManager().channel_service.get_rep_ids()
            try:
                block_verifier.verify(confirmed_block,
                                      blockchain.last_block,
                                      blockchain,
                                      blockchain.last_block.header.next_leader,
                                      reps=reps)
            except Exception as e:
                self._exception = AnnounceNewBlockError(
                    f"error: {type(e)}, message: {str(e)}")
            else:
                logging.debug(
                    f"add_confirmed_block height({confirmed_block.header.height}), "
                    f"hash({confirmed_block.header.hash.hex()}), confirm_info({confirm_info})"
                )
                ObjectManager(
                ).channel_service.block_manager.add_confirmed_block(
                    confirmed_block=confirmed_block, confirm_info=confirm_info)
Esempio n. 4
0
    def vote_as_peer(self):
        """Vote to AnnounceUnconfirmedBlock
        """
        if self.__unconfirmedBlockQueue.empty():
            return

        unconfirmed_block: Block = self.__unconfirmedBlockQueue.get()
        logging.debug(
            f"we got unconfirmed block ....{unconfirmed_block.header.hash.hex()}"
        )

        my_height = self.__blockchain.block_height
        if my_height < (unconfirmed_block.header.height - 1):
            self.__channel_service.state_machine.block_sync()
            return

        # a block is already added that same height unconfirmed_block height
        if my_height >= unconfirmed_block.header.height:
            return

        logging.info("PeerService received unconfirmed block: " +
                     unconfirmed_block.header.hash.hex())

        block_version = self.__blockchain.block_versioner.get_version(
            unconfirmed_block.header.height)
        block_verifier = BlockVerifier.new(block_version,
                                           self.__blockchain.tx_versioner)
        block_verifier.invoke_func = self.__channel_service.score_invoke

        exception = None
        try:
            invoke_results = block_verifier.verify(
                unconfirmed_block, self.__blockchain.last_block,
                self.__blockchain,
                self.__blockchain.last_block.header.next_leader)
        except Exception as e:
            exception = e
            logging.error(e)
            traceback.print_exc()
        else:
            self.set_invoke_results(unconfirmed_block.header.hash.hex(),
                                    invoke_results)
            self.candidate_blocks.add_block(unconfirmed_block)
        finally:
            self.vote_unconfirmed_block(unconfirmed_block.header.hash,
                                        exception is None)
Esempio n. 5
0
    def __add_block_by_sync(self, block_):
        commit_state = block_.header.commit_state
        logging.debug(
            f"block_manager.py >> block_height_sync :: "
            f"height({block_.header.height}) commit_state({commit_state})")

        block_version = self.get_blockchain().block_versioner.get_version(
            block_.header.height)
        block_verifier = BlockVerifier.new(block_version,
                                           self.get_blockchain().tx_versioner)
        if block_.header.height == 0:
            block_verifier.invoke_func = self.__channel_service.genesis_invoke
        else:
            block_verifier.invoke_func = self.__channel_service.score_invoke
        invoke_results = block_verifier.verify_loosely(
            block_, self.__blockchain.last_block, self.__blockchain)
        self.__blockchain.set_invoke_results(block_.header.hash.hex(),
                                             invoke_results)
        return self.add_block(block_)
Esempio n. 6
0
    def __add_block_by_sync(self, block_, confirm_info=None):
        logging.debug(
            f"block_manager.py >> block_height_sync :: "
            f"height({block_.header.height}) confirm_info({confirm_info})")

        block_version = self.get_blockchain().block_versioner.get_version(
            block_.header.height)
        block_verifier = BlockVerifier.new(block_version,
                                           self.get_blockchain().tx_versioner,
                                           raise_exceptions=False)
        if block_.header.height == 0:
            block_verifier.invoke_func = self.__channel_service.genesis_invoke
        else:
            block_verifier.invoke_func = self.__channel_service.score_invoke

        reps = self.__channel_service.get_rep_ids()
        invoke_results = block_verifier.verify_loosely(
            block_, self.__blockchain.last_block, self.__blockchain, reps=reps)
        need_to_write_tx_info, need_to_score_invoke = True, True
        for exc in block_verifier.exceptions:
            if isinstance(exc, TransactionInvalidDuplicatedHash):
                need_to_write_tx_info = False
            if isinstance(exc, ScoreInvokeError) and not need_to_write_tx_info:
                need_to_score_invoke = False

        exc = next((exc for exc in block_verifier.exceptions
                    if not isinstance(exc, TransactionInvalidDuplicatedHash)),
                   None)
        if exc:
            if isinstance(exc, ScoreInvokeError) and not need_to_score_invoke:
                pass
            else:
                raise exc

        self.__blockchain.set_invoke_results(block_.header.hash.hex(),
                                             invoke_results)
        return self.__blockchain.add_block(block_, confirm_info,
                                           need_to_write_tx_info,
                                           need_to_score_invoke)
Esempio n. 7
0
    async def consensus(self):
        start_time = time.time()
        empty_block: Block = None

        try:
            self._loop = asyncio.get_event_loop()
            self._vote_queue = asyncio.Queue(loop=self._loop)

            block_builder = self._makeup_block()

            if len(block_builder.transactions
                   ) == 0 and not conf.ALLOW_MAKE_EMPTY_BLOCK:
                return

            peer_manager = ObjectManager().channel_service.peer_manager

            last_block = self._blockchain.last_block
            block_builder.height = last_block.header.height + 1
            block_builder.prev_hash = last_block.header.hash
            block_builder.next_leader = Address.fromhex(
                peer_manager.get_next_leader_peer().peer_id)
            block_builder.peer_private_key = ObjectManager(
            ).channel_service.peer_auth.peer_private_key
            block_builder.confirm_prev_block = (self._made_block_count > 0)

            candidate_block = block_builder.build()
            candidate_block, invoke_results = ObjectManager(
            ).channel_service.score_invoke(candidate_block)

            block_verifier = BlockVerifier.new("0.1a")
            block_verifier.verify(candidate_block, self._blockchain.last_block,
                                  self._blockchain)

            logging.info(
                f"candidate block height: {candidate_block.header.height}")
            logging.info(
                f"candidate block hash: {candidate_block.header.hash.hex()}")
            logging.info(
                f"candidate block next leader: {candidate_block.header.next_leader.hex()}"
            )
            logging.info(
                f"candidate block confirm_prev_block: {candidate_block.body.confirm_prev_block}"
            )

            vote = Vote(candidate_block.header.hash.hex(),
                        ObjectManager().channel_service.peer_manager)
            vote.add_vote(ChannelProperty().group_id,
                          ChannelProperty().peer_id, True)

            self._blockmanager.broadcast_send_unconfirmed_block(
                candidate_block)
            success = await self._wait_for_voting(candidate_block, vote)
            if not success:
                return

            self._blockmanager.set_invoke_results(
                candidate_block.header.hash.hex(), invoke_results)
            self._blockmanager.add_block(candidate_block)
            self._made_block_count += 1

            pending_tx = self._txQueue.get_item_in_status(
                TransactionStatusInQueue.normal,
                TransactionStatusInQueue.normal)
            if not pending_tx and not conf.ALLOW_MAKE_EMPTY_BLOCK:
                block_builder = BlockBuilder.new("0.1a")
                block_builder.prev_hash = candidate_block.header.hash
                block_builder.height = candidate_block.header.height + 1
                block_builder.next_leader = candidate_block.header.next_leader
                block_builder.peer_private_key = ObjectManager(
                ).channel_service.peer_auth.peer_private_key
                block_builder.confirm_prev_block = True
                empty_block = block_builder.build()

                self._blockmanager.broadcast_send_unconfirmed_block(
                    empty_block)

                ObjectManager().channel_service.state_machine.turn_to_peer()
        finally:
            if not empty_block:
                elapsed_time = time.time() - start_time
                delay_time = conf.INTERVAL_BLOCKGENERATION - elapsed_time
                self._start_consensus_timer(delay_time)
Esempio n. 8
0
    async def consensus(self):
        util.logger.debug(
            f"-------------------consensus "
            f"candidate_blocks({len(self._blockmanager.candidate_blocks.blocks)})"
        )
        with self.__lock:
            block_builder = self._makeup_block()
            vote_result = None

            if len(block_builder.transactions) > 0:
                # util.logger.debug(f"-------------------consensus logic-1")
                next_leader = ExternalAddress.fromhex(
                    ChannelProperty().peer_id)

                if self._blockchain.last_unconfirmed_block:
                    if (len(self._blockchain.last_unconfirmed_block.body.
                            transactions) > 0) or (
                                len(self._blockchain.last_unconfirmed_block.
                                    body.transactions) == 0 and
                                self._blockchain.last_unconfirmed_block.header.
                                peer_id.hex_hx() != ChannelProperty().peer_id):
                        # util.logger.debug(f"-------------------consensus logic-2")
                        vote = self._blockmanager.candidate_blocks.get_vote(
                            self._blockchain.last_unconfirmed_block.header.hash
                        )
                        vote_result = vote.get_result(
                            self._blockchain.last_unconfirmed_block.header.
                            hash.hex(), conf.VOTING_RATIO)
                        if not vote_result:
                            return self.__block_generation_timer.call()

                        self._blockmanager.add_block(
                            self._blockchain.last_unconfirmed_block, vote)
                        self._made_block_count += 1

                        next_leader = self._blockchain.last_unconfirmed_block.header.next_leader
            else:
                if self._blockchain.last_unconfirmed_block and len(
                        self._blockchain.last_unconfirmed_block.body.
                        transactions) > 0:
                    # util.logger.debug(f"-------------------consensus logic-3")
                    vote = self._blockmanager.candidate_blocks.get_vote(
                        self._blockchain.last_unconfirmed_block.header.hash)
                    vote_result = vote.get_result(
                        self._blockchain.last_unconfirmed_block.header.hash.
                        hex(), conf.VOTING_RATIO)
                    if not vote_result:
                        return self.__block_generation_timer.call()

                    self._blockmanager.add_block(
                        self._blockchain.last_unconfirmed_block, vote)
                    self._made_block_count += 1

                    peer_manager = ObjectManager().channel_service.peer_manager
                    next_leader = ExternalAddress.fromhex(
                        peer_manager.get_next_leader_peer().peer_id)
                else:
                    # util.logger.spam(f"tx count in block({len(block_builder.transactions)})")
                    return self.__block_generation_timer.call()

            last_block = self._blockchain.last_block
            block_builder.height = last_block.header.height + 1
            block_builder.prev_hash = last_block.header.hash
            block_builder.next_leader = next_leader
            block_builder.peer_private_key = ObjectManager(
            ).channel_service.peer_auth.peer_private_key
            block_builder.confirm_prev_block = vote_result or (
                self._made_block_count > 0)

            candidate_block = block_builder.build()
            candidate_block, invoke_results = ObjectManager(
            ).channel_service.score_invoke(candidate_block)
            self._blockmanager.set_invoke_results(
                candidate_block.header.hash.hex(), invoke_results)

            block_verifier = BlockVerifier.new(candidate_block.header.version,
                                               self._blockchain.tx_versioner)
            block_verifier.verify(candidate_block, self._blockchain.last_block,
                                  self._blockchain)

            logging.debug(f"candidate block : {candidate_block.header}")

            self._blockmanager.vote_unconfirmed_block(
                candidate_block.header.hash, True)
            self._blockmanager.candidate_blocks.add_block(candidate_block)

            self._blockchain.last_unconfirmed_block = candidate_block
            broadcast_func = partial(
                self._blockmanager.broadcast_send_unconfirmed_block,
                candidate_block)
            self.__start_broadcast_send_unconfirmed_block_timer(broadcast_func)

            if len(block_builder.transactions) == 0 and not conf.ALLOW_MAKE_EMPTY_BLOCK and \
                    next_leader.hex() != ChannelProperty().peer_id:
                # util.logger.debug(f"-------------------turn_to_peer")
                ObjectManager().channel_service.state_machine.turn_to_peer()
            else:
                self.__block_generation_timer.call()
Esempio n. 9
0
    async def consensus(self):
        util.logger.debug(
            f"-------------------consensus "
            f"candidate_blocks({len(self._block_manager.candidate_blocks.blocks)})"
        )
        with self.__lock:
            complained_result = self._block_manager.epoch.complained_result
            block_builder = self._block_manager.epoch.makeup_block(
                complained_result)
            vote_result = None
            last_unconfirmed_block = self._blockchain.last_unconfirmed_block
            next_leader = ExternalAddress.fromhex(ChannelProperty().peer_id)

            if complained_result:
                util.logger.spam("consensus block_builder.complained")
                confirm_info = self._blockchain.find_confirm_info_by_hash(
                    self._blockchain.last_block.header.hash)
                if not confirm_info and self._blockchain.last_block.header.height > 0:
                    util.logger.spam(
                        "Can't make a block as a leader, this peer will be complained too."
                    )
                    return
                vote_result = True
                self._block_manager.epoch.set_epoch_leader(
                    ChannelProperty().peer_id)
                self._made_block_count += 1
            elif len(block_builder.transactions) > 0:
                util.logger.spam(
                    f"consensus len(block_builder.transactions) > 0")
                if last_unconfirmed_block:
                    if (len(last_unconfirmed_block.body.transactions) > 0
                            or last_unconfirmed_block.header.complained) or (
                                len(last_unconfirmed_block.body.transactions)
                                == 0 and
                                last_unconfirmed_block.header.peer_id.hex_hx()
                                != ChannelProperty().peer_id):
                        vote = self._block_manager.candidate_blocks.get_vote(
                            last_unconfirmed_block.header.hash)
                        vote_result = vote.get_result(
                            last_unconfirmed_block.header.hash.hex(),
                            conf.VOTING_RATIO)
                        if not vote_result:
                            return self.__block_generation_timer.call()

                        self.__add_block(last_unconfirmed_block, vote)

                        next_leader = last_unconfirmed_block.header.next_leader
            else:
                if (last_unconfirmed_block) and (
                        len(last_unconfirmed_block.body.transactions) > 0
                        or last_unconfirmed_block.header.complained):
                    vote = self._block_manager.candidate_blocks.get_vote(
                        last_unconfirmed_block.header.hash)
                    vote_result = vote.get_result(
                        last_unconfirmed_block.header.hash.hex(),
                        conf.VOTING_RATIO)
                    if not vote_result:
                        return self.__block_generation_timer.call()

                    self.__add_block(last_unconfirmed_block, vote)

                    peer_manager = ObjectManager().channel_service.peer_manager
                    next_leader = ExternalAddress.fromhex(
                        peer_manager.get_next_leader_peer(
                            current_leader_peer_id=ChannelProperty().peer_id).
                        peer_id)
                else:
                    return self.__block_generation_timer.call()

            last_block = self._blockchain.last_block
            block_builder.height = last_block.header.height + 1
            block_builder.prev_hash = last_block.header.hash
            block_builder.next_leader = next_leader
            block_builder.peer_private_key = ObjectManager(
            ).channel_service.peer_auth.private_key
            block_builder.confirm_prev_block = vote_result or (
                self._made_block_count > 0)

            candidate_block = block_builder.build()
            candidate_block, invoke_results = ObjectManager(
            ).channel_service.score_invoke(candidate_block)
            self._block_manager.set_invoke_results(
                candidate_block.header.hash.hex(), invoke_results)

            util.logger.spam(f"candidate block : {candidate_block.header}")
            block_verifier = BlockVerifier.new(candidate_block.header.version,
                                               self._blockchain.tx_versioner)
            block_verifier.verify(candidate_block, self._blockchain.last_block,
                                  self._blockchain)

            self._block_manager.vote_unconfirmed_block(
                candidate_block.header.hash, True)
            self._block_manager.candidate_blocks.add_block(candidate_block)

            self._blockchain.last_unconfirmed_block = candidate_block
            broadcast_func = partial(
                self._block_manager.broadcast_send_unconfirmed_block,
                candidate_block)

            # TODO Temporary ignore below line for developing leader complain
            self.__start_broadcast_send_unconfirmed_block_timer(broadcast_func)

            if len(block_builder.transactions) == 0 and not conf.ALLOW_MAKE_EMPTY_BLOCK and \
                    next_leader.hex_hx() != ChannelProperty().peer_id:
                util.logger.spam(f"-------------------turn_to_peer "
                                 f"next_leader({next_leader.hex_hx()}) "
                                 f"peer_id({ChannelProperty().peer_id})")
                await ObjectManager().channel_service.reset_leader(
                    next_leader.hex_hx())
            else:
                self.__block_generation_timer.call()
Esempio n. 10
0
    def test_block_v0_3(self):
        private_auth = test_util.create_default_peer_auth()
        tx_versioner = TransactionVersioner()

        dummy_receipts = {}
        block_builder = BlockBuilder.new("0.3", tx_versioner)
        for i in range(1000):
            tx_builder = TransactionBuilder.new("0x3", tx_versioner)
            tx_builder.private_key = private_auth.private_key
            tx_builder.to_address = ExternalAddress.new()
            tx_builder.step_limit = random.randint(0, 10000)
            tx_builder.value = random.randint(0, 10000)
            tx_builder.nid = 2
            tx = tx_builder.build()

            tx_serializer = TransactionSerializer.new(tx.version, tx_versioner)
            block_builder.transactions[tx.hash] = tx
            dummy_receipts[tx.hash.hex()] = {
                "dummy_receipt": "dummy",
                "tx_dumped": tx_serializer.to_full_data(tx)
            }

        block_builder.peer_private_key = private_auth.private_key
        block_builder.height = 0
        block_builder.state_hash = Hash32(bytes(Hash32.size))
        block_builder.receipts = dummy_receipts
        block_builder.reps = [
            ExternalAddress.fromhex_address(private_auth.address)
        ]
        block_builder.next_leader = ExternalAddress.fromhex(
            "hx00112233445566778899aabbccddeeff00112233")

        block = block_builder.build()
        block_verifier = BlockVerifier.new("0.3", tx_versioner)
        block_verifier.invoke_func = lambda b: (block, dummy_receipts)
        block_verifier.verify(block,
                              None,
                              None,
                              block.header.peer_id,
                              reps=block_builder.reps)

        block_serializer = BlockSerializer.new("0.3", tx_versioner)
        block_serialized = block_serializer.serialize(block)
        block_deserialized = block_serializer.deserialize(block_serialized)

        assert block.header == block_deserialized.header
        # FIXME : confirm_prev_block not serialized
        # assert block.body == block_deserialized.body

        tx_hashes = list(block.body.transactions)
        tx_index = random.randrange(0, len(tx_hashes))

        block_prover = BlockProver.new(block.header.version, tx_hashes,
                                       BlockProverType.Transaction)
        tx_proof = block_prover.get_proof(tx_index)
        assert block_prover.prove(tx_hashes[tx_index],
                                  block.header.transaction_hash, tx_proof)

        block_prover = BlockProver.new(block.header.version,
                                       block_builder.receipts,
                                       BlockProverType.Receipt)
        receipt_proof = block_prover.get_proof(tx_index)
        receipt_hash = block_prover.to_hash32(block_builder.receipts[tx_index])
        assert block_prover.prove(receipt_hash, block.header.receipt_hash,
                                  receipt_proof)