def leader_complain(self): complained_leader_id, new_leader_id = self.get_leader_ids_for_complaint( ) version = self.blockchain.block_versioner.get_version( self.epoch.height) leader_vote = Vote.get_leader_vote_class(version).new( signer=ChannelProperty().peer_auth, block_height=self.epoch.height, round_=self.epoch.round, old_leader=ExternalAddress.fromhex_address(complained_leader_id), new_leader=ExternalAddress.fromhex_address(new_leader_id), timestamp=util.get_time_stamp()) util.logger.info( f"LeaderVote : old_leader({complained_leader_id}), new_leader({new_leader_id}), round({self.epoch.round})" ) self.add_complain(leader_vote) leader_vote_serialized = leader_vote.serialize() leader_vote_dumped = json.dumps(leader_vote_serialized) request = loopchain_pb2.ComplainLeaderRequest( complain_vote=leader_vote_dumped, channel=self.channel_name) util.logger.debug(f"leader complain " f"complained_leader_id({complained_leader_id}), " f"new_leader_id({new_leader_id})") reps_hash = self.blockchain.get_next_reps_hash_by_header( self.blockchain.last_block.header) self.__channel_service.broadcast_scheduler.schedule_broadcast( "ComplainLeader", request, reps_hash=reps_hash)
def _deserialize(cls, data: dict): data_deserialized = super()._deserialize(data) data_deserialized["block_height"] = int(data["blockHeight"], 16) data_deserialized["round"] = int(data["round"], 16) data_deserialized["old_leader"] = ExternalAddress.fromhex_address( data["oldLeader"]) data_deserialized["new_leader"] = ExternalAddress.fromhex_address( data["newLeader"]) return data_deserialized
def test_invoke(self): guard = self.guard value = f"hx{os.urandom(20).hex()}" address = ExternalAddress.fromhex_address(value) tx = MockTx(address) for i in range(self.guard_threshold): blocked: bool = guard.invoke(tx) assert not blocked assert not guard._is_update_denylist assert len(guard._denylist) == 0 # The case when count > guard_threshold blocked: bool = guard.invoke(tx) assert blocked assert guard._is_update_denylist assert value in guard._denylist # Blocking is expired _sleep(self.block_duration + 1) guard._check_denylist() assert value not in guard._denylist blocked: bool = guard.invoke(tx) assert not blocked assert guard._is_update_denylist assert len(guard._denylist) == 0 # Sleep for reset test _sleep(self.reset_time + 1) # Case when cur_time - expire_time > reset_time and count > 0 and not blocked blocked: bool = guard.invoke(tx) assert not blocked assert value not in guard._statistics
async def init(self, **kwargs): """Initialize Channel Service :param kwargs: takes (peer_id, peer_port, peer_target, rest_target) within parameters :return: None """ loggers.get_preset().peer_id = kwargs.get('peer_id') loggers.get_preset().update_logger() ChannelProperty().peer_port = kwargs.get('peer_port') ChannelProperty().peer_target = kwargs.get('peer_target') ChannelProperty().rest_target = kwargs.get('rest_target') ChannelProperty().peer_id = kwargs.get('peer_id') ChannelProperty().peer_address = ExternalAddress.fromhex_address( ChannelProperty().peer_id) ChannelProperty().node_type = conf.NodeType.CitizenNode ChannelProperty().rs_target = None self.__peer_manager = PeerManager() await self.__init_peer_auth() self.__init_broadcast_scheduler() self.__init_block_manager() await self.__init_score_container() await self.__inner_service.connect(conf.AMQP_CONNECTION_ATTEMPTS, conf.AMQP_RETRY_DELAY, exclusive=True) await self.__init_sub_services()
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)
def build_peer_id(self): if self.peer_id is not None: return self.peer_id if self.signer is None: raise RuntimeError self.peer_id = ExternalAddress.fromhex_address(self.signer.address) return self.peer_id
def build_from_address(self): if self.from_address: return self.from_address if self.signer is None: raise RuntimeError(f"'signer' or 'from_address' is required.") self.from_address = ExternalAddress.fromhex_address(self.signer.address) return self.from_address
def reps_hash(self) -> Hash32: """return reps root hash. :return: """ block_prover = BlockProver( (ExternalAddress.fromhex_address(peer.peer_id).extend() for peer in self._peer_list_data.peer_list.values()), BlockProverType.Rep) return block_prover.get_proof_root()
def new_votes(self): self.reps_hash = self.__blockchain.last_block.header.revealed_next_reps_hash or \ ObjectManager().channel_service.peer_manager.prepared_reps_hash self.reps = self.__blockchain.find_preps_addresses_by_roothash(self.reps_hash) # TODO After the v0.4 update, remove this version parsing. if parse_version(self.__blockchain.last_block.header.version) >= parse_version("0.4"): ratio = conf.VOTING_RATIO else: ratio = conf.LEADER_COMPLAIN_RATIO leader_votes = LeaderVotes(self.reps, ratio, self.height, self.round, ExternalAddress.fromhex_address(self.leader_id)) self.complain_votes[self.round] = leader_votes
def _init_properties(**kwargs): """Initialize properties :param kwargs: takes (peer_id, peer_port, peer_target, rest_target) within parameters :return: None """ loggers.get_preset().peer_id = kwargs.get('peer_id') loggers.get_preset().update_logger() ChannelProperty().peer_port = kwargs.get('peer_port') ChannelProperty().peer_target = kwargs.get('peer_target') ChannelProperty().rest_target = kwargs.get('rest_target') ChannelProperty().peer_id = kwargs.get('peer_id') ChannelProperty().peer_address = ExternalAddress.fromhex_address(ChannelProperty().peer_id) ChannelProperty().node_type = conf.NodeType.CitizenNode ChannelProperty().rs_target = None
def new_votes(self): self.reps_hash = self.__blockchain.last_block.header.revealed_next_reps_hash or \ ChannelProperty().crep_root_hash self.reps = self.__blockchain.find_preps_addresses_by_roothash( self.reps_hash) # TODO After the v0.4 update, remove this version parsing. if parse_version(self.__blockchain.last_block.header.version ) >= parse_version("0.4"): ratio = conf.VOTING_RATIO else: ratio = conf.LEADER_COMPLAIN_RATIO version = self.__blockchain.block_versioner.get_version(self.height) leader_votes = Votes.get_leader_votes_class(version)( self.reps, ratio, self.height, self.round, ExternalAddress.fromhex_address(self.leader_id)) self.complain_votes[self.round] = leader_votes
def load(): peers = PeerLoader._load_peers_from_db() if peers: utils.logger.info("Reps data loaded from DB") elif os.path.exists(conf.CHANNEL_MANAGE_DATA_PATH): utils.logger.info( f"Try to load reps data from {conf.CHANNEL_MANAGE_DATA_PATH}") peers = PeerLoader._load_peers_from_file() else: utils.logger.info("Try to load reps data from other reps") peers = PeerLoader._load_peers_from_rest_call() block_prover = BlockProver( (ExternalAddress.fromhex_address(peer['id']).extend() for peer in peers), BlockProverType.Rep) peer_root_hash = block_prover.get_proof_root() return peer_root_hash, peers
def test_transaction_v2_unsigned(self): signer = Signer.new() tb = TransactionBuilder.new("0x2", None, self.tx_versioner) tb.fee = 1000000 tb.value = 100000 tb.from_address = ExternalAddress.fromhex_address(signer.address) tb.to_address = ExternalAddress(os.urandom(20)) tb.nonce = random.randint(0, 100000) tx = tb.build(is_signing=False) tv = TransactionVerifier.new("0x2", tx.type(), self.tx_versioner) self.assertRaises(TransactionInvalidSignatureError, lambda: tv.verify(tx)) self.assertRaises(TransactionInvalidSignatureError, lambda: tv.pre_verify(tx)) tb.signer = signer signed_tx = tb.sign_transaction(tx) tv.verify(signed_tx) tv.pre_verify(signed_tx)
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
def __build_candidate_block(self, block_builder: 'BlockBuilder'): last_block = self._blockchain.last_block block_builder.height = last_block.header.height + 1 block_builder.prev_hash = last_block.header.hash block_builder.signer = ChannelProperty().peer_auth block_builder.confirm_prev_block = (block_builder.version == '0.1a') if block_builder.version == '0.1a' or (not block_builder.next_leader and not block_builder.reps): block_builder.next_leader = ExternalAddress.fromhex_address( self._block_manager.epoch.leader_id) block_builder.reps = self._block_manager.epoch.reps try: if block_builder.next_reps is None: # to build temporary block (version >= 0.4) block_builder.next_reps = [] except AttributeError as e: util.logger.info(f"block_version = {block_builder.version} : {e}") return block_builder.build()
def test_transaction_v3_unsigned(self): signer = Signer.new() tb = TransactionBuilder.new("0x3", None, self.tx_versioner) tb.step_limit = 1000000 tb.value = 100000 tb.from_address = ExternalAddress.fromhex_address(signer.address) tb.to_address = ExternalAddress(os.urandom(20)) tb.nid = 3 tb.nonce = random.randint(0, 100000) tb.data = "test" tb.data_type = "message" tx = tb.build(False) tv = TransactionVerifier.new("0x3", tx.type(), self.tx_versioner) self.assertRaises(TransactionInvalidSignatureError, lambda: tv.verify(tx)) self.assertRaises(TransactionInvalidSignatureError, lambda: tv.pre_verify(tx, nid=3)) tb.signer = signer signed_tx = tb.sign_transaction(tx) tv.verify(signed_tx) tv.pre_verify(signed_tx, nid=3)
def pytest_configure(): signers = [Signer.from_prikey(os.urandom(32)) for _ in range(100)] reps = [ExternalAddress.fromhex_address(signer.address) for signer in signers] pytest.SIGNERS: List[Signer] = signers pytest.REPS: List[ExternalAddress] = reps
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)
def setUpClass(cls): cls.signers = [Signer.from_prikey(os.urandom(32)) for _ in range(100)] cls.reps = [ ExternalAddress.fromhex_address(signer.address) for signer in cls.signers ]
def _deserialize(cls, data: dict): return { "rep": ExternalAddress.fromhex_address(data["rep"]), "timestamp": int(data["timestamp"], 16), "signature": Signature.from_base64str(data["signature"]) }