Esempio n. 1
0
    def verify_confirm_info(self, unconfirmed_block: Block):
        unconfirmed_header = unconfirmed_block.header
        my_height = self.blockchain.block_height
        if my_height < (unconfirmed_header.height - 2):
            raise ConfirmInfoInvalidNeedBlockSync(
                f"trigger block sync: my_height({my_height}), "
                f"unconfirmed_block.header.height({unconfirmed_header.height})"
            )

        is_rep = ObjectManager().channel_service.is_support_node_function(
            conf.NodeFunction.Vote)
        if is_rep and my_height == unconfirmed_header.height - 2 and not self.blockchain.last_unconfirmed_block:
            raise ConfirmInfoInvalidNeedBlockSync(
                f"trigger block sync: my_height({my_height}), "
                f"unconfirmed_block.header.height({unconfirmed_header.height})"
            )

        # a block is already added that same height unconfirmed_block height
        if my_height >= unconfirmed_header.height:
            raise ConfirmInfoInvalidAddedBlock(
                f"block is already added my_height({my_height}), "
                f"unconfirmed_block.header.height({unconfirmed_header.height})"
            )

        block_verifier = BlockVerifier.new(unconfirmed_header.version,
                                           self.blockchain.tx_versioner)
        prev_block = self.blockchain.get_prev_block(unconfirmed_block)
        reps_getter = self.blockchain.find_preps_addresses_by_roothash

        util.logger.spam(
            f"prev_block: {prev_block.header.hash if prev_block else None}")
        if not prev_block:
            raise NotReadyToConfirmInfo(
                "There is no prev block or not ready to confirm block (Maybe node is starting)"
            )

        try:
            if prev_block and prev_block.header.reps_hash and unconfirmed_header.height > 1:
                prev_reps = reps_getter(prev_block.header.reps_hash)
                block_verifier.verify_prev_votes(unconfirmed_block, prev_reps)
        except Exception as e:
            util.logger.warning(e)
            traceback.print_exc()
            raise ConfirmInfoInvalid(
                "Unconfirmed block has no valid confirm info for previous block"
            )
Esempio n. 2
0
    def __add_block_by_sync(self, block_, confirm_info=None):
        util.logger.debug(
            f"__add_block_by_sync :: height({block_.header.height}) hash({block_.header.hash})"
        )

        block_version = self.blockchain.block_versioner.get_version(
            block_.header.height)
        block_verifier = BlockVerifier.new(block_version,
                                           self.blockchain.tx_versioner,
                                           raise_exceptions=False)
        block_verifier.invoke_func = self.blockchain.get_invoke_func(
            block_.header.height)

        reps_getter = self.blockchain.find_preps_addresses_by_roothash
        block_verifier.verify_loosely(block_,
                                      self.blockchain.last_block,
                                      self.blockchain,
                                      reps_getter=reps_getter)
        need_to_write_tx_info, need_to_score_invoke = True, True
        for exc in block_verifier.exceptions:
            if isinstance(exc, TransactionDuplicatedHashError):
                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, TransactionDuplicatedHashError)),
                   None)
        if exc:
            if isinstance(exc, ScoreInvokeError) and not need_to_score_invoke:
                pass
            else:
                raise exc

        if parse_version(block_.header.version) >= parse_version("0.3"):
            reps = reps_getter(block_.header.reps_hash)
            round_ = next(vote for vote in confirm_info if vote).round
            votes = Votes.get_block_votes_class(block_.header.version)(
                reps, conf.VOTING_RATIO, block_.header.height, round_,
                block_.header.hash, confirm_info)
            votes.verify()
        return self.blockchain.add_block(block_, confirm_info,
                                         need_to_write_tx_info,
                                         need_to_score_invoke)
