Пример #1
0
    def to_hash32(self, value: Union[Hash32, bytes, bytearray, int, bool,
                                     dict]):
        if value is None:
            return Hash32.empty()
        elif isinstance(value, Hash32):
            return value
        elif isinstance(value, (bytes, bytearray)) and len(value) == 32:
            return Hash32(value)

        if isinstance(value, bool):
            value = b'\x01' if value else b'\x00'
        elif isinstance(value, int):
            if value < 0:
                raise RuntimeError(f"value : {value} is negative.")
            value = value.to_bytes((value.bit_length() + 7) // 8, "big")
        elif isinstance(value, dict):
            if self.type == BlockProverType.Receipt:
                value = dict(value)
                value.pop("failure", None)
                value.pop("blockHash", None)

            hash_generator = self.get_hash_generator()
            value = hash_generator.generate_salted_origin(value)
            value = value.encode()
        return Hash32(hashlib.sha3_256(value).digest())
Пример #2
0
    def test_prep_changed_by_penalty_if_exists_next_reps_hash_and_next_leader(self, header_factory):
        header = header_factory(next_leader=ExternalAddress(os.urandom(ExternalAddress.size)),
                                reps_hash=Hash32(os.urandom(Hash32.size)),
                                next_reps_hash=Hash32(os.urandom(Hash32.size)))

        assert header.prep_changed
        assert header.prep_changed_reason == NextRepsChangeReason.TermEnd
Пример #3
0
    def _build_merkle_tree_root_hash(self):
        merkle_tree_root_hash = None
        mt_list = [tx_hash.hex() for tx_hash in self.transactions.keys()]

        while True:
            tree_length = len(mt_list)
            tmp_mt_list = []
            if tree_length <= 1:
                break
            elif tree_length % 2 == 1:
                mt_list.append(mt_list[tree_length - 1])
                tree_length += 1

            for row in range(int(tree_length / 2)):
                idx = row * 2
                mt_nodes = [
                    mt_list[idx].encode(encoding='UTF-8'),
                    mt_list[idx + 1].encode(encoding='UTF-8')
                ]
                mk_sum = b''.join(mt_nodes)
                mk_hash = hashlib.sha256(mk_sum).hexdigest()
                tmp_mt_list.append(mk_hash)
            mt_list = tmp_mt_list

        if len(mt_list) == 1:
            merkle_tree_root_hash = mt_list[0]

        if merkle_tree_root_hash:
            return Hash32.fromhex(merkle_tree_root_hash, True)

        return Hash32(bytes(Hash32.size))
Пример #4
0
    def test_block_invalid_vote(self):
        ratio = 0.67
        block_hash = Hash32(os.urandom(Hash32.size))
        block_votes = BlockVotes(self.reps, ratio, 0, 0, block_hash)

        invalid_block_vote = BlockVote.new(self.signers[0], 0, 0, 1,
                                           block_hash)
        self.assertRaises(RuntimeError, block_votes.add_vote,
                          invalid_block_vote)

        invalid_block_vote = BlockVote.new(self.signers[0], 0, 1, 0,
                                           block_hash)
        self.assertRaises(RuntimeError, block_votes.add_vote,
                          invalid_block_vote)

        invalid_block_vote = BlockVote.new(self.signers[0], 0, 0, 0,
                                           Hash32(os.urandom(32)))
        self.assertRaises(RuntimeError, block_votes.add_vote,
                          invalid_block_vote)

        invalid_block_vote = BlockVote(rep=self.reps[0],
                                       timestamp=0,
                                       signature=Signature(os.urandom(65)),
                                       block_height=0,
                                       round_=0,
                                       block_hash=block_hash)
        self.assertRaises(RuntimeError, block_votes.add_vote,
                          invalid_block_vote)

        block_vote = BlockVote.new(self.signers[0], 0, 0, 0, block_hash)
        block_votes.add_vote(block_vote)
        duplicate_block_vote = BlockVote.new(self.signers[0], 0, 0, 0,
                                             Hash32.empty())
        self.assertRaises(votes.VoteDuplicateError, block_votes.add_vote,
                          duplicate_block_vote)
Пример #5
0
    def test_prep_changed_by_term_end_if_next_leader_is_empty(self, header_factory):
        header = header_factory(next_leader=ExternalAddress.empty(),
                                reps_hash=Hash32(os.urandom(Hash32.size)),
                                next_reps_hash=Hash32(os.urandom(Hash32.size)))

        assert header.prep_changed
        assert header.prep_changed_reason is NextRepsChangeReason.TermEnd
Пример #6
0
def make_proof_serializable(proof: list):
    proof_serializable = []
    for item in proof:
        try:
            left = Hash32(item["left"])
            proof_serializable.append({"left": left.hex_0x()})
        except KeyError:
            right = Hash32(item["right"])
            proof_serializable.append({"right": right.hex_0x()})
    return proof_serializable
Пример #7
0
def make_proof_deserializable(proof: list):
    proof_deserializable = []
    for item in proof:
        try:
            left: str = item["left"]
            proof_deserializable.append({"left": Hash32.fromhex(left)})
        except KeyError:
            right: str = item["right"]
            proof_deserializable.append({"right": Hash32.fromhex(right)})
    return proof_deserializable
Пример #8
0
    def _deserialize_header_data(self, json_data: dict):
        hash_ = Hash32.fromhex(json_data["hash"])

        prev_hash = json_data.get('prevHash')
        prev_hash = Hash32.fromhex(prev_hash) if prev_hash else None

        peer_id = json_data.get('leader')
        peer_id = ExternalAddress.fromhex(peer_id) if peer_id else None

        signature = json_data.get('signature')
        signature = Signature.from_base64str(signature) if signature else None

        next_leader = json_data.get("nextLeader")
        next_leader = ExternalAddress.fromhex(
            next_leader) if next_leader else None

        transactions_hash = json_data["transactionsHash"]
        transactions_hash = Hash32.fromhex(transactions_hash)

        receipts_hash = json_data["receiptsHash"]
        receipts_hash = Hash32.fromhex(receipts_hash)

        state_hash = json_data["stateHash"]
        state_hash = Hash32.fromhex(state_hash)

        reps_hash = json_data["repsHash"]
        reps_hash = Hash32.fromhex(reps_hash)

        next_reps_hash = json_data["nextRepsHash"]
        next_reps_hash = Hash32.fromhex(next_reps_hash)

        leader_votes_hash = json_data["leaderVotesHash"]
        leader_votes_hash = Hash32.fromhex(leader_votes_hash)

        prev_votes_hash = json_data["prevVotesHash"]
        prev_votes_hash = Hash32.fromhex(prev_votes_hash)

        height = json_data["height"]
        height = int(height, 16)

        timestamp = json_data["timestamp"]
        timestamp = int(timestamp, 16)

        return {
            "hash": hash_,
            "prev_hash": prev_hash,
            "height": height,
            "timestamp": timestamp,
            "peer_id": peer_id,
            "signature": signature,
            "next_leader": next_leader,
            "transactions_hash": transactions_hash,
            "receipts_hash": receipts_hash,
            "state_hash": state_hash,
            "reps_hash": reps_hash,
            "next_reps_hash": next_reps_hash,
            "leader_votes_hash": leader_votes_hash,
            "prev_votes_hash": prev_votes_hash,
            "logs_bloom": BloomFilter.fromhex(json_data["logsBloom"])
        }
Пример #9
0
        def _header(hash_: Hash32 = Hash32.new(),
                    prev_hash: Hash32 = Hash32.new(),
                    height: int = 0,
                    timestamp: int = 0,
                    peer_id: ExternalAddress = ExternalAddress.new(),
                    signature: Signature = Signature.new(),
                    next_leader: Address = Address.new(),
                    merkle_tree_root_hash: Hash32 = Hash32.new(),
                    commit_state: dict = dict()) -> BlockHeader_v0_1a:

            return BlockHeader_v0_1a(hash_, prev_hash, height, timestamp, peer_id,
                                     signature, next_leader, merkle_tree_root_hash, commit_state)
Пример #10
0
    def add_vote(self, vote: BlockVote):
        with self.__blocks_lock:
            if vote.block_hash != Hash32.empty() and vote.block_hash not in self.blocks:
                # util.logger.debug(f"-------------block_hash({block_hash}) self.blocks({self.blocks})")
                self.blocks[vote.block_hash] = CandidateBlock.from_hash(vote.block_hash, vote.block_height)

        if vote.block_hash != Hash32.empty():
            self.blocks[vote.block_hash].add_vote(vote)
        else:
            for block in self.blocks.values():
                if block.height == vote.block_height:
                    block.add_vote(vote)
Пример #11
0
    def add_vote(self, vote: 'BlockVote'):
        with self.__blocks_lock:
            if vote.block_hash != Hash32.empty(
            ) and vote.block_hash not in self.blocks:
                self.blocks[vote.block_hash] = CandidateBlock.from_hash(
                    vote.block_hash, vote.block_height)

        if vote.block_hash != Hash32.empty():
            self.blocks[vote.block_hash].add_vote(vote)
        else:
            for block in self.blocks.values():
                if block.height == vote.block_height:
                    block.add_vote(vote)
Пример #12
0
    def test_block_votes_false(self):
        ratio = 0.67
        block_hash = Hash32(os.urandom(Hash32.size))
        block_votes = BlockVotes(self.reps, ratio, 0, 0, block_hash)

        for i, signer in enumerate(self.signers):
            if i % 4 == 0:
                block_vote = BlockVote.new(signer, 0, 0, 0, block_hash)
            else:
                block_vote = BlockVote.new(signer, 0, 0, 0, Hash32.empty())
            block_votes.add_vote(block_vote)

        logging.info(block_votes)
        self.assertEqual(block_votes.quorum, len(self.reps) * ratio)
        self.assertEqual(block_votes.get_result(), False)
Пример #13
0
    def reset_all_peers(self, reps_hash, reps, update_now=True):
        util.logger.debug(f"reset_all_peers."
                          f"\nresult roothash({reps_hash})"
                          f"\npeer_list roothash({self.reps_hash().hex()})"
                          f"\nupdate now({update_now})")

        if not update_now:
            self._reps_reset_data = (reps_hash, reps)
            return

        blockchain = ObjectManager().channel_service.block_manager.blockchain

        if reps_hash == self.reps_hash().hex():
            util.logger.debug(f"There is no change in load_peers_from_iiss.")
            return

        self._peer_list_data.peer_list.clear()
        self._prepared_reps_hash = None

        for order, rep_info in enumerate(reps, 1):
            peer = Peer(rep_info["id"], rep_info["p2pEndpoint"], order=order)
            self.add_peer(peer)

        new_reps = blockchain.find_preps_addresses_by_roothash(
            Hash32.fromhex(reps_hash, ignore_prefix=True))
        new_node_type = NodeType.CommunityNode if ChannelProperty(
        ).peer_address in new_reps else NodeType.CitizenNode
        is_switched_role = new_node_type != ChannelProperty().node_type
        blockchain.reset_leader_made_block_count(is_switched_role)
Пример #14
0
    async def __get_block(self, block_hash, block_height):
        if block_hash == "" and block_height == -1 and self._blockchain.last_block:
            block_hash = self._blockchain.last_block.header.hash.hex()

        block = None
        confirm_info = b''
        fail_response_code = None
        if block_hash:
            block = self._blockchain.find_block_by_hash(block_hash)
            if block is None:
                fail_response_code = message_code.Response.fail_wrong_block_hash
                confirm_info = bytes()
            else:
                confirm_info = self._blockchain.find_confirm_info_by_hash(
                    Hash32.fromhex(block_hash, True))
        elif block_height != -1:
            block = self._blockchain.find_block_by_height(block_height)
            if block is None:
                fail_response_code = message_code.Response.fail_wrong_block_height
                confirm_info = bytes()
            else:
                confirm_info = self._blockchain.find_confirm_info_by_hash(
                    block.header.hash)
        else:
            fail_response_code = message_code.Response.fail_wrong_block_hash

        return block, block_hash, bytes(confirm_info), fail_response_code
Пример #15
0
    def get_hash(self, block_dumped: Union[str, dict]):
        if isinstance(block_dumped, str):
            block_dumped = json.loads(block_dumped)

        hash_ = block_dumped.get("block_hash") or block_dumped.get("hash")
        ignore_prefix = block_dumped['version'] == '0.1a'
        return Hash32.fromhex(hash_, ignore_prefix) if isinstance(hash_, str) else hash_
Пример #16
0
    def vote_unconfirmed_block(self, block: Block, round_: int, is_validated):
        util.logger.debug(
            f"vote_unconfirmed_block() ({block.header.height}/{block.header.hash}/{is_validated})"
        )
        vote = Vote.get_block_vote_class(block.header.version).new(
            signer=ChannelProperty().peer_auth,
            block_height=block.header.height,
            round_=round_,
            block_hash=block.header.hash if is_validated else Hash32.empty(),
            timestamp=util.get_time_stamp())
        self.candidate_blocks.add_vote(vote)

        vote_serialized = vote.serialize()
        vote_dumped = json.dumps(vote_serialized)
        block_vote = loopchain_pb2.BlockVote(vote=vote_dumped,
                                             channel=ChannelProperty().name)

        target_reps_hash = block.header.reps_hash
        if not target_reps_hash:
            target_reps_hash = self.__channel_service.peer_manager.crep_root_hash

        self.__channel_service.broadcast_scheduler.schedule_broadcast(
            "VoteUnconfirmedBlock", block_vote, reps_hash=target_reps_hash)

        return vote
Пример #17
0
    async def __get_block(self, block_hash, block_height, unconfirmed=False):
        if block_hash == "" and block_height == -1 and self._blockchain.last_block:
            block_hash = self._blockchain.last_block.header.hash.hex()

        block = None
        confirm_info = b''
        fail_response_code = None
        try:
            if block_hash:
                block = self._blockchain.find_block_by_hash(block_hash)
                if block is None:
                    fail_response_code = message_code.Response.fail_wrong_block_hash
                    confirm_info = bytes()
                else:
                    confirm_info = self._blockchain.find_confirm_info_by_hash(Hash32.fromhex(block_hash, True))
            elif block_height != -1:
                block = self._blockchain.find_block_by_height(block_height)
                is_wrong_block_height: bool = (
                        block is None or
                        unconfirmed is False
                        and self._blockchain.is_last_unconfirmed_block(block.header.height)
                )

                if is_wrong_block_height:
                    fail_response_code = message_code.Response.fail_wrong_block_height
                    confirm_info = bytes()
                else:
                    confirm_info = self._blockchain.find_confirm_info_by_hash(block.header.hash)
            else:
                fail_response_code = message_code.Response.fail_wrong_block_hash
        except PrunedHashDataError as e:
            logging.warning(f"{e!r}")
            fail_response_code = e.message_code
        return block, block_hash, bytes(confirm_info), fail_response_code
Пример #18
0
    def create_icx_origin_v3(self, is_raw_data=False):
        params = dict()
        params["version"] = "0x3"
        params["from"] = self.address
        params["to"] = self.to_address
        params["value"] = hex(int(self.value * ICX_FACTOR))
        params["stepLimit"] = "0x3000000"
        params["timestamp"] = hex(utils.get_now_time_stamp())
        params["nonce"] = "0x0"
        params["nid"] = self.nid
        if self.message is not None:
            params["dataType"] = "message"
            params["data"] = VarBytes(self.message.encode('utf-8')).hex_0x()

        hash_for_sign = self.__hash_generators["0x3"].generate_hash(params)
        params["signature"] = self.create_signature(hash_for_sign)
        if self.is_logging:
            logging.debug(f"icx_sendTransaction params for v3: {params}")

        self.__last_tx_hash = Hash32(hash_for_sign).hex_0x()
        icx_origin = dict()
        icx_origin["jsonrpc"] = "2.0"
        icx_origin["method"] = "icx_sendTransaction"
        icx_origin["id"] = random.randrange(0, 100000)
        icx_origin["params"] = params

        return icx_origin if is_raw_data else params
Пример #19
0
    def is_unrecorded(self) -> bool:
        """Return is unrecorded block

        :return: bool
        """
        return (self.next_leader == ExternalAddress.empty() and
                self.reps_hash == self.next_reps_hash == Hash32.empty())
Пример #20
0
    def from_(self, tx_data: dict) -> 'Transaction':
        tx_data_copied = dict(tx_data)

        tx_data_copied.pop('method', None)
        hash = tx_data_copied.pop('tx_hash', None)
        signature = tx_data_copied.pop('signature', None)
        timestamp = tx_data_copied.pop('timestamp', None)
        from_address = tx_data_copied.pop('from', None)
        to_address = tx_data_copied.pop('to', None)
        value = tx_data_copied.pop('value', None)
        fee = tx_data_copied.pop('fee', None)
        nonce = tx_data_copied.pop('nonce', None)
        extra = tx_data_copied

        value = int_fromhex(value)
        fee = int_fromhex(fee)

        if nonce is not None:
            nonce = int_fromstr(nonce)

        return Transaction(
            raw_data=tx_data,
            hash=Hash32.fromhex(hash, ignore_prefix=True, allow_malformed=False),
            signature=Signature.from_base64str(signature),
            timestamp=int(timestamp) if timestamp is not None else None,
            from_address=ExternalAddress.fromhex(from_address, ignore_prefix=False, allow_malformed=True),
            to_address=ExternalAddress.fromhex(to_address, ignore_prefix=False, allow_malformed=True),
            value=value,
            fee=fee,
            nonce=nonce,
            extra=extra,
        )
Пример #21
0
    def _build_transactions_hash(self):
        if not self.transactions:
            return Hash32.empty()

        block_prover = BlockProver(self.transactions.keys(),
                                   BlockProverType.Transaction)
        return block_prover.get_proof_root()
Пример #22
0
    def test_block_vote(self):
        signer = self.signers[0]
        block_hash = Hash32(os.urandom(Hash32.size))
        block_vote = BlockVote.new(signer, 0, 0, 0, block_hash)
        block_vote.verify()

        origin = f"icx_vote.blockHash.{block_vote.block_hash.hex_0x()}.blockHeight.{hex(block_vote.block_height)}."
        origin += f"rep.{block_vote.rep.hex_hx()}.round_.{block_vote.round_}.timestamp.{hex(block_vote.timestamp)}"

        origin_data = block_vote.to_origin_data(**block_vote.origin_args())
        self.assertEqual(
            origin, vote.hash_generator.generate_salted_origin(origin_data))

        self.assertEqual(
            Hash32(hashlib.sha3_256(origin.encode('utf-8')).digest()),
            block_vote.to_hash(**block_vote.origin_args()))
Пример #23
0
    def __init__(self, channel_name, amqp_target, amqp_key, rollback=False):
        self.__block_manager: BlockManager = None
        self.__score_container: CommonSubprocess = None
        self.__score_info: dict = None
        self.__peer_auth: Signer = None
        self.__broadcast_scheduler: BroadcastScheduler = None
        self.__rs_client: RestClient = None
        self.__timer_service = TimerService()
        self.__node_subscriber: NodeSubscriber = None
        self._rollback: bool = rollback

        loggers.get_preset().channel_name = channel_name
        loggers.get_preset().update_logger()

        channel_queue_name = conf.CHANNEL_QUEUE_NAME_FORMAT.format(channel_name=channel_name, amqp_key=amqp_key)
        self.__inner_service = ChannelInnerService(
            amqp_target, channel_queue_name, conf.AMQP_USERNAME, conf.AMQP_PASSWORD, channel_service=self)

        logging.info(f"ChannelService : {channel_name}, Queue : {channel_queue_name}")

        ChannelProperty().name = channel_name
        ChannelProperty().amqp_target = amqp_target
        ChannelProperty().crep_root_hash = Hash32.fromhex(conf.CHANNEL_OPTION[channel_name].get('crep_root_hash'))

        StubCollection().amqp_key = amqp_key
        StubCollection().amqp_target = amqp_target

        command_arguments.add_raw_command(command_arguments.Type.Channel, channel_name)
        command_arguments.add_raw_command(command_arguments.Type.AMQPTarget, amqp_target)
        command_arguments.add_raw_command(command_arguments.Type.AMQPKey, amqp_key)

        ObjectManager().channel_service = self
        self.__state_machine = ChannelStateMachine(self)
Пример #24
0
 def to_origin_data(cls, rep: ExternalAddress, timestamp: int,
                    block_height: int, round: int, block_hash: Hash32):
     origin_data = super().to_origin_data(rep, timestamp)
     origin_data["blockHeight"] = hex(block_height)
     origin_data["round"] = hex(round)
     origin_data["blockHash"] = block_hash.hex_0x(
     ) if block_hash is not None else None
     return origin_data
Пример #25
0
    def _build_prev_votes_hash(self):
        if not self.prev_votes:
            return Hash32.new()

        block_prover = BlockProver(
            (vote.hash() if vote else None for vote in self.prev_votes),
            BlockProverType.Vote)
        return block_prover.get_proof_root()
Пример #26
0
    def test_get_hash(self, tx_factory: TxFactory):
        tx: Transaction = tx_factory(self.tx_version)
        ts = TransactionSerializer.new(version=tx.version, type_=self.type_, versioner=tx_versioner)

        full_data = ts.to_full_data(tx)
        tx_hash = ts.get_hash(full_data)

        assert tx.hash == Hash32.fromhex(tx_hash, ignore_prefix=True)
Пример #27
0
    def _load_peers_from_db() -> list:
        blockchain = ObjectManager().channel_service.block_manager.blockchain
        last_block = blockchain.last_block
        rep_root_hash = (last_block.header.reps_hash
                         if last_block else Hash32.fromhex(conf.CHANNEL_OPTION[
                             ChannelProperty().name].get('crep_root_hash')))

        return blockchain.find_preps_by_roothash(rep_root_hash)
Пример #28
0
    def test_get_hash(self, tx_factory: TxFactory):
        tx: Transaction = tx_factory(self.tx_version)
        ts = TransactionSerializer.new(version=tx.version, type_=tx.type(), versioner=tx_versioner)

        full_data = ts.to_full_data(tx)
        tx_hash = ts.get_hash(full_data)

        assert tx.hash == Hash32(tx_hash)
Пример #29
0
    async def prove_receipt(self, tx_hash: str, proof: list) -> Union[str, dict]:
        try:
            proof = make_proof_deserializable(proof)
        except Exception as e:
            return make_error_response(JsonError.INTERNAL_ERROR, str(e))

        try:
            return "0x1" if self._blockchain.prove_receipt(Hash32.fromhex(tx_hash), proof) else "0x0"
        except Exception as e:
            return make_error_response(JsonError.INVALID_PARAMS, str(e))
Пример #30
0
    async def get_receipt_proof(self, tx_hash: str) -> Union[list, dict]:
        try:
            proof = self._blockchain.get_receipt_proof(Hash32.fromhex(tx_hash))
        except Exception as e:
            return make_error_response(JsonError.INVALID_PARAMS, str(e))

        try:
            return make_proof_serializable(proof)
        except Exception as e:
            return make_error_response(JsonError.INTERNAL_ERROR, str(e))