示例#1
0
    async def announce_new_block(self, subscriber_block_height: int,
                                 subscriber_id: str):
        while True:
            my_block_height = self._blockchain.block_height
            if subscriber_block_height > my_block_height:
                logging.warning(
                    f"subscriber's height({subscriber_block_height}) is higher "
                    f"than this node's height({my_block_height}).")
                self._channel_service.inner_service.notify_unregister()
                error_msg = {"error": "Invalid block height from citizen."}
                return json.dumps(error_msg), b''
            elif subscriber_block_height == my_block_height:
                async with self._citizen_condition_new_block:
                    await self._citizen_condition_new_block.wait()

            new_block_height = subscriber_block_height + 1
            new_block = self._blockchain.find_block_by_height(new_block_height)

            if new_block is None:
                logging.warning(
                    f"Cannot find block height({new_block_height})")
                # To prevent excessive occupancy of the CPU in an infinite loop
                await asyncio.sleep(2 * conf.INTERVAL_BLOCKGENERATION)
                continue

            confirm_info: bytes = self._blockchain.find_confirm_info_by_hash(
                new_block.header.hash)

            logging.debug(
                f"announce_new_block: height({new_block.header.height}), to: {subscriber_id}"
            )
            bs = BlockSerializer.new(new_block.header.version,
                                     self._blockchain.tx_versioner)
            return json.dumps(bs.serialize(new_block)), confirm_info
示例#2
0
    def __block_request_by_citizen(self, block_height):
        rs_client = ObjectManager().channel_service.rs_client
        get_block_result = rs_client.call(
            RestMethod.GetBlockByHeight,
            RestMethod.GetBlockByHeight.value.params(height=str(block_height)))
        last_block = rs_client.call(RestMethod.GetLastBlock)
        if not last_block:
            raise exception.InvalidBlockSyncTarget(
                "The Radiostation may not be ready. It will retry after a while."
            )

        max_height = self.blockchain.block_versioner.get_height(last_block)
        block_version = self.blockchain.block_versioner.get_version(
            block_height)
        block_serializer = BlockSerializer.new(block_version,
                                               self.blockchain.tx_versioner)
        block = block_serializer.deserialize(get_block_result['block'])
        votes_dumped: str = get_block_result.get('confirm_info', '')
        try:
            votes_serialized = json.loads(votes_dumped)
            version = self.blockchain.block_versioner.get_version(block_height)
            votes = Votes.get_block_votes_class(version).deserialize_votes(
                votes_serialized)
        except json.JSONDecodeError:
            votes = votes_dumped
        return block, max_height, -1, votes, message_code.Response.success
示例#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 = BlockVotes.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()
示例#4
0
    async def get_block(self, block_height, block_hash, unconfirmed=False) -> Tuple[int, str, bytes, str]:
        block, block_hash, confirm_info, fail_response_code = (
            await self.__get_block(block_hash, block_height, unconfirmed)
        )

        if fail_response_code:
            return fail_response_code, block_hash, b"", json.dumps({})

        tx_versioner = self._blockchain.tx_versioner
        bs = BlockSerializer.new(block.header.version, tx_versioner)
        block_dict = bs.serialize(block)
        return message_code.Response.success, block_hash, confirm_info, json.dumps(block_dict)
    def test_verify(self, plyvel_db, block_versioner, tx_versioner):
        """
        1. prepare plyvel db, block_versioner, tx_versioner
        2. pick block, transaction, vote, etc from db
        3. verify block, vote transaction, vote, etc...
        """

        # given db instance, block_versioner, tx_versioner

        block_key = plyvel_db.get(b'last_block_key')

        while True:
            # when get block from db
            block_dumped = plyvel_db.get(block_key)
            Logger.info(f"block_dump : {block_dumped}")
            block_serialized = json.loads(block_dumped)
            block_height = block_versioner.get_height(block_serialized)
            block_version = block_versioner.get_version(block_height)
            block_serializer = BlockSerializer.new(block_version, tx_versioner)
            block = block_serializer.deserialize(block_serialized)
            Logger.info(f"block_height : {block_height}, block_version : {block_version}")

            if block_height == 0:
                break

            # then block verify
            block_verifier = BlockVerifier.new(block_version, tx_versioner)
            block_verifier.verify_signature(block)

            # then vote verify
            if parse_version(block_version) >= parse_version("0.3"):
                Logger.info(f"leader_votes : {block.body.leader_votes}")
                for leader_vote in block.body.leader_votes:
                    if not leader_vote:
                        continue
                    leader_vote.verify()

                Logger.info(f"prev_votes : {block.body.prev_votes}")
                for block_vote in block.body.prev_votes:
                    if not block_vote:
                        continue
                    block_vote.verify()

            # then transaction verify
            for tx in block.body.transactions.values():
                tv = TransactionVerifier.new(tx.version, tx.type(), tx_versioner)
                tv.verify_signature(tx)

            Logger.info(f"prev_hash : {block.header.prev_hash}, {bytes(block.header.prev_hash)}")
            block_key = block.header.prev_hash.hex().encode("utf-8")