Esempio n. 3
0
    async def node_ws_PublishNewBlock(self, **kwargs):
        block_dict, votes_dumped = kwargs.get('block'), kwargs.get(
            'confirm_info', '')
        try:
            votes_serialized = json.loads(votes_dumped)
            vote = Votes.get_block_votes_class(
                block_dict["version"]).deserialize_votes(votes_serialized)
        except json.JSONDecodeError:
            vote = votes_dumped
        blockchain = ObjectManager().channel_service.block_manager.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 = blockchain.score_invoke
            reps_getter = blockchain.find_preps_addresses_by_roothash
            try:
                block_verifier.verify(
                    confirmed_block,
                    blockchain.last_block,
                    blockchain,
                    generator=blockchain.get_expected_generator(
                        confirmed_block),
                    reps_getter=reps_getter)
            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()}), votes_dumped({votes_dumped})"
                )
                ObjectManager(
                ).channel_service.block_manager.add_confirmed_block(
                    confirmed_block=confirmed_block, confirm_info=vote)
            finally:
                ObjectManager().channel_service.reset_block_monitoring_timer()
Esempio n. 4
0
    def __confirm_prev_block_by_sync(self, block_):
        prev_block = self.blockchain.last_unconfirmed_block
        confirm_info = block_.body.confirm_prev_block

        util.logger.debug(
            f"confirm_prev_block_by_sync :: height({prev_block.header.height})"
        )

        block_version = self.blockchain.block_versioner.get_version(
            prev_block.header.height)
        block_verifier = BlockVerifier.new(block_version,
                                           self.blockchain.tx_versioner)
        block_verifier.invoke_func = self.blockchain.get_invoke_func(
            prev_block.header.height)

        reps_getter = self.blockchain.find_preps_addresses_by_roothash
        block_verifier.verify_loosely(prev_block,
                                      self.blockchain.last_block,
                                      self.blockchain,
                                      reps_getter=reps_getter)
        return self.blockchain.add_block(prev_block, confirm_info)
Esempio n. 5
0
    def _add_block_by_sync(self, block_, confirm_info: Optional[List] = None):
        """
        TODO : If possible, change _add_block_by_sync to coroutine

        :param block_:
        :param confirm_info:
        :return:
        """
        utils.logger.debug(
            f"height({block_.header.height}) hash({block_.header.hash})")

        block_version = self._blockchain.block_versioner.get_version(
            block_.header.height)
        block_verifier = BlockVerifier.new(block_version,
                                           self._blockchain.tx_versioner,
                                           raise_exceptions=False)
        block_verifier.invoke_func = self._blockchain.get_invoke_func(
            block_.header.height)

        reps_getter = self._blockchain.find_preps_addresses_by_roothash
        block_verifier.verify_loosely(block_,
                                      self._blockchain.last_block,
                                      self._blockchain,
                                      reps_getter=reps_getter)

        need_to_write_tx_info, need_to_score_invoke = True, True
        for exc in block_verifier.exceptions:
            if isinstance(exc, exception.TransactionDuplicatedHashError):
                need_to_write_tx_info = False
            if isinstance(
                    exc,
                    exception.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, exception.TransactionDuplicatedHashError)),
            None)
        if exc:
            if isinstance(
                    exc,
                    exception.ScoreInvokeError) and not need_to_score_invoke:
                pass
            else:
                raise exc

        try:
            if parse_version(block_.header.version) >= parse_version("0.3"):
                reps = reps_getter(block_.header.reps_hash)
                round_ = next(vote for vote in confirm_info if vote).round
                votes = Votes.get_block_votes_class(block_.header.version)(
                    reps, conf.VOTING_RATIO, block_.header.height, round_,
                    block_.header.hash, confirm_info)
                votes.verify()
        except StopIteration:
            # I think is is unconfirmed_block because no confirm_info.
            # should be fix prevent unconfirmed block later.
            utils.logger.warning(f"block: {block_}")
            raise Exception(f"confirm_info is empty: {confirm_info}")

        self._blockchain.add_block(block_, confirm_info, need_to_write_tx_info,
                                   need_to_score_invoke)
Esempio n. 6
0
    def test_valid_timestamp(self):
        """Test for timestamp buffer in block verifier"""
        def block_maker(timestamp: int, height: int = 0, prev_hash=None):
            """Make dummy block"""
            tx_versioner = TransactionVersioner()

            dummy_receipts = {}
            block_builder = BlockBuilder.new("0.1a", tx_versioner)

            for i in range(1000):
                tx_builder = TransactionBuilder.new("0x3", None, tx_versioner)
                tx_builder.signer = test_signer
                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.type(), 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.signer = test_signer
            block_builder.prev_hash = prev_hash
            block_builder.height = height
            block_builder.state_hash = Hash32(bytes(Hash32.size))
            block_builder.receipts = dummy_receipts
            block_builder.reps = [
                ExternalAddress.fromhex_address(test_signer.address)
            ]
            block_builder.peer_id = ExternalAddress.fromhex(
                test_signer.address)
            block_builder.next_leader = ExternalAddress.fromhex(
                test_signer.address)
            block_builder.fixed_timestamp = timestamp

            b = block_builder.build()
            assert b.header.timestamp == timestamp

            return b

        test_signer = Signer.from_prikey(os.urandom(32))

        first_block = block_maker(height=0, timestamp=utils.get_time_stamp())
        second_block = block_maker(height=1,
                                   timestamp=utils.get_time_stamp() + 5,
                                   prev_hash=first_block.header.hash)
        third_block_from_far_future = block_maker(
            height=2,
            prev_hash=second_block.header.hash,
            timestamp=utils.get_time_stamp() +
            conf.TIMESTAMP_BUFFER_IN_VERIFIER + 5_000_000)

        block_verifier = BlockVerifier.new("0.1a", TransactionVersioner())
        leader = first_block.header.peer_id
        reps = [ExternalAddress.fromhex_address(test_signer.address)]
        print("*---Normal time range")
        block_verifier.verify(block=second_block,
                              prev_block=first_block,
                              blockchain=None,
                              generator=leader,
                              reps=reps)

        print("*---Abnormal time range")
        with self.assertRaises(Exception):
            block_verifier.verify(block=third_block_from_far_future,
                                  prev_block=second_block,
                                  blockchain=None,
                                  generator=leader,
                                  reps=reps)
Esempio n. 7
0
    def test_block_v0_4(self):
        block_version = "0.4"
        test_signer = Signer.from_prikey(os.urandom(32))
        tx_versioner = TransactionVersioner()

        dummy_receipts = {}
        block_builder = BlockBuilder.new(block_version, tx_versioner)
        for i in range(5):
            tx_builder = TransactionBuilder.new("0x3", None, tx_versioner)
            tx_builder.signer = test_signer
            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.type(),
                                                      tx_versioner)
            block_builder.transactions[tx.hash] = tx
            dummy_receipts[tx.hash.hex()] = {
                "dummy_receipt": "dummy",
                "tx_dumped": tx_serializer.to_full_data(tx)
            }

        next_leader = ExternalAddress.fromhex(
            "hx00112233445566778899aabbccddeeff00112233")

        block_builder.signer = test_signer
        block_builder.height = 0
        block_builder.prev_hash = Hash32(bytes(Hash32.size))
        block_builder.state_hash = Hash32(bytes(Hash32.size))
        block_builder.receipts = dummy_receipts
        block_builder.reps = [
            ExternalAddress.fromhex_address(test_signer.address)
        ]
        block_builder.next_leader = next_leader
        block_builder.next_reps = []

        vote = BlockVote.new(test_signer, utils.get_time_stamp(),
                             block_builder.height - 1, 0,
                             block_builder.prev_hash)
        votes = BlockVotes(block_builder.reps, conf.VOTING_RATIO,
                           block_builder.height - 1, 0,
                           block_builder.prev_hash)
        votes.add_vote(vote)
        block_builder.prev_votes = votes.votes

        block = block_builder.build()
        block_verifier = BlockVerifier.new(block_version, tx_versioner)

        block_verifier.invoke_func = lambda b, prev_b: (block, dummy_receipts)
        reps_getter = lambda _: block_builder.reps
        generator = ExternalAddress.fromhex_address(test_signer.address)
        block_verifier.verify(block,
                              None,
                              None,
                              generator=generator,
                              reps_getter=reps_getter)

        block_serializer = BlockSerializer.new(block_version, tx_versioner)
        block_serialized = block_serializer.serialize(block)
        logging.info(json.dumps(block_serialized, indent=4))
        block_deserialized = block_serializer.deserialize(block_serialized)
        logging.info(
            json.dumps(block_serializer.serialize(block_deserialized),
                       indent=4))

        assert block.header == block_deserialized.header
        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.transactions_hash, tx_proof)

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