def gen_signature(self): r = b"" r = self.serialize_unsigned(r, self.version) signature = keytool.ecdsa_sign(self.private_key, r) Logger.debug("{} len signature: {}".format(self.tag, len(signature))) self.signature = signature return signature
def _check_password(self): ret = keytool.sha256_hash(str.encode(self._password), 3).hex() == self._get_password_hash() if not ret: Logger.error("Invalid password!") return ret
def terminate_all_process(self, result=True): Logger.info("{} terminal all the process and exit...".format(self.tag)) self.node_manager.stop_nodes() time.sleep(1) os.system("sh {}/shell/killall.sh".format(self.root_path)) if result: exit(0)
def validate(self): if self.version != 0: Logger.error("invalid vote version") return False type_list = list() for content in self.contents: if content.vote_type in type_list: Logger.error("{} duplicate vote type") return False type_list.append(content.vote_type) if content.vote_type != VoteContent.DELEGATE: Logger.error("{} invalid vote type") if len(content.candidates) == 0 or len(content.candidates) > 36: Logger.error("{} invalid vote candidates") return False candidates_list = list() for candidate in content.candidates: if candidate in candidates_list: Logger.error("{} duplicate candidate") return False candidates_list.append(candidate) return True
def create_side_info(self, node_type: str): self.params.arbiter_params.side_info[node_type] = dict() global side_chain_genesis_hash if node_type is not "geth": side_port = util.reset_port(1, node_type, "json_port") Logger.warn("{} side port: {}".format(self.tag, side_port)) side_chain_genesis_hash = rpc.get_block_hash_by_height( 0, side_port) Logger.debug("{} {} genesis hash: {}".format( self.tag, node_type, self.params.arbiter_params.side_chain_genesis_hash)) else: side_chain_genesis_hash = self.params.eth_params.genesis_hash recharge_address = keytool.gen_cross_chain_address( bytes.fromhex(side_chain_genesis_hash)) self.params.arbiter_params.recharge_address = recharge_address self.params.arbiter_params.withdraw_address = "0000000000000000000000000000000000" self.params.arbiter_params.side_chain_genesis_hash = side_chain_genesis_hash Logger.info("{} side genesis hash:{}".format(self.tag, side_chain_genesis_hash)) Logger.info("{} recharge address: {}".format( self.tag, self.params.arbiter_params.recharge_address)) Logger.info("{} withdraw address: {}".format( self.tag, self.params.arbiter_params.withdraw_address)) self.params.arbiter_params.side_info[node_type][ constant.SIDE_GENESIS_ADDRESS] = side_chain_genesis_hash self.params.arbiter_params.side_info[node_type][ constant.SIDE_RECHARGE_ADDRESS] = recharge_address self.params.arbiter_params.side_info[node_type][constant.SIDE_WITHDRAW_ADDRESS] = \ self.params.arbiter_params.withdraw_address
def crc_proposal_secretary_general(self): ela_node = self.node_manager.ela_nodes[1] cr_private_key = ela_node.cr_account.private_key() ela_node = self.node_manager.ela_nodes[2] secretary_general_private_key = ela_node.cr_account.private_key() result = True crc_proposal = CRCProposal( private_key=cr_private_key, cr_private_key=cr_private_key, secretary_general_private_key=secretary_general_private_key, proposal_type=CRCProposal.SECRETARY_GENERAL, category_data="", draft_hash=Random.get_random_bytes(serialize.UINT256SIZE)) Logger.info( "{} create crc proposal change secretary general on success. \n{}". format(self.tag, crc_proposal)) ret = self.tx_manager.crc_proposal( input_private_key=self.tap_account.private_key(), amount=10 * constant.TO_SELA, crc_proposal=crc_proposal) if not ret: return False self.discrete_miner(1) return result
def start(self): if self.running: return if self.arbiter_enable: self.process = subprocess.Popen( "./ela{} -p {}".format(self.index, self.password), stdout=self.dev_null, stderr=self.err_output, shell=True, cwd=self.cwd_dir ) if self.index in range(1, self.params.crc_number + 1): Logger.debug("{} crc{} started on success.".format(self.tag, self.index)) elif self.index in range(self.params.crc_number + 1, self.params.crc_number * 3 + 1): Logger.debug("{} producer{} started on success.".format(self.tag, self.index)) else: Logger.debug("{} candidate{} started on success.".format(self.tag, self.index)) else: self.process = subprocess.Popen( "./ela{}".format(self.index), stdout=self.dev_null, stderr=self.err_output, shell=True, cwd=self.cwd_dir ) if self.index == 0: Logger.debug("{} miner started on success.".format(self.tag)) else: Logger.debug("{} normal ela{} started on success.".format(self.tag, self.index)) self.running = True return True
def crc_proposal_change_owner(self): ela_node = self.node_manager.ela_nodes[1] cr_private_key = ela_node.cr_account.private_key() ela_node = self.node_manager.ela_nodes[2] new_owner_private_key = ela_node.cr_account.private_key() result = True crc_proposal = CRCProposal( private_key=cr_private_key, cr_private_key=cr_private_key, new_owner_private_key=new_owner_private_key, proposal_type=CRCProposal.CHANGE_SPONSOR_OWNER, category_data="", draft_hash=Random.get_random_bytes(serialize.UINT256SIZE), target_proposal_hash=self.crc_proposal_hash) Logger.info( "{} create crc proposal change owner on success. \n{}".format( self.tag, crc_proposal)) ret = self.tx_manager.crc_proposal( input_private_key=self.tap_account.private_key(), amount=10 * constant.TO_SELA, crc_proposal=crc_proposal) if not ret: return False self.discrete_miner(1) return result
def crc_proposal_withdraw(self): global result result = True # Recipient ela_node = self.node_manager.ela_nodes[1] recipient = ela_node.cr_account.address() # leader privatekey ela_node = self.node_manager.ela_nodes[2] cr_private_key = ela_node.cr_account.private_key() withdraw = CRCProposalWithdraw( private_key=cr_private_key, proposal_hash=self.crc_proposal_hash, ) Logger.info("{} create crc proposal withdraw on success. \n{}".format( self.tag, withdraw)) amount = self.get_withdraw_amount( util.bytes_reverse(self.crc_proposal_hash).hex()) - util.TX_FEE ret = self.tx_manager.crc_proposal_withdraw( input_address=self.CRC_COMMITTEE_ADDRESS, amount=amount, crc_proposal_withdraw=withdraw, output_address=recipient) if not ret: return False self.discrete_miner(1) return result
def crc_proposal_tracking(self, new_leader_private_key, tracking_type: int, stage: int): global result result = True tracking = CRCProposalTracking( secretary_private_key=self.secretary_private_key, leader_private_key=self.owner_private_key, new_leader_private_key=new_leader_private_key, proposal_hash=self.crc_proposal_hash, document_hash=Random.get_random_bytes(serialize.UINT256SIZE), stage=stage, tracking_type=tracking_type, secretary_opinion_hash=Random.get_random_bytes( serialize.UINT256SIZE), ) Logger.info("{} create crc proposal tracking on success. \n{}".format( self.tag, tracking)) ret = self.tx_manager.crc_proposal_tracking( input_private_key=self.tap_account.private_key(), amount=10 * constant.TO_SELA, crc_proposal_tracking=tracking) if not ret: return False self.discrete_miner(1) return result
def ready_for_crc_proposal_secretary_general(self): ret = self.crc_proposal_secretary_general() self.get_current_height() self.check_result("crc proposal change secretary general", ret) Logger.info( "{} crc proposal change secretary general on success!".format( self.tag))
def get_dpos_votes(self): list_producers = rpc.list_producers(0, 200) if list_producers is False: return 0 total_votes = float(list_producers["totalvotes"]) # candidates = rpc.get_arbiters_info()["candidates"] dpos_votes = dict() producers = list_producers["producers"] for producer in producers: node_pubkey = producer["nodepublickey"] dpos_votes[ self.node_manager.node_pubkey_name_dict[node_pubkey]] = float( producer["votes"]) # if after_h2_transactions is not None: # for tx_income in after_h2_transactions: # if tx_income.node_pubkey != "" and tx_income.node_pubkey in candidates: # total_votes -= tx_income.votes # node_name = self.node_manager.node_pubkey_name_dict[tx_income.node_pubkey] # origin_votes = dpos_votes[node_name] # origin_votes -= tx_income.votes # dpos_votes[node_name] = origin_votes Logger.debug("{} total votes: {}".format(self.tag, total_votes)) dpos_votes["total"] = total_votes self.dpos_votes_dict = dpos_votes return dpos_votes
def crc_proposal(self): ela_node = self.node_manager.ela_nodes[1] cr_private_key = ela_node.cr_account.private_key() self.owner_private_key = cr_private_key budget_list = list() budget_list.append( Budget(budget_type=Budget.IMPREST, stage=0, amount=100000)) budget_list.append( Budget(budget_type=Budget.NORMAL_PAYMENT, stage=1, amount=200000)) budget_list.append( Budget(budget_type=Budget.NORMAL_PAYMENT, stage=2, amount=300000)) budget_list.append( Budget(budget_type=Budget.FINAL_PAYMENT, stage=3, amount=400000)) result = True crc_proposal = CRCProposal( private_key=cr_private_key, cr_private_key=cr_private_key, proposal_type=CRCProposal.NORMAL, category_data="", draft_hash=Random.get_random_bytes(serialize.UINT256SIZE), budget=budget_list, recipient=bytes.fromhex(ela_node.cr_account.program_hash())) Logger.info("{} create crc proposal on success. \n{}".format( self.tag, crc_proposal)) ret = self.tx_manager.crc_proposal( input_private_key=self.tap_account.private_key(), amount=10 * constant.TO_SELA, crc_proposal=crc_proposal) self.crc_proposal_hash = crc_proposal.hash if not ret: return False self.discrete_miner(1) return result
def test_content(): test_case = "update producer after pre offset but before h2" controller = Controller(config) controller.ready_for_dpos() h1 = controller.params.ela_params.crc_dpos_height h2 = controller.params.ela_params.public_dpos_height pre_offset = config["ela"]["pre_connect_offset"] update_node_prikey = "aa8ad6d1ac6953f7b9a68b5b13fe79d7217fb687651c1c30be12e5e0328b667f" # update_producer_beforeh1 = controller.tx_manager.register_producers_list[0] update_producer = controller.tx_manager.register_producers_list[0] current_height = controller.get_current_height() if current_height < h1 - 5: controller.discrete_mining_blocks(h1 - 5 - current_height) height_times = dict() height_times[current_height] = 1 global result global update_height update_height = 0 while True: current_height = controller.get_current_height() times = controller.get_height_times(height_times, current_height) Logger.debug("current height: {}, times: {}".format( current_height, times)) if times >= 100: result = False break if current_height >= h1: controller.show_arbiter_info() if update_height == 0 and current_height > h1 + 35: producer_payload = update_producer.producer_info() producer_payload.nickname = "^_^ HAHA" producer_payload.node_account = Account(update_node_prikey) producer_payload.url = "127.0.0.1" result = controller.tx_manager.update_producer( update_producer, producer_payload) controller.check_result(test_case, result) if result: controller.node_manager.node_pubkey_name_dict[ update_node_prikey] = producer_payload.nickname update_height = current_height if current_height > h2 + 100: break controller.discrete_mining_blocks(1) time.sleep(1) controller.check_result(test_case, result) controller.terminate_all_process(result)
def has_dpos_reward(self, height: int): response = rpc.get_block_by_height(height) if response is False: Logger.error("{} rpc response invalid".format(self.tag)) return False # Logger.debug("{} response: {}".format(self.tag, response)) return len(response["tx"][0]["vout"]) > 2
def arbiter_public_keys(key_stores): public_keys = [] if len(key_stores) != 5: Logger.error("[common] Invalid argument, the length of the argument must be equal 5") exit(0) for key_store in key_stores: public_keys.append(key_store.public_key.hex()) return public_keys
def add_sub_account(self, sub_account: Account): if not self._valid: Logger.error("Invalid keystore!") return self._sub_accounts_list.append(sub_account) sub_account_data = self._create_account_data(sub_account, self.SUB_ACCOUNT) self._accounts_data_list.append(sub_account_data)
def ready_for_dpos(self): ret = self.tx_manager.register_producers_candidates() self.check_result("register producers", ret) Logger.info("{} register producers on success!".format(self.tag)) ret = self.tx_manager.vote_producers_candidates() self.check_result("vote producers", ret) Logger.info("{} vote producer on success!".format(self.tag)) self.get_dpos_votes()
def create_crc_tracking(self, register_private_key: str, nickname: str, url: str, location: int): cr_info = CRInfo(private_key=register_private_key, nickname=nickname, url=url, location=location) Logger.info("{} create create_crc_tracking on success. \n{}".format( self.tag, cr_info)) return cr_info
def show_arbiter_info(self): arbiters_nicknames = self.get_arbiter_names("arbiters") arbiters_nicknames.sort() next_arbiter_nicknames = self.get_arbiter_names("nextarbiters") next_arbiter_nicknames.sort() Logger.info( "current arbiters nicknames: {}".format(arbiters_nicknames)) Logger.info( "next arbiters nicknames: {}".format(next_arbiter_nicknames))
def check_params(self): if self.params.ela_params.number < 3 * self.params.ela_params.crc_number + \ self.params.ela_params.later_start_number: Logger.error( "Ela node number should be >= 3 * crc number + later start number , " "please check your config in the beginning of your test case or config.json, exit..." ) time.sleep(1) exit(-1)
def test_content(): test_case = "update producer after pre offset but before h2" controller = Controller(config) controller.ready_for_dpos() h1 = controller.params.ela_params.crc_dpos_height h2 = controller.params.ela_params.public_dpos_height pre_offset = config["ela"]["pre_connect_offset"] update_node_pubkey = "0303710a960f04893281fe016ec7563a9c17fb8c7f0bea555b3a9349a6a1646479" # update_producer_beforeh1 = controller.tx_manager.register_producers_list[0] update_producer = controller.tx_manager.register_producers_list[0] current_height = controller.get_current_height() if current_height < h1 - 5: controller.discrete_mining_blocks(h1 - 5 - current_height) height_times = dict() height_times[current_height] = 1 global result global update_height update_height = 0 while True: current_height = controller.get_current_height() times = controller.get_height_times(height_times, current_height) Logger.debug("current height: {}, times: {}".format(current_height, times)) if times >= 100: result = False break if current_height >= h1: controller.show_current_next_info() if update_height == 0 and current_height > h1 + 35: producer_payload = update_producer.info producer_payload.nickname = "^_^ HAHA" producer_payload.node_public_key = bytes.fromhex(update_node_pubkey) producer_payload.url = "127.0.0.1" result = controller.tx_manager.update_producer(update_producer, producer_payload) controller.check_result(test_case, result) if result: controller.rpc_manager.node_info_dict[update_node_pubkey] = producer_payload.nickname update_height = current_height if current_height > h2 + 100: break controller.discrete_mining_blocks(1) time.sleep(1) controller.check_result(test_case, result) controller.terminate_all_process()
def wait_block(self): Logger.info("waiting for the block ... ") count_height = 0 height = self.get_current_height() while True: if height < count_height: break else: time.sleep(10) count_height = self.get_current_height()
def start(self): self.process = subprocess.Popen("./did{}".format(self.index), stdout=self.dev_null, stderr=self.err_output, shell=True, cwd=self.cwd_dir) self.running = True Logger.debug("{} ./did{} started on success.".format( self.tag, self.index)) return True
def get_master_key(self): password_twice_hash = keytool.sha256_hash(str.encode(self.password), 2) encrypt_master_key = self.get_encrypt_master_key() if encrypt_master_key is None: Logger.error("encrypt master key is None") return None master_key = keytool.aes_decrypt(bytes.fromhex(encrypt_master_key), password_twice_hash, self.iv) return master_key
def wait_block(self): Logger.info("waiting for the block ... ") count_height = 0 height = self.get_current_height() while True: if height + 1 >= count_height: rpc.discrete_mining(1) time.sleep(1) count_height = self.get_current_height() else: break
def get_encrypt_private_key(self): if "Account" not in self.keystore_dat.keys(): Logger.error("keystore_dat dose not contain key Account") return None at = self.keystore_dat["Account"][0] if "PrivateKeyEncrypted" not in at.keys(): Logger.error("Account dose not contain key PrivateKeyEncrypted") return None return at["PrivateKeyEncrypted"]
def stop(self): if not self.running: Logger.error("{} arbiter{} has already stopped".format(self.tag, self.index)) return try: self.process.terminate() self.dev_null.close() self.err_output.close() except subprocess.SubprocessError as e: Logger.error("{} Unable to stop arbiter{}, error: {}".format(self.tag, self.index, e)) self.running = False
def serialize(self, version: int): if self.candidates is None or len(self.candidates) == 0: Logger.error("candidates list is empty!") return None r = b"" r += struct.pack("<B", self.vote_type) r += serialize.write_var_uint(len(self.candidates)) for candidate in self.candidates: r = serialize.write_var_bytes(r, candidate) return r
def get_total_tx_fee(self, transactions: list): Logger.debug("{} transactions length: {}".format( self.tag, len(transactions))) if len(transactions) == 0: return 0 tx_fee = 0 for tx in transactions: if tx.valid: tx_fee += tx.tx_fee return tx_fee