示例#6
0
    async def get_block_v2(self, block_height,
                           block_hash) -> Tuple[int, str, str]:
        # This is a temporary function for v2 support of exchanges.
        block, block_hash, _, fail_response_code = await self.__get_block(
            block_hash, block_height)
        if fail_response_code:
            return fail_response_code, block_hash, json.dumps({})

        tx_versioner = self._blockchain.tx_versioner
        bs = BlockSerializer.new(block.header.version, tx_versioner)
        block_data_dict = bs.serialize(block)

        if block.header.height == 0:
            return message_code.Response.success, block_hash, json.dumps(
                block_data_dict)

        confirmed_tx_list_without_fail = []
        for tx in block.body.transactions.values():
            invoke_result = self._block_manager.get_invoke_result(tx.hash)

            if 'failure' in invoke_result:
                continue

            ts = TransactionSerializer.new(tx.version, tx.type(), tx_versioner)
            full_data = ts.to_full_data(tx)
            if tx.version == "0x3":
                step_used, step_price = int(invoke_result["stepUsed"],
                                            16), int(
                                                invoke_result["stepPrice"], 16)
                full_data["fee"] = hex(step_used * step_price)

            confirmed_tx_list_without_fail.append(full_data)

        # Replace the existing confirmed_transactions with v2 ver.
        if block.header.version == "0.1a":
            block_data_dict[
                "confirmed_transaction_list"] = confirmed_tx_list_without_fail
        else:
            block_data_dict["transactions"] = confirmed_tx_list_without_fail
        block_data_json = json.dumps(block_data_dict)

        if fail_response_code:
            return fail_response_code, block_hash, json.dumps({})

        return message_code.Response.success, block_hash, block_data_json
示例#7
0
    async def _block_request_by_citizen(
            self,
            block_height: int,
            request_client: RestClient = None) -> RequestResult:
        max_height = self._max_height
        if request_client is None:
            request_client = self._rest_client

        get_block_result = await request_client.call_async(
            RestMethod.GetBlockByHeight,
            RestMethod.GetBlockByHeight.value.params(height=str(block_height)))

        response_code = get_block_result["response_code"]
        if response_code != message_code.Response.success:
            exc = exception.MessageCodeError(
                f"getBlockByHeight failed height={block_height}")
            exc.message_code = response_code
            raise exc

        if max_height == block_height:
            last_block_height = self._get_last_block_height()
            if last_block_height > max_height:
                max_height = last_block_height

        block_version = self._blockchain.block_versioner.get_version(
            block_height)
        block_serializer = BlockSerializer.new(block_version,
                                               self._blockchain.tx_versioner)
        block = block_serializer.deserialize(get_block_result['block'])
        votes_dumped: str = get_block_result.get('confirm_info', '')
        try:
            votes_serialized = json.loads(votes_dumped)
            version = self._blockchain.block_versioner.get_version(
                block_height)
            votes = Votes.get_block_votes_class(version).deserialize_votes(
                votes_serialized)
        except json.JSONDecodeError:
            votes = votes_dumped
        return block, max_height, -1, votes, message_code.Response.success
示例#8
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)