def create_vote_transaction(input_private_key: str, candidates_list: list, amount: int, rpc_port: int, vote_content): # check output if candidates_list is None or len(candidates_list) == 0: Logger.error("Invalid output addresses") return None # candidates_bytes_list = list() # # for candidate in candidates_list: # candidates_bytes_list.append(bytes.fromhex(candidate)) # create outputs account = Account(input_private_key) outputs = create_vote_output(account.address(), amount, vote_content) # create inputs total_amount = amount + util.TX_FEE inputs, change_outputs = create_normal_inputs(account.address(), total_amount, rpc_port) if inputs is None or change_outputs is None: Logger.error("Create normal inputs failed") return None outputs.extend(change_outputs) # create program programs = list() redeem_script = bytes.fromhex(account.redeem_script()) program = Program(code=redeem_script, params=None) programs.append(program) # create attributes attributes = list() attribute = Attribute( usage=Attribute.NONCE, data=bytes("attributes".encode()) ) attributes.append(attribute) tx = Transaction() tx.version = Transaction.TX_VERSION_09 tx.tx_type = Transaction.TRANSFER_ASSET tx.payload = Payload(Payload.DEFAULT_VERSION) tx.attributes = attributes tx.inputs = inputs tx.outputs = outputs tx.lock_time = 0 tx.programs = programs return tx
def transfer_multi_cross_chain_asset(self, input_private_key: str, lock_address: str, cross_address: str, tx_count: int, amount: int, recharge: bool, port: int): account = Account(input_private_key) response = rpc.list_unspent_utxos(account.address(), port=port) if not response or isinstance(response, dict): Logger.error("get utxos return error: {}".format(response)) return False utxos = response if len(utxos) < tx_count: Logger.error("utxo is not enough") return False for i in range(tx_count): current_utxos = list() utxo = utxos[i] current_utxos.append(utxo) Logger.info("current cross chain index: {}".format(i)) tx = txbuild.create_cross_chain_transaction_by_utxo( input_private_key=input_private_key, lock_address=lock_address, cross_chain_address=cross_address, amount=amount, recharge=recharge, utxos=current_utxos) if tx is None: return False tx = txbuild.single_sign_transaction(input_private_key, tx) Logger.debug("cross chain asset transaction: \n{}".format(tx)) ret = self.handle_tx_result(tx, port) return ret
def create_crc_proposal_tracking_transaction(input_private_key: str, amount: int, payload: CRCProposalTracking, rpc_port: int): # create outputs account = Account(input_private_key) outputs, total_amount = create_normal_outputs( output_addresses=[account.address()], amount=amount, fee=util.TX_FEE, output_lock=0 ) # create inputs inputs, change_outputs = create_normal_inputs(account.address(), total_amount, rpc_port) if inputs is None or change_outputs is None: Logger.error("Create normal inputs failed") return None outputs.extend(change_outputs) # create program programs = list() redeem_script = bytes.fromhex(account.redeem_script()) program = Program(code=redeem_script, params=None) programs.append(program) # create attributes attributes = list() attribute = Attribute( usage=Attribute.NONCE, data=bytes("attributes".encode()) ) attributes.append(attribute) tx = Transaction() tx.version = Transaction.TX_VERSION_09 tx.tx_type = Transaction.CRC_PROPOSAL_TRACKING tx.payload_version = 0 tx.payload = payload tx.attributes = attributes tx.inputs = inputs tx.outputs = outputs tx.lock_time = 0 tx.programs = programs return tx
def create_transaction(input_private_key: str, output_addresses: list, amount: int, rpc_port: int, side_chain: bool): account = Account(input_private_key) # check output if output_addresses is None or len(output_addresses) == 0: Logger.error("Invalid output addresses") return None # create outputs outputs, total_amount = create_normal_outputs( output_addresses=output_addresses, amount=amount, fee=util.TX_FEE, output_lock=0 ) # create inputs inputs, change_outputs = create_normal_inputs(account.address(), total_amount, rpc_port) if inputs is None or change_outputs is None: Logger.error("Create normal inputs failed") return None outputs.extend(change_outputs) # create program programs = list() redeem_script = bytes.fromhex(account.redeem_script()) program = Program(code=redeem_script, params=None) programs.append(program) # create attributes attributes = list() attribute = Attribute( usage=Attribute.NONCE, data=bytes("attributes".encode()) ) attributes.append(attribute) tx = Transaction() if not side_chain : tx.version = Transaction.TX_VERSION_09 else: tx.version = Transaction.TX_VERSION_DEFAULT tx.tx_type = Transaction.TRANSFER_ASSET tx.payload = Payload(Payload.DEFAULT_VERSION) tx.attributes = attributes tx.inputs = inputs tx.outputs = outputs tx.lock_time = 0 tx.programs = programs return tx
def _create_account_data(self, account: Account, account_type: str): private_key_encrypted = keytool.encrypt_private_key( self._master_key, bytes.fromhex(account.private_key()), account.ecc_public_key(), self._iv) account_data = dict() account_data["Address"] = account.address() account_data["ProgramHash"] = account.program_hash() account_data["RedeemScript"] = account.redeem_script() account_data["PrivateKeyEncrypted"] = private_key_encrypted.hex() account_data["Type"] = account_type return account_data
def create_cancel_transaction(input_private_key: str, payload: ProducerInfo, rpc_port: int): # create inputs account = Account(input_private_key) inputs, change_outputs = create_normal_inputs(account.address(), util.TX_FEE, rpc_port) if inputs is None or change_outputs is None: Logger.error("Create normal inputs failed") return None # create outputs outputs = list() outputs.extend(change_outputs) # create program programs = list() redeem_script = bytes.fromhex(account.redeem_script()) program = Program(code=redeem_script, params=None) programs.append(program) # create attributes attributes = list() attribute = Attribute( usage=Attribute.NONCE, data=bytes("attributes".encode()) ) attributes.append(attribute) payload = ProcessProducer(bytes.fromhex(payload.owner_account.public_key()), bytes.fromhex(payload.owner_account.private_key())) tx = Transaction() tx.version = Transaction.TX_VERSION_09 tx.tx_type = Transaction.CANCEL_PRODUCER tx.payload_version = 0 tx.payload = payload tx.attributes = attributes tx.inputs = inputs tx.outputs = outputs tx.lock_time = 0 tx.programs = programs return tx
def create_cr_update_transaction(input_private_key: str, update_payload: CRInfo, rpc_port: int): # create inputs account = Account(input_private_key) inputs, change_outputs = create_normal_inputs(account.address(), util.TX_FEE, rpc_port) if inputs is None or change_outputs is None: Logger.error("Create normal inputs failed") return None # create outputs outputs = list() outputs.extend(change_outputs) # create program programs = list() redeem_script = bytes.fromhex(account.redeem_script()) program = Program(code=redeem_script, params=None) programs.append(program) # create attributes attributes = list() attribute = Attribute( usage=Attribute.NONCE, data=bytes("attributes".encode()) ) attributes.append(attribute) # update_payload.gen_signature() tx = Transaction() tx.version = Transaction.TX_VERSION_09 tx.tx_type = Transaction.UPDATE_CR tx.payload_version = 0 tx.payload = update_payload tx.attributes = attributes tx.inputs = inputs tx.outputs = outputs tx.lock_time = 0 tx.programs = programs return tx
def create_cross_chain_transaction_by_utxo(input_private_key: str, lock_address: str, cross_chain_address: str, amount: int, recharge: bool, utxos: list): if lock_address is None or lock_address is "": Logger.error("Invalid lock address") return None if cross_chain_address is None or cross_chain_address is "": Logger.error("Invalid cross chain address") return None account = Account(input_private_key) # create outputs: outputs, total_amount = create_normal_outputs( output_addresses=[lock_address], amount=amount, fee=util.TX_FEE, output_lock=0 ) # create inputs: inputs, change_outputs = create_normal_inputs_by_utxo( account.address(), total_amount, utxos) if inputs is None or change_outputs is None: Logger.error("Create normal inputs failed") return None outputs.extend(change_outputs) # create program programs = list() redeem_script = bytes.fromhex(account.redeem_script()) program = Program(code=redeem_script, params=None) programs.append(program) # create attributes attributes = list() attribute = Attribute( usage=Attribute.NONCE, data=bytes("attributes".encode()) ) attributes.append(attribute) cross_chain_asset = TransferCrossChainAsset() cross_chain_asset.cross_chain_addresses = [cross_chain_address] cross_chain_asset.output_indexes = [0] cross_chain_asset.cross_chain_amounts = [amount - 10000] tx = Transaction() if recharge: tx.version = Transaction.TX_VERSION_09 else: tx.version = Transaction.TX_VERSION_DEFAULT # Logger.debug("transaction version {}".format(tx.version)) tx.tx_type = Transaction.TRANSFER_CROSS_CHAIN_ASSET tx.payload = cross_chain_asset tx.attributes = attributes tx.inputs = inputs tx.outputs = outputs tx.lock_time = 0 tx.programs = programs return tx
class Proposal(object): def __init__(self, input_private_key: str, node: ElaNode, nick_name: str, url: str, location: int, net_address: str): self.input_private_key = input_private_key self.input = Account(input_private_key) self.node = node self.utxo_value = 0 self.fee = 10000 self.state = "" self.deposit_amount = 5000 * util.TO_SELA self.info = self._producer_info(self.node.owner_account, self.node.node_account, nick_name, url, location, net_address) @staticmethod def _producer_info(owner_account: Account, node_account: Account, nick_name: str, url: str, location: int, net_address: str): info = ProducerInfo(owner_account=owner_account, node_account=node_account, nickname=nick_name, url=url, location=location, net_address=net_address) return info def producer_info(self): return self.info def input_account(self): return self.input def owner_account(self): return self.node.owner_account def node_account(self): return self.node.node_account def register(self, rpc_port: int): tx = txbuild.create_register_transaction( input_private_key=self.input_private_key, amount=self.deposit_amount, payload=self.info, rpc_port=rpc_port) if tx is None: return None tx = txbuild.single_sign_transaction(self.input_private_key, tx) return tx def update(self, producer_info: ProducerInfo, rpc_port: int): tx = txbuild.create_update_transaction( input_private_key=self.input_private_key, payload=producer_info, rpc_port=rpc_port) if tx is None: return None producer_info.gen_signature() tx = txbuild.single_sign_transaction(self.input_private_key, tx) return tx def cancel(self, rpc_port: int): tx = txbuild.create_cancel_transaction( input_private_key=self.input_private_key, payload=self.producer_info(), rpc_port=rpc_port) if tx is None: return None tx = txbuild.single_sign_transaction(self.input_private_key, tx) return tx def redeem(self, amount: int, rpc_port: int): tx = txbuild.create_redeem_transaction( payload=self.producer_info(), output_address=self.input.address(), amount=amount, rpc_port=rpc_port) if tx is None: return None tx = txbuild.single_sign_transaction( self.producer_info().owner_account.private_key(), tx) return tx def active(self): # note activate producer transaction needn't to sign the whole transaction tx = txbuild.create_active_transaction( self.node_account().private_key(), self.node_account().public_key()) if tx is None: return None return tx def __repr__(self): return self.producer_info().__repr__()
class Controller(object): PRODUCER_STATE_ACTIVE = "Active" PRODUCER_STATE_INACTIVE = "Inactive" # CR_Foundation_TEMP = "EULhetag9FKS6Jd6aifFaPqjFTpZbSMY7u" CR_Foundation_TEMP = "CRASSETSXXXXXXXXXXXXXXXXXXXX2qDX5J" SECRETARY_PRIVATE_KEY = "E0076A271A137A2BD4429FA46E79BE3E10F2A730585F8AC2763D570B60469F11" CRC_COMMITTEE_ADDRESS = "CREXPENSESXXXXXXXXXXXXXXXXXX4UdT6b" def __init__(self, up_config: dict): self.tag = util.tag_from_path(__file__, Controller.__name__) # set config self.up_config = up_config self.root_path = os.path.abspath( os.path.join(os.path.abspath(__file__), "../../../")) self.config = util.read_config_file( os.path.join(self.root_path, "config.json")) self.node_types = ["ela", "arbiter", "did", "token", "neo"] self.reset_config(up_config) self.params = Parameter(self.config, self.root_path) self.check_params() self.env_manager = EnvManager() self.keystore_manager = KeyStoreManager(self.params) self.node_manager = NodeManager(self.params, self.env_manager, self.keystore_manager) self.tx_manager = TransactionManager(self.node_manager) # init tap amount and register amount(unit: ELA) self.tap_amount = 20000000 self.register_amount = 6000 self.node_amount = 5000 # necessary keystore self.foundation_account = self.keystore_manager.foundation_account self.tap_account = self.keystore_manager.tap_account # pressure keystore self.pressure_account = Account() self.init_for_testing() self.later_nodes = self.node_manager.ela_nodes[( self.params.ela_params.number - self.params.ela_params.later_start_number + 1):] self.dpos_votes_dict = dict() self.crc_proposal_hash = bytes() self.owner_private_key = None self.secretary_private_key = self.SECRETARY_PRIVATE_KEY def init_for_testing(self): self.node_manager.deploy_nodes() Logger.info("{} deploying nodes on success!".format(self.tag)) self.node_manager.start_nodes() self.node_manager.create_address_name_dict() self.node_manager.create_owner_pubkey_name_dict() self.node_manager.create_node_pubkey_name_dict() self.node_manager.create_normal_dpos_pubkey() Logger.info("{} starting nodes on success!".format(self.tag)) self.mining_blocks_ready(self.foundation_account.address()) Logger.info("{} mining 110 blocks on success!".format(self.tag)) time.sleep(5) ret = self.tx_manager.recharge_necessary_keystore( input_private_key=self.foundation_account.private_key(), accounts=[self.tap_account], amount=self.tap_amount * constant.TO_SELA) self.check_result("recharge tap keystore", ret) Logger.info("{} recharge tap keystore {} ELAs on success!".format( self.tag, self.tap_amount * constant.TO_SELA)) ret = self.tx_manager.recharge_necessary_keystore( input_private_key=self.tap_account.private_key(), accounts=self.keystore_manager.owner_accounts, amount=self.register_amount * constant.TO_SELA) self.check_result("recharge owner keystore", ret) ret = self.tx_manager.recharge_necessary_keystore( input_private_key=self.tap_account.private_key(), accounts=self.keystore_manager.node_accounts, amount=self.node_amount * constant.TO_SELA) self.check_result("recharge node keystore", ret) Logger.info("{} recharge producer on success!".format(self.tag)) if self.params.arbiter_params.enable: ret = self.tx_manager.recharge_necessary_keystore( input_private_key=self.tap_account.private_key(), accounts=self.keystore_manager.sub1_accounts, amount=3 * constant.TO_SELA) self.check_result("recharge sub1 keystore", ret) Logger.info("{} recharge each sub1 keystore {} ELAs on success!") ret = self.tx_manager.recharge_necessary_keystore( input_private_key=self.tap_account.private_key(), accounts=self.keystore_manager.sub2_accounts, amount=3 * constant.TO_SELA) self.check_result("recharge sub2 keystore", ret) Logger.info("{} recharge each sub2 keystore {} ELAs on success!") ret = self.tx_manager.recharge_necessary_keystore( input_private_key=self.tap_account.private_key(), accounts=self.keystore_manager.sub3_accounts, amount=3 * constant.TO_SELA) self.check_result("recharge sub3 keystore", ret) Logger.info("{} recharge each sub3 keystore {} ELAs on success!") ret = self.tx_manager.recharge_necessary_keystore( input_private_key=self.tap_account.private_key(), accounts=self.keystore_manager.sub4_accounts, amount=3 * constant.TO_SELA) self.check_result("recharge sub4 keystore", ret) Logger.info("{} recharge each sub4 keystore {} ELAs on success!") def ready_for_pressure_inputs(self, inputs_num: int): ret = self.pressure_inputs(inputs_num) self.check_result("pressure inputs number:{}".format(inputs_num), ret) Logger.info("{}pressure inputs on success!".format(self.tag)) def ready_for_pressure_big_block(self, data_size: int): ret = self.pressure_big_block(data_size) self.check_result("pressure big block size:{} ".format(data_size), ret) Logger.info("{}pressure big block on success!".format( self.tag, data_size)) def pressure_inputs(self, inputs_num: int): output_addresses = list() for i in range(inputs_num): output_addresses.append(self.pressure_account.address()) ret = self.tx_manager.transfer_asset(self.tap_account.private_key(), output_addresses, 1 * util.TO_SELA) if ret: self.wait_block() value = rpc.get_balance_by_address(self.pressure_account.address()) Logger.debug("{} account {} wallet balance: {}".format( self.tag, self.pressure_account.address(), value)) ret = self.tx_manager.transfer_asset( self.pressure_account.private_key(), [self.pressure_account.address()], int(Decimal(value) * util.TO_SELA - util.TX_FEE)) if ret: self.wait_block() return True else: Logger.error("{} pressure inputs transfer failed".format( self.tag)) return False else: Logger.error("{} pressure outupts transfer failed".format( self.tag)) return ret def pressure_big_block(self, data_size): attributes = list() attribute = Attribute(usage=Attribute.NONCE, data=Random.get_random_bytes(data_size)) attributes.append(attribute) ret = self.tx_manager.transfer_abnormal_asset( self.tap_account.private_key(), [self.tap_account.address()], 1 * util.TO_SELA, attributes=attributes) if ret: self.wait_block() return True else: Logger.error("{} pressure big block transfer failed".format( self.tag)) return False 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 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 ready_for_cr(self): ret = self.register_cr_candidates() self.get_current_height() self.check_result("register cr", ret) Logger.info("{} register cr on success!".format(self.tag)) ret = self.tx_manager.vote_cr_candidates() self.get_current_height() self.check_result("vote cr", ret) Logger.info("{} vote cr on success!".format(self.tag)) # transfer to CRFoundation # self.tx_manager.transfer_asset(self.tap_account.private_key(), [self.CR_Foundation_TEMP], 5000 * util.TO_SELA) # if ret: # rpc.discrete_mining(1) # value = rpc.get_balance_by_address(self.CR_Foundation_TEMP) # Logger.debug("{} CRFoundation {} wallet balance: {}".format(self.tag, self.CR_Foundation_TEMP, value)) # else: # Logger.error("{} CRFoundation transfer failed".format(self.tag)) self.tx_manager.transfer_asset(self.tap_account.private_key(), [self.CRC_COMMITTEE_ADDRESS], 5000 * util.TO_SELA) if ret: rpc.discrete_mining(1) value = rpc.get_balance_by_address(self.CRC_COMMITTEE_ADDRESS) Logger.debug("{} CRFoundation {} wallet balance: {}".format( self.tag, self.CRC_COMMITTEE_ADDRESS, value)) else: Logger.error("{} CRFoundation transfer failed".format(self.tag)) def ready_for_crc_proposal(self): ret = self.crc_proposal() self.get_current_height() self.check_result("crc proposal", ret) Logger.info("{} crc proposal on success!".format(self.tag)) 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 ready_for_crc_proposal_change_owner(self): ret = self.crc_proposal_change_owner() self.get_current_height() self.check_result("crc proposal change owner", ret) Logger.info("{} crc proposal change owneron success!".format(self.tag)) def ready_for_crc_proposal_review(self): ret = self.crc_proposal_review() self.get_current_height() self.check_result("crc proposal review", ret) Logger.info("{} crc proposal review on success!".format(self.tag)) self.discrete_miner(self.params.ela_params.proposal_cr_voting_period) ret = self.tx_manager.vote_crc_proposal_candidates( self.crc_proposal_hash) self.get_current_height() self.check_result("vote cr proposal", ret) Logger.info("{} vote crc proposal on success!".format(self.tag)) self.discrete_miner( self.params.ela_params.proposal_public_voting_period) def ready_for_crc_proposal_tracking(self): # common ret = self.crc_proposal_tracking(None, CRCProposalTracking.COMMON, 0) self.get_current_height() self.check_result("crc proposal tracking common type", ret) Logger.info("{} crc proposal tracking common on success!".format( self.tag)) # progress ret = self.crc_proposal_tracking(None, CRCProposalTracking.PROGRESS, 1) self.get_current_height() self.check_result("crc proposal tracking progress type", ret) Logger.info("{} crc proposal tracking progress on success!".format( self.tag)) # Reject ret = self.crc_proposal_tracking(None, CRCProposalTracking.REJECTED, 2) self.get_current_height() self.check_result("crc proposal tracking reject type", ret) Logger.info("{} crc proposal tracking reject on success!".format( self.tag)) # progress ret = self.crc_proposal_tracking(None, CRCProposalTracking.PROGRESS, 2) self.get_current_height() self.check_result("crc proposal tracking progress type", ret) Logger.info("{} crc proposal tracking progress on success!".format( self.tag)) # proposal leader ela_node = self.node_manager.ela_nodes[2] new_leader_private_key = ela_node.cr_account.private_key() ret = self.crc_proposal_tracking(new_leader_private_key, CRCProposalTracking.PROPOSAL_LEADER, 0) self.get_current_height() self.check_result("crc proposal tracking proposal leader type", ret) Logger.info( "{} crc proposal tracking proposal leader on success!".format( self.tag)) self.owner_private_key = new_leader_private_key # finalized ret = self.crc_proposal_tracking(None, CRCProposalTracking.FINALIZED, 3) self.get_current_height() self.check_result("crc proposal tracking finalized type", ret) Logger.info("{} crc proposal tracking finalized on success!".format( self.tag)) # Terminated # ret = self.crc_proposal_tracking(p_hash, leader_private_key, None, CRCProposalTracking.TERMINATED, 0) # self.get_current_height() # self.check_result("crc proposal tracking terminated type", ret) # Logger.info("{} crc proposal tracking terminated on success!".format(self.tag)) def ready_for_crc_proposal_withdraw(self): ret = self.crc_proposal_withdraw() self.get_current_height() self.check_result("crc proposal withdraw", ret) Logger.info("{} crc proposal withdraw on success!".format(self.tag)) 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_review(self): global result result = True for i in range(1, self.params.ela_params.crc_number + 1): ela_node = self.node_manager.ela_nodes[i] cr_private_key = ela_node.cr_account.private_key() review = CRCProposalReview(private_key=cr_private_key, proposal_hash=self.crc_proposal_hash, vote_result=CRCProposalReview.APPROVE, opinion_hash=Random.get_random_bytes( serialize.UINT256SIZE)) Logger.info( "{} create crc proposal review on success. \n{}".format( self.tag, review)) ret = self.tx_manager.crc_proposal_review( input_private_key=self.tap_account.private_key(), amount=10 * constant.TO_SELA, crc_proposal_review=review) if not ret: return False self.discrete_miner(1) Logger.info("{} node-{} review on success!\n".format(self.tag, i)) 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 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 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(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 register_cr_candidates(self): global result result = True for i in range(1, self.params.ela_params.crc_number + 1): ela_node = self.node_manager.ela_nodes[i] cid = ela_node.cr_account.cid_address() cr_info = self.create_cr_info( register_private_key=ela_node.cr_account.private_key(), nickname="CR-00{}".format(i), url="www.00{}.com".format(i), location=0) ret = self.tx_manager.register_cr( input_private_key=self.tap_account.private_key(), amount=5000 * constant.TO_SELA, cr_info=cr_info) if not ret: return False self.discrete_miner(7) status = self.get_cr_status(cid) Logger.debug( "After mining 7 blocks, register status: {}".format(status)) result = status == "Active" if not result: Logger.error("{} register CR {} failed".format( self.tag, ela_node.name)) break Logger.info("{} register CR-{} to be a CR on success!\n".format( self.tag, i)) return result def create_cr_info(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 cr_info on success. \n{}".format( self.tag, cr_info)) return cr_info def register_a_cr(self, input_private_key: str, cr_info: CRInfo): ret = self.tx_manager.register_cr(input_private_key=input_private_key, amount=5000 * constant.TO_SELA, cr_info=cr_info) self.check_result("register a cr", ret) return ret def create_crc_proposal(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_proposal on success. \n{}".format( self.tag, cr_info)) return cr_info def create_crc_proposal_review(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_proposal_review on success. \n{}".format( self.tag, cr_info)) return cr_info 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 mining_blocks_ready(self, foundation_address): time.sleep(3) rpc.discrete_mining(110) balance = rpc.get_balance_by_address(foundation_address) Logger.debug("{} foundation address value: {}".format( self.tag, balance)) 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 get_arbiter_names(self, category: str): arbiters = rpc.get_arbiters_info()[category] current_nicknames = list() for public_key in arbiters: current_nicknames.append( self.node_manager.node_pubkey_name_dict[public_key]) return current_nicknames 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 reset_config(self, up_config: dict): for key in up_config.keys(): if key is "side": if not up_config[key]: self.config["arbiter"]["enable"] = False self.config["did"]["enable"] = False self.config["token"]["enable"] = False self.config["neo"]["enable"] = False continue if key in self.node_types: _config = self.up_config[key] for k in _config.keys(): self.config[key][k] = _config[k] 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 start_later_nodes(self): for node in self.later_nodes: node.start() def check_result(self, case: str, result: bool):
class TxControl(object): PRODUCER_STATE_ACTIVE = "Active" PRODUCER_STATE_INACTIVE = "Inactive" # CR_Foundation_TEMP = "EULhetag9FKS6Jd6aifFaPqjFTpZbSMY7u" CR_Foundation_TEMP = "CRASSETSXXXXXXXXXXXXXXXXXXXX2qDX5J" SECRETARY_PRIVATE_KEY = "E0076A271A137A2BD4429FA46E79BE3E10F2A730585F8AC2763D570B60469F11" CRC_COMMITTEE_ADDRESS = "CREXPENSESXXXXXXXXXXXXXXXXXX4UdT6b" def __init__(self, config: dict): self.tag = util.tag_from_path(__file__, TxControl.__name__) self._init_config(config) self.tap_account = Account(private_key_str=self.tap_private_key) self.pressure_account = Account( private_key_str=self.pressure_private_key) self.register_amount = 6000 self.node_amount = 5000 self.dpos_votes_dict = dict() self.producers_list = list() self.cr_list = list() self.tx_manager = TxManager(self.rpc_port) def _init_config(self, config: dict): self.rpc_port = config["rpc_port"] self.host = config["host"] self.outputs_num = config["outputs_num"] self.inputs_num = config["inputs_num"] self.block_size = config["block_size"] self.pressure_private_key = config["pressure_private_key"] self.tap_private_key = config["tap_private_key"] self.lock_address = config["lock_address"] self.recharge = config["recharge"] self.eth_tap_address = config["eth_tap_address"] rpc.DEFAULT_HOST = self.host def ready_for_pressure_outputs(self): ret = self.pressure_outputs() self.check_result( "pressure outputs number:{}".format(self.outputs_num), ret) Logger.info("{}pressure outputs on success!".format(self.tag)) def ready_for_pressure_inputs(self): ret = self.pressure_inputs() self.check_result("pressure inputs number:{}".format(self.inputs_num), ret) Logger.info("{}pressure inputs on success!".format(self.tag)) def ready_for_pressure_cross_chain(self): Logger.info("waiting for cross chain pressure test ... ") ret = self.pressure_cross_chain() self.check_result( "pressure cross chain number:{}".format(self.outputs_num), ret) Logger.info("{}pressure cross chain on success!".format(self.tag)) def ready_for_pressure_big_block(self): ret = self.pressure_big_block() self.check_result( "pressure big block size:{} ".format(self.block_size), ret) Logger.info("{}pressure big block on success!".format( self.tag, self.block_size)) def pressure_outputs(self): output_addresses = list() for i in range(self.outputs_num): output_addresses.append(self.pressure_account.address()) ret = self.tx_manager.transfer_asset(self.tap_account.private_key(), output_addresses, util.TX_SINGLE_OUTPUT, not self.recharge) if ret: self.wait_block() return True else: Logger.error("{} pressure outputs transfer failed".format( self.tag)) return False def pressure_inputs(self): value = self.inputs_num * util.TX_FEE Logger.debug("{} account {} wallet balance: {}".format( self.tag, self.pressure_account.address(), value)) ret = self.tx_manager.transfer_asset( self.pressure_account.private_key(), [self.tap_account.address()], value - util.TX_FEE) if ret: self.wait_block() return True else: Logger.error("{} pressure inputs transfer failed".format(self.tag)) return False def pressure_cross_chain(self): value = self.outputs_num * util.TX_SINGLE_OUTPUT Logger.info("{} account {} wallet balance: {}".format( self.tag, self.pressure_account.address(), value)) #self.tap_account.address(), #"0x53781e106a2e3378083bdcede1874e5c2a7225f8", ret = self.tx_manager.transfer_multi_cross_chain_asset( self.pressure_account.private_key(), self.lock_address, self.eth_tap_address, self.outputs_num, util.TX_SINGLE_OUTPUT - util.TX_FEE, self.recharge, self.rpc_port) if ret: self.wait_block() return True else: Logger.error("{} pressure inputs transfer failed".format(self.tag)) return False def pressure_big_block(self): attributes = list() attribute = Attribute(usage=Attribute.NONCE, data=Random.get_random_bytes(self.block_size)) attributes.append(attribute) ret = self.tx_manager.transfer_abnormal_asset( self.tap_account.private_key(), [self.tap_account.address()], 1 * util.TO_SELA, attributes=attributes) if ret: self.wait_block() return True else: Logger.error("{} pressure big block transfer failed".format( self.tag)) return False def ready_for_dpos(self): producers = rpc.list_producers(0, 100, state="active") if producers is None: Logger.info('{} list producers is null'.format(self.tag)) return Logger.debug('{} list producers:{}'.format(self.tag, producers)) self.producers_list = producers["producers"] ret = self.vote_producers_candidates() self.check_result("vote producers", ret) Logger.info("{} vote producer on success!".format(self.tag)) # self.get_dpos_votes() def ready_for_cr(self): cr = rpc.list_current_crs() # cr = rpc.list_cr_candidates(0, 100, state="active") if cr is None: Logger.info('{} list cr is null'.format(self.tag)) return Logger.debug('{} list cr:{}'.format(self.tag, cr)) # self.cr_list = cr["crcandidatesinfo"] self.cr_list = cr["crmembersinfo"] ret = self.vote_cr_candidates() self.check_result("vote cr", ret) Logger.info("{} vote cr on success!".format(self.tag)) def ready_for_crc_proposal(self): ret, p_hash = self.crc_proposal() self.get_current_height() self.check_result("crc proposal", ret) Logger.info("{} crc proposal on success!".format(self.tag)) return p_hash def ready_for_crc_proposal_review(self, p_hash: bytes): ret = self.crc_proposal_review(p_hash) self.get_current_height() self.check_result("crc proposal review", ret) Logger.info("{} crc proposal review on success!".format(self.tag)) self.discrete_miner(self.params.ela_params.proposal_cr_voting_period) ret = self.tx_manager.vote_crc_proposal_candidates() self.get_current_height() self.check_result("vote cr proposal", ret) Logger.info("{} vote crc proposal on success!".format(self.tag)) self.discrete_miner( self.params.ela_params.proposal_public_voting_period) def ready_for_crc_proposal_tracking(self, p_hash: bytes): ela_node = self.node_manager.ela_nodes[1] leader_private_key = ela_node.cr_account.private_key() # common ret = self.crc_proposal_tracking(p_hash, leader_private_key, None, CRCProposalTracking.COMMON, 0) self.get_current_height() self.check_result("crc proposal tracking common type", ret) Logger.info("{} crc proposal tracking common on success!".format( self.tag)) # progress ret = self.crc_proposal_tracking(p_hash, leader_private_key, None, CRCProposalTracking.PROGRESS, 1) self.get_current_height() self.check_result("crc proposal tracking progress type", ret) Logger.info("{} crc proposal tracking progress on success!".format( self.tag)) # Reject ret = self.crc_proposal_tracking(p_hash, leader_private_key, None, CRCProposalTracking.REJECTED, 2) self.get_current_height() self.check_result("crc proposal tracking reject type", ret) Logger.info("{} crc proposal tracking reject on success!".format( self.tag)) # progress ret = self.crc_proposal_tracking(p_hash, leader_private_key, None, CRCProposalTracking.PROGRESS, 2) self.get_current_height() self.check_result("crc proposal tracking progress type", ret) Logger.info("{} crc proposal tracking progress on success!".format( self.tag)) # proposal leader ela_node = self.node_manager.ela_nodes[2] new_leader_private_key = ela_node.cr_account.private_key() ret = self.crc_proposal_tracking(p_hash, leader_private_key, new_leader_private_key, CRCProposalTracking.PROPOSAL_LEADER, 0) self.get_current_height() self.check_result("crc proposal tracking proposal leader type", ret) Logger.info( "{} crc proposal tracking proposal leader on success!".format( self.tag)) # finalized ret = self.crc_proposal_tracking(p_hash, new_leader_private_key, None, CRCProposalTracking.FINALIZED, 3) self.get_current_height() self.check_result("crc proposal tracking finalized type", ret) Logger.info("{} crc proposal tracking finalized on success!".format( self.tag)) # Terminated # ret = self.crc_proposal_tracking(p_hash, leader_private_key, None, CRCProposalTracking.TERMINATED, 0) # self.get_current_height() # self.check_result("crc proposal tracking terminated type", ret) # Logger.info("{} crc proposal tracking terminated on success!".format(self.tag)) def ready_for_crc_proposal_withdraw(self, p_hash: bytes): ret = self.crc_proposal_withdraw(p_hash) self.get_current_height() self.check_result("crc proposal withdraw", ret) Logger.info("{} crc proposal withdraw on success!".format(self.tag)) def crc_proposal_withdraw(self, p_hash: bytes): 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=p_hash, ) Logger.info("{} create crc proposal withdraw on success. \n{}".format( self.tag, withdraw)) amount = self.get_withdraw_amount(p_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_review(self, p_hash: bytes): global result result = True for i in range(1, self.params.ela_params.crc_number + 1): ela_node = self.node_manager.ela_nodes[i] cr_private_key = ela_node.cr_account.private_key() review = CRCProposalReview(private_key=cr_private_key, proposal_hash=p_hash, vote_result=CRCProposalReview.APPROVE, opinion_hash=Random.get_random_bytes( serialize.UINT256SIZE)) Logger.info( "{} create crc proposal review on success. \n{}".format( self.tag, review)) ret = self.tx_manager.crc_proposal_review( input_private_key=self.tap_account.private_key(), amount=10 * constant.TO_SELA, crc_proposal_review=review) if not ret: return False self.discrete_miner(1) Logger.info("{} node-{} review on success!\n".format(self.tag, i)) return result def crc_proposal_tracking(self, p_hash: bytes, leader_private_key: str, 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=leader_private_key, new_leader_private_key=new_leader_private_key, proposal_hash=p_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 crc_proposal(self): ela_node = self.node_manager.ela_nodes[1] cr_private_key = ela_node.cr_account.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="normal", 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) if not ret: return False, crc_proposal.hash self.discrete_miner(1) return result, crc_proposal.hash def register_cr_candidates(self): global result result = True for i in range(1, self.params.ela_params.crc_number + 1): ela_node = self.node_manager.ela_nodes[i] cid = ela_node.cr_account.cid_address() cr_info = self.create_cr_info( register_private_key=ela_node.cr_account.private_key(), nickname="CR-00{}".format(i), url="www.00{}.com".format(i), location=0) ret = self.tx_manager.register_cr( input_private_key=self.tap_account.private_key(), amount=5000 * constant.TO_SELA, cr_info=cr_info) if not ret: return False self.discrete_miner(7) status = self.get_cr_status(cid) Logger.debug( "After mining 7 blocks, register status: {}".format(status)) result = status == "Active" if not result: Logger.error("{} register CR {} failed".format( self.tag, ela_node.name)) break Logger.info("{} register node-{} to be a CR on success!\n".format( self.tag, i)) return result def create_cr_info(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 cr_info on success. \n{}".format( self.tag, cr_info)) return cr_info def register_a_cr(self, input_private_key: str, cr_info: CRInfo): ret = self.tx_manager.register_cr(input_private_key=input_private_key, amount=5000 * constant.TO_SELA, cr_info=cr_info) self.check_result("register a cr", ret) return ret def create_crc_proposal(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_proposal on success. \n{}".format( self.tag, cr_info)) return cr_info def create_crc_proposal_review(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_proposal_review on success. \n{}".format( self.tag, cr_info)) return cr_info 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 mining_blocks_ready(self, foundation_address): time.sleep(3) rpc.discrete_mining(110) balance = rpc.get_balance_by_address(foundation_address) Logger.debug("{} foundation address value: {}".format( self.tag, balance)) 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 get_arbiter_names(self, category: str): arbiters = rpc.get_arbiters_info()[category] current_nicknames = list() for public_key in arbiters: current_nicknames.append( self.node_manager.node_pubkey_name_dict[public_key]) return current_nicknames 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 reset_config(self, up_config: dict): for key in up_config.keys(): if key is "side": if not up_config[key]: self.config["arbiter"]["enable"] = False self.config["did"]["enable"] = False self.config["token"]["enable"] = False self.config["neo"]["enable"] = False continue if key in self.node_types: _config = self.up_config[key] for k in _config.keys(): self.config[key][k] = _config[k] def vote_producers_candidates(self): candidates = list() vote_amount = 10 p = len(self.producers_list) if len(self.producers_list) > 36: p = 36 for i in range(1, p): producer = self.producers_list[i]["ownerpublickey"] candidates.append( CandidateVotes(bytes.fromhex(producer), vote_amount)) ret = self.tx_manager.vote_producer( input_private_key=self.tap_private_key, amount=vote_amount, candidates=candidates, ) if not ret: return False self.wait_block() return True def vote_cr_candidates(self): candidates = list() amount = 0 p = len(self.cr_list) if len(self.cr_list) > 36: p = 36 for i in range(1, p): cr = self.cr_list[i]["cid"] vote_amount = i * 10 amount += vote_amount candidates.append( CandidateVotes(keytool.address_to_program_hash(cr), vote_amount)) ret = self.tx_manager.vote_cr( input_private_key=self.tap_account.private_key(), amount=amount, candidates=candidates, ) if not ret: return False self.wait_block() return True def check_result(self, case: str, result: bool):