class CRCProposalReview(Payload): APPROVE = 0x00 REJECT = 0x01 ABSTAIN = 0x02 def __init__(self, private_key: str, proposal_hash: bytes, vote_result: int, opinion_hash: bytes): Payload.__init__(self, self.DEFAULT_VERSION) self.account = Account(private_key) self.proposal_hash = proposal_hash self.vote_result = vote_result self.opinion_hash = opinion_hash self.did = bytes.fromhex(self.account.did()) self.sign = None self.gen_signature() self.serialize_data = None def data(self, version: int): if self.serialize_data is not None: return self.serialize_data r = b"" r = self.serialize(r, self.version) self.serialize_data = r return r def serialize(self, r: bytes, version: int): r = self.serialize_unsigned(r, version) r = serialize.write_var_bytes(r, self.sign) return r def serialize_unsigned(self, r: bytes, version=0): r += self.proposal_hash r += struct.pack("<B", self.vote_result) r += self.opinion_hash r += self.did return r def deserialize(self, r: bytes, version: int): pass def gen_signature(self): r = b"" r = self.serialize_unsigned(r, self.version) self.sign = keytool.ecdsa_sign(bytes.fromhex(self.account.private_key()), r) return r def __repr__(self): return "CRCProposalReview {" + "\n\t" \ + "privateKey: {}".format(self.account.private_key()) + "\n\t" \ + "proposalHash: {}".format(self.proposal_hash.hex()) + "\n\t" \ + "voteResult : {}".format(self.vote_result) + "\n\t" \ + "crOpinionHash: {}".format(self.opinion_hash.hex()) + "\n\t" \ + "did : {}".format(keytool.create_address(self.did)) + "\n\t" \ + "sign: {}".format(self.sign.hex()) + "\n\t" \ + "}"
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
class CRCProposalWithdraw(Payload): def __init__(self, private_key: str, proposal_hash: bytes): Payload.__init__(self, self.DEFAULT_VERSION) self.account = Account(private_key) self.proposal_hash = proposal_hash self.sponsor_public_key = bytes.fromhex(self.account.public_key()) self.sign = None self.gen_signature() self.serialize_data = None def data(self, version: int): if self.serialize_data is not None: return self.serialize_data r = b"" r = self.serialize(r, self.version) self.serialize_data = r return r def serialize(self, r: bytes, version: int): r = self.serialize_unsigned(r, version) r = serialize.write_var_bytes(r, self.sign) return r def serialize_unsigned(self, r: bytes, version=0): r += self.proposal_hash r = serialize.write_var_bytes(r, self.sponsor_public_key) return r def deserialize(self, r: bytes, version: int): pass def gen_signature(self): r = b"" r = self.serialize_unsigned(r, self.version) self.sign = keytool.ecdsa_sign( bytes.fromhex(self.account.private_key()), r) return r def __repr__(self): return "CRCProposalWithdraw {" + "\n\t" \ + "proposalHash: {}".format(self.proposal_hash.hex()) + "\n\t" \ + "sponsorPublicKey : {}".format(self.sponsor_public_key.hex()) + "\n\t" \ + "sign: {}".format(self.sign.hex()) + "\n\t" \ + "}"
class UnRegisterCR(Payload): def __init__(self, register_private_key: str): Payload.__init__(self, self.DEFAULT_VERSION) self.account = Account(register_private_key) self.cid = self.account.cid() self.signature = None self.gen_signature() self.serialize_data = None def gen_signature(self): r = b"" r = self.serialize_unsigned(r, self.version) signature = keytool.ecdsa_sign( bytes.fromhex(self.account.private_key()), r) self.signature = signature def data(self, version: int): r = b"" if self.serialize_data is not None: return self.serialize_data r = self.serialize(r, self.version) self.serialize_data = r return r def serialize(self, r: bytes, version: int): r = self.serialize_unsigned(r, self.version) if self.signature is not None: r = serialize.write_var_bytes(r, self.signature) return r def serialize_unsigned(self, r: bytes, version: int): r += bytes.fromhex(self.cid) return r def deserialize(self, r: bytes, version: int): pass
class CRCProposalTracking(Payload): COMMON = 0x00 PROGRESS = 0x01 REJECTED = 0x02 TERMINATED = 0x03 PROPOSAL_LEADER = 0x04 FINALIZED = 0x05 DEFAULT = 0x00 def __init__(self, secretary_private_key: str, leader_private_key: str, new_leader_private_key, tracking_type: int, proposal_hash: bytes, document_hash: bytes, stage: int, secretary_opinion_hash: bytes): Payload.__init__(self, self.DEFAULT_VERSION) self.secretary_general_account = Account(secretary_private_key) self.leader_account = Account(leader_private_key) self.new_leader_account = None self.proposal_hash = proposal_hash self.document_hash = document_hash self.stage = stage self.leader_public_key = bytes.fromhex( self.leader_account.public_key()) self.new_leader_public_key = None self.proposal_tracking_type = tracking_type self.secretary_opinion_hash = secretary_opinion_hash self.secretary_general_sign = None self.leader_sign = None self.new_leader_sign = None self._get_new_leader_account(new_leader_private_key) self.gen_signature() self.serialize_data = None def data(self, version: int): if self.serialize_data is not None: return self.serialize_data r = b"" r = self.serialize(r, self.version) self.serialize_data = r return r def serialize(self, r: bytes, version: int): r = self.serialize_unsigned(r, version) r = serialize.write_var_bytes(r, self.leader_sign) if self.new_leader_sign is not None: r = serialize.write_var_bytes(r, self.new_leader_sign) else: r += struct.pack("<B", CRCProposalTracking.DEFAULT) r += struct.pack("<B", self.proposal_tracking_type) r += self.secretary_opinion_hash r = serialize.write_var_bytes(r, self.secretary_general_sign) return r def serialize_unsigned(self, r: bytes, version=0): r += self.proposal_hash r += self.document_hash r += serialize.write_var_uint(self.stage) r = serialize.write_var_bytes(r, self.leader_public_key) if self.new_leader_public_key is not None: r = serialize.write_var_bytes(r, self.new_leader_public_key) else: r += struct.pack("<B", CRCProposalTracking.DEFAULT) return r def deserialize(self, r: bytes, version: int): pass def gen_signature(self): r = b"" r = self.serialize_unsigned(r, self.version) self.leader_sign = keytool.ecdsa_sign( bytes.fromhex(self.leader_account.private_key()), r) r = serialize.write_var_bytes(r, self.leader_sign) if self.new_leader_account is not None: self.new_leader_sign = keytool.ecdsa_sign( bytes.fromhex(self.new_leader_account.private_key()), r) r = serialize.write_var_bytes(r, self.new_leader_sign) else: self.new_leader_sign = None r += struct.pack("<B", CRCProposalTracking.DEFAULT) r += struct.pack("<B", self.proposal_tracking_type) r += self.secretary_opinion_hash self.secretary_general_sign = keytool.ecdsa_sign( bytes.fromhex(self.secretary_general_account.private_key()), r) return r def _get_new_leader_account(self, new_leader_private_key): if new_leader_private_key is not None: self.new_leader_account = Account(new_leader_private_key) self.new_leader_public_key = bytes.fromhex( self.new_leader_account.public_key()) def __repr__(self): return "CRCProposalTracking {" + "\n\t" \ + "SecretaryGeneralPrivateKey: {}".format(self.secretary_general_account.private_key()) + "\n\t" \ + "proposalTrackingType: {}".format(self.proposal_tracking_type) + "\n\t" \ + "proposalHash: {}".format(self.proposal_hash.hex()) + "\n\t" \ + "documentHash : {}".format(self.document_hash) + "\n\t" \ + "stage : {}".format(self.stage) + "\n\t" \ + "leaderPublicKey: {}".format(self.leader_public_key.hex()) + "\n\t" \ + "newLeaderPublicKey: {}".format(self.new_leader_public_key) + "\n\t" \ + "leaderSign: {}".format(self.leader_sign.hex()) + "\n\t" \ + "newLeaderSign: {}".format(self.new_leader_sign) + "\n\t" \ + "secretaryOpinionHash: {}".format(self.secretary_opinion_hash) + "\n\t" \ + "secretaryGeneralSign: {}".format(self.secretary_general_sign.hex()) + "\n\t" \ + "}"
def _create_keystore(self, category: str, num: int): keystore_saved_dir = os.path.join(self.key_message_saved_dir, category) if not os.path.exists(keystore_saved_dir): os.makedirs(keystore_saved_dir) for i in range(num): if i == 0: first_time = True else: first_time = False if category == "arbiter": a = Account(self.node_accounts[i].private_key()) else: a = Account() Logger.debug("{} {}_{} private key: {}".format( self.tag, category, i, a.private_key())) k = Keystore(a, self.password) self.category_dict[category].append(a) if category == "arbiter": sub1 = Account() k.add_sub_account(sub1) self.sub1_accounts.append(sub1) util.save_to_json( sub1, "sub1_" + str(i), os.path.join(self.key_message_saved_dir, "sub1.json"), first_time) sub2 = Account() k.add_sub_account(sub2) self.sub2_accounts.append(sub2) util.save_to_json( sub2, "sub2_" + str(i), os.path.join(self.key_message_saved_dir, "sub2.json"), first_time) sub3 = Account() k.add_sub_account(sub3) self.sub3_accounts.append(sub3) util.save_to_json( sub3, "sub3_" + str(i), os.path.join(self.key_message_saved_dir, "sub3.json"), first_time) sub4 = Account() k.add_sub_account(sub4) self.sub3_accounts.append(sub4) util.save_to_json( sub4, "sub4_" + str(i), os.path.join(self.key_message_saved_dir, "sub4.json"), first_time) util.save_to_json( a, category + "_" + str(i), os.path.join(self.key_message_saved_dir, category + ".json"), first_time) util.save_to_dat( k.key_store_dict(), os.path.join(keystore_saved_dir, category + str(i) + ".dat")) Logger.debug("{} create {} keystores on success!".format( self.tag, category))
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 CRCProposal(Payload): NORMAL = 0x0000 ELIP = 0x0100 FLOW_ELIP = 0x0101 INFO_ELIP = 0x0102 MAIN_CHAIN_UPGRADE_CODE = 0x0200 SIDE_CHAIN_UPGRADE_CODE = 0x0300 REGISTER_SIDE_CHAIN = 0x0301 SECRETARY_GENERAL = 0x0400 CHANGE_SPONSOR_OWNER = 0x0401 CLOSE_PROPOSAL = 0x0402 DAPP_CONSENSUS = 0x0500 WRONG = 0x4321 def __init__(self, private_key: str, cr_private_key: str, proposal_type: int, category_data: str, draft_hash: bytes, budget=None, recipient=None, target_proposal_hash=None, new_recipient=None, secretary_general_private_key=None, new_owner_private_key=None): Payload.__init__(self, self.DEFAULT_VERSION) self.account = Account(private_key) self.cr_account = Account(cr_private_key) self.secretary_general_account = None self.new_owner_account = None self.proposal_type = proposal_type self.category_data = category_data self.draft_hash = draft_hash self.target_proposal_hash = target_proposal_hash self.new_owner_public_key = None self.budget = budget self.recipient = recipient self.new_recipient = None self.secretary_general_public_key = None self.secretary_general_did = None self.sign = None self.new_owner_signature = None self.secretary_general_signature = None self._gen_secretary_general_account(secretary_general_private_key) self._gen_new_owner_account(new_owner_private_key) self.cr_council_member_did = bytes.fromhex(self.cr_account.did()) self.cr_council_member_sign = None self._gen_signature() self.hash = self.gen_hash() self.serialize_data = None def data(self, version: int): if self.serialize_data is not None: return self.serialize_data r = b"" r = self.serialize(r, self.version) self.serialize_data = r return r def serialize(self, r: bytes, version: int): if self.proposal_type is self.SECRETARY_GENERAL: return self.serialize_secretary_general(r, version) elif self.proposal_type is self.CHANGE_SPONSOR_OWNER: return self.serialize_change_proposal_owner(r, version) elif self.proposal_type is self.CLOSE_PROPOSAL: return self.serialize_close_proposal(r, version) else: return self.serialize_normal_or_elip(r, version) def serialize_normal_or_elip(self, r: bytes, version: int): r = self.serialize_unsigned_normal_or_elip(r, version) r = serialize.write_var_bytes(r, self.sign) r += self.cr_council_member_did r = serialize.write_var_bytes(r, self.cr_council_member_sign) return r def serialize_secretary_general(self, r: bytes, version: int): r = self.serialize_unsigned_secretary_genera(r, version) r = serialize.write_var_bytes(r, self.sign) r = serialize.write_var_bytes(r, self.secretary_general_signature) r += self.cr_council_member_did r = serialize.write_var_bytes(r, self.cr_council_member_sign) return r def serialize_change_proposal_owner(self, r: bytes, version: int): r = self.serialize_unsigned_change_proposal_owner(r, version) r = serialize.write_var_bytes(r, self.sign) r = serialize.write_var_bytes(r, self.new_owner_signature) r += self.cr_council_member_did r = serialize.write_var_bytes(r, self.cr_council_member_sign) return r def serialize_close_proposal(self, r: bytes, version: int): r = self.serialize_unsigned_close_proposal(r, version) r = serialize.write_var_bytes(r, self.sign) r += self.cr_council_member_did r = serialize.write_var_bytes(r, self.cr_council_member_sign) return r def serialize_unsigned_normal_or_elip(self, r: bytes, version=0): r += struct.pack("<H", self.proposal_type) r = serialize.write_var_bytes(r, bytes(self.category_data.encode())) r = serialize.write_var_bytes(r, bytes.fromhex(self.account.public_key())) r += self.draft_hash r += serialize.write_var_uint(len(self.budget)) for budget in self.budget: r += budget.serialize(version) r += self.recipient return r def serialize_unsigned_secretary_genera(self, r: bytes, version=0): r += struct.pack("<H", self.proposal_type) r = serialize.write_var_bytes(r, bytes(self.category_data.encode())) r = serialize.write_var_bytes(r, bytes.fromhex(self.account.public_key())) r += self.draft_hash r = serialize.write_var_bytes(r, self.secretary_general_public_key) r += self.secretary_general_did return r def serialize_unsigned_change_proposal_owner(self, r: bytes, version=0): r += struct.pack("<H", self.proposal_type) r = serialize.write_var_bytes(r, bytes(self.category_data.encode())) r = serialize.write_var_bytes(r, bytes.fromhex(self.account.public_key())) r += self.draft_hash r += self.target_proposal_hash r += self.new_recipient r = serialize.write_var_bytes(r, self.new_owner_public_key) return r def serialize_unsigned_close_proposal(self, r: bytes, version=0): r += struct.pack("<H", self.proposal_type) r = serialize.write_var_bytes(r, bytes(self.category_data.encode())) r = serialize.write_var_bytes(r, bytes.fromhex(self.account.public_key())) r += self.draft_hash r += self.target_proposal_hash return r def deserialize(self, r: bytes, version: int): pass def _gen_secretary_general_account(self, private_key): if private_key is not None: self.secretary_general_account = Account(private_key) self.secretary_general_public_key = bytes.fromhex(self.secretary_general_account.public_key()) self.secretary_general_did = bytes.fromhex(self.secretary_general_account.did()) def _gen_new_owner_account(self, private_key): if private_key is not None: self.new_owner_account = Account(private_key) self.new_owner_public_key = bytes.fromhex(self.new_owner_account.public_key()) self.new_recipient = bytes.fromhex(self.new_owner_account.did()) def get_deposit_address(self): return self.account.deposit_address() def _gen_signature(self): r = b"" if self.proposal_type is self.SECRETARY_GENERAL: r = self.serialize_unsigned_secretary_genera(r, self.version) self.sign = keytool.ecdsa_sign(bytes.fromhex(self.account.private_key()), r) self.secretary_general_signature = keytool.ecdsa_sign( bytes.fromhex(self.secretary_general_account.private_key()), r) r = serialize.write_var_bytes(r, self.sign) r = serialize.write_var_bytes(r, self.secretary_general_signature) r += self.cr_council_member_did self.cr_council_member_sign = keytool.ecdsa_sign(bytes.fromhex(self.cr_account.private_key()), r) return r elif self.proposal_type is self.CHANGE_SPONSOR_OWNER: r = self.serialize_unsigned_change_proposal_owner(r, self.version) self.sign = keytool.ecdsa_sign(bytes.fromhex(self.account.private_key()), r) self.new_owner_signature = keytool.ecdsa_sign(bytes.fromhex(self.new_owner_account.private_key()), r) r = serialize.write_var_bytes(r, self.sign) r = serialize.write_var_bytes(r, self.new_owner_signature) r += self.cr_council_member_did self.cr_council_member_sign = keytool.ecdsa_sign(bytes.fromhex(self.cr_account.private_key()), r) return r elif self.proposal_type is self.CLOSE_PROPOSAL: r = self.serialize_unsigned_close_proposal(r, self.version) self.sign = keytool.ecdsa_sign(bytes.fromhex(self.account.private_key()), r) r = serialize.write_var_bytes(r, self.sign) r += self.cr_council_member_did self.cr_council_member_sign = keytool.ecdsa_sign(bytes.fromhex(self.cr_account.private_key()), r) return r else: r = self.serialize_unsigned_normal_or_elip(r, self.version) self.sign = keytool.ecdsa_sign(bytes.fromhex(self.account.private_key()), r) r = serialize.write_var_bytes(r, self.sign) r += self.cr_council_member_did self.cr_council_member_sign = keytool.ecdsa_sign(bytes.fromhex(self.cr_account.private_key()), r) return r def gen_hash(self): r = b"" r = self.serialize(r, 0) return keytool.sha256_hash(r, 2) def __repr__(self): if self.proposal_type is self.SECRETARY_GENERAL: return "CRCProposalSecretaryGeneral {" + "\n\t" \ + "privateKey: {}".format(self.proposal_type) + "\n\t" \ + "crCouncilMemberDid: {}".format(self.proposal_type) + "\n\t" \ + "proposalType: {}".format(self.proposal_type) + "\n\t" \ + "categoryData : {}".format(self.category_data) + "\n\t" \ + "sponsorPublicKey : {}".format(self.account.public_key()) + "\n\t" \ + "draftHash: {}".format(self.draft_hash.hex()) + "\n\t" \ + "secretaryGeneralPublicKey: {}".format(self.secretary_general_public_key.hex()) + "\n\t" \ + "secretaryGeneralDid: {}".format(keytool.create_address(self.secretary_general_did)) + "\n\t" \ + "sign: {}".format(self.sign.hex()) + "\n\t" \ + "secretaryGeneralSignature: {}".format(self.secretary_general_signature.hex()) + "\n\t" \ + "crCouncilMemberDid: {}".format(keytool.create_address(self.cr_council_member_did)) + "\n\t" \ + "crCouncilMemberSign: {}".format(self.cr_council_member_sign.hex()) + "\n\t" \ + "hash: {}".format(self.hash.hex()) + "\n\t" \ + "}" elif self.proposal_type is self.CHANGE_SPONSOR_OWNER: return "CRCProposalChangeSponsor {" + "\n\t" \ + "proposalType: {}".format(self.proposal_type) + "\n\t" \ + "categoryData : {}".format(self.category_data) + "\n\t" \ + "sponsorPublicKey : {}".format(self.account.public_key()) + "\n\t" \ + "draftHash: {}".format(self.draft_hash.hex()) + "\n\t" \ + "targetProposalHash: {}".format(self.target_proposal_hash.hex()) + "\n\t" \ + "newRecipient: {}".format(keytool.create_address(self.new_recipient)) + "\n\t" \ + "newOwnerPublicKey: {}".format(self.new_owner_public_key.hex()) + "\n\t" \ + "sign: {}".format(self.sign.hex()) + "\n\t" \ + "crCouncilMemberDid: {}".format(keytool.create_address(self.cr_council_member_did)) + "\n\t" \ + "crCouncilMemberSign: {}".format(self.cr_council_member_sign.hex()) + "\n\t" \ + "hash: {}".format(self.hash.hex()) + "\n\t" \ + "}" elif self.proposal_type is self.CLOSE_PROPOSAL: return "CRCProposalCloseProposal {" + "\n\t" \ + "proposalType: {}".format(self.proposal_type) + "\n\t" \ + "categoryData : {}".format(self.category_data) + "\n\t" \ + "sponsorPublicKey : {}".format(self.account.public_key()) + "\n\t" \ + "draftHash: {}".format(self.draft_hash.hex()) + "\n\t" \ + "targetProposalHash: {}".format(self.target_proposal_hash.hex) + "\n\t" \ + "sign: {}".format(self.sign.hex()) + "\n\t" \ + "crCouncilMemberDid: {}".format(keytool.create_address(self.cr_council_member_did)) + "\n\t" \ + "crCouncilMemberSign: {}".format(self.cr_council_member_sign.hex()) + "\n\t" \ + "hash: {}".format(self.hash.hex()) + "\n\t" \ + "}" else: return "CRCProposal {" + "\n\t" \ + "proposalType: {}".format(self.proposal_type) + "\n\t" \ + "categoryData : {}".format(self.category_data) + "\n\t" \ + "sponsorPublicKey : {}".format(self.account.public_key()) + "\n\t" \ + "draftHash: {}".format(self.draft_hash.hex()) + "\n\t" \ + "budgets: {}".format(self.budget) + "\n\t" \ + "recipient: {}".format(keytool.create_address(self.recipient)) + "\n\t" \ + "sign: {}".format(self.sign.hex()) + "\n\t" \ + "crCouncilMemberDid: {}".format(keytool.create_address(self.cr_council_member_did)) + "\n\t" \ + "crCouncilMemberSign: {}".format(self.cr_council_member_sign.hex()) + "\n\t" \ + "hash: {}".format(self.hash.hex()) + "\n\t" \ + "}"
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):
class CRInfo(Payload): CR_INFO_VERSION = 0x00 CR_INFO_DID_VERSION = 0x01 def __init__(self, private_key: str, nickname: str, url: str, location: int): Payload.__init__(self, self.DEFAULT_VERSION) self.account = Account(private_key) self.nickname = nickname self.url = url self.location = location self.code = self.account.redeem_script() self.cid = self.account.cid() self.did = self.account.did() self.signature = None self.gen_signature() self.serialize_data = None def data(self, version: int): if self.serialize_data is not None: return self.serialize_data r = b"" r = self.serialize(r, self.version) self.serialize_data = r return r def serialize(self, r: bytes, version: int): r = self.serialize_unsigned(r, version) if self.signature is not None: r = serialize.write_var_bytes(r, self.signature) return r def serialize_unsigned(self, r: bytes, version=0): r = serialize.write_var_bytes(r, bytes.fromhex(self.code)) r += bytes.fromhex(self.cid) r += bytes.fromhex(self.did) r = serialize.write_var_bytes(r, bytes(self.nickname.encode())) r = serialize.write_var_bytes(r, bytes(self.url.encode())) r += struct.pack("<Q", self.location) return r def deserialize(self, r: bytes, version: int): pass def get_deposit_address(self): return self.account.deposit_address() def gen_signature(self): r = b"" r = self.serialize_unsigned(r, self.version) signature = keytool.ecdsa_sign( bytes.fromhex(self.account.private_key()), r) self.signature = signature return signature def __repr__(self): return "CRInfo {" + "\n\t" \ + "privateKey: {}".format(self.account.private_key()) + "\n\t" \ + "code: {}".format(self.code) + "\n\t" \ + "cid : {}".format(keytool.create_address(bytes.fromhex(self.cid))) + "\n\t" \ + "did : {}".format(keytool.create_address(bytes.fromhex(self.did))) + "\n\t" \ + "nickname: {}".format(self.nickname) + "\n\t" \ + "url: {}".format(self.url) + "\n\t" \ + "location: {}".format(self.location) + "\n\t" \ + "signature: {}".format(self.signature.hex()) + "\n" \ + "}"