def validate(self): if self.version != 0: Logger.error("invalid vote version") return False type_list = list() for content in self.contents: if content.vote_type in type_list: Logger.error("{} duplicate vote type") return False type_list.append(content.vote_type) if content.vote_type != VoteContent.TYPE_DELEGATE: Logger.error("{} invalid vote type") if len(content.candidates) == 0 or len(content.candidates) > 36: Logger.error("{} invalid vote candidates") return False candidates_list = list() for candidate in content.candidates: if candidate in candidates_list: Logger.error("{} duplicate candidate") return False candidates_list.append(candidate) return True
def _check_password(self): ret = keytool.sha256_hash(str.encode(self._password), 3).hex() == self._get_password_hash() if not ret: Logger.error("Invalid password!") return ret
def add_sub_account(self, sub_account: Account): if not self._valid: Logger.error("Invalid keystore!") return self._sub_accounts_list.append(sub_account) sub_account_data = self._create_account_data(sub_account, self.SUB_ACCOUNT) self._accounts_data_list.append(sub_account_data)
def arbiter_public_keys(key_stores): public_keys = [] if len(key_stores) != 5: Logger.error( "[common] Invalid argument, the length of the argument must be equal 5" ) exit(0) for key_store in key_stores: public_keys.append(key_store.public_key.hex()) return public_keys
def _producer_info(self, owner_private_key: str, node_private_key: str, nick_name: str, url: str, location: int, net_address: str): info = ProducerInfo(owner_private_key=owner_private_key, node_private_key=node_private_key, nickname=nick_name, url=url, location=location, net_address=net_address) Logger.debug("generate register producer{} payload".format(nick_name)) return info
def serialize(self, version: int): if self.candidates is None or len(self.candidates) == 0: Logger.error("candidates list is empty!") return None r = b"" r += struct.pack("<B", self.vote_type) r += serialize.write_var_uint(len(self.candidates)) for candidate in self.candidates: r = serialize.write_var_bytes(r, candidate) return r
def _get_master_key(self): password_twice_hash = keytool.sha256_hash(str.encode(self._password), 2) encrypt_master_key = self._get_master_key_encrypted() if encrypt_master_key is None: Logger.error("encrypt master key is None") return None master_key = keytool.aes_decrypt(bytes.fromhex(encrypt_master_key), password_twice_hash, self._iv) return master_key
def serialize(self): if self.contents is None or len(self.contents) == 0: Logger.error("contents is invalid") return None r = b"" r += struct.pack("<B", self.version) r += serialize.write_var_uint(len(self.contents)) for content in self.contents: r += content.serialize(self.version) return r
def key_store_dict(self): if not self._valid: Logger.error("Invalid keystore!") return None store_dict = { "Version": "1.0.0", "PasswordHash": self._password_thrice_hash.hex(), "IV": self._iv.hex(), "MasterKey": self._master_key_encrypted.hex(), "Account": self._accounts_data_list } return store_dict
def create_normal_inputs(address: str, total_amount: int, rpc_port: int): global total_amount_global global response total_amount_global = total_amount total_amount_format = str( Decimal(str(total_amount_global)) / Decimal(util.TO_SELA)) if rpc_port != rpc.DEFAULT_PORT: response = rpc.list_unspent_utxos(address, port=rpc_port) else: response = rpc.get_utxos_by_amount(address, total_amount_format, rpc_port) if not response or isinstance(response, dict): Logger.error("get utxos return error: {}".format(response)) return None, None utxos = response # Logger.debug("utxos: {}".format(utxos)) inputs = list() change_outputs = list() program_hash = keytool.address_to_program_hash(address) for utxo in utxos: txid = util.bytes_reverse(bytes.fromhex(utxo["txid"])) index = utxo["vout"] input = Input(txid, index) inputs.append(input) amount = int(Decimal(utxo["amount"]) * util.TO_SELA) if amount < total_amount_global: total_amount -= amount elif amount == total_amount: total_amount_global = 0 break elif amount > total_amount: change = Output(value=amount - total_amount_global, output_lock=0, program_hash=program_hash, output_type=Output.OT_NONE, output_payload=OutputPayload()) change_outputs.append(change) total_amount_global = 0 break if total_amount_global > 0: Logger.error("Available token is not enough!") return None, None return inputs, change_outputs
def create_cross_chain_asset(input_private_key: str, lock_address: str, cross_chain_address: str, amount: int, recharge: bool, rpc_port: int): 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(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) 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 - util.TX_FEE] 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
def save_to_file(self, dest_dir_path: str): if not self._valid: Logger.error("Invalid keystore!") return False if dest_dir_path is "": Logger.debug("Invalid parameter!") return False if not os.path.exists(dest_dir_path): os.makedirs(dest_dir_path) file_path = os.path.join(dest_dir_path, "keystore.dat") util.write_config_file(self.key_store_dict(), file_path) return True
def serialize(self, r: bytes, version: int): if len(self.cross_chain_addresses) != len(self.output_indexes) or \ len(self.cross_chain_addresses) != len(self.cross_chain_addresses): Logger.error("Invalid cross chain asset") return None r += serialize.write_var_uint(len(self.cross_chain_addresses)) for i in range(len(self.cross_chain_addresses)): r = serialize.write_var_bytes( r, bytes(self.cross_chain_addresses[i].encode())) r += serialize.write_var_uint(self.output_indexes[i]) r += struct.pack("<q", self.cross_chain_amounts[i]) return r
def _get_account(self, index): encrypt_private_key = self._accounts_data_list[index][ "PrivateKeyEncrypted"] if encrypt_private_key is None: Logger.error("encrypt private key is None") return None encrypt_private_key_bytes = bytes.fromhex(encrypt_private_key) if len(encrypt_private_key_bytes) != 96: Logger.error("encrypt private key length is not 96") return None private_key = keytool.aes_decrypt(encrypt_private_key_bytes, self._master_key, self._iv)[64:96] account = Account(private_key.hex()) return account
def create_transaction(input_private_key: str, output_addresses: list, amount: int, rpc_port: int): 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() 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 create_redeem_transaction(payload: ProducerInfo, output_address: str, amount: int, rpc_port: int): # create outputs outputs, total_amount = create_normal_outputs( output_addresses=[output_address], amount=amount, fee=util.TX_FEE, output_lock=0) # create inputs deposit_address = payload.get_deposit_address() inputs, change_outputs = create_normal_inputs(deposit_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(payload.owner_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.RETURN_DEPOSIT_CHAIN tx.payload_version = 0 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_register_transaction(input_private_key: str, amount: int, payload: ProducerInfo, rpc_port: int): # create outputs outputs, total_amount = create_normal_outputs( output_addresses=[payload.get_deposit_address()], amount=amount, fee=util.TX_FEE, output_lock=0) # create inputs account = Account(input_private_key) 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.REGISTER_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_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 serialize_unsigned(self): # version r = b"" if self.version >= self.TX_VERSION_09: r += struct.pack(">B", self.version) # tx type r += struct.pack(">B", self.tx_type) # payload version r += struct.pack(">B", self.payload_version) # payload if self.payload is None: Logger.error("Transaction payload is None") return None if self.payload.data(self.payload_version) is not None: r += self.payload.data(self.payload_version) # attributes if self.attributes is not None: r += serialize.write_var_uint(len(self.attributes)) for attribute in self.attributes: r += attribute.serialize() # inputs if self.inputs is not None: r += serialize.write_var_uint(len(self.inputs)) for input in self.inputs: r += input.serialize() # outputs if self.outputs is not None: r += serialize.write_var_uint(len(self.outputs)) for output in self.outputs: r += output.serialize(self.version) # lock_time r += struct.pack("<I", self.lock_time) return r
def _get_iv(self): if "IV" not in self._store_dict.keys(): Logger.error("keystore_dat dose not contain key IV") return None return self._store_dict["IV"]
def _get_accounts_data(self, ): if "Account" not in self._store_dict.keys(): Logger.error("keystore_dat dose not contain key Account") return None return self._store_dict["Account"]
def main_account(self): if not self._valid: Logger.error("Invalid keystore!") return None return self._main_account
def sub_accounts(self): if not self._valid: Logger.error("Invalid keystore!") return None return self._sub_accounts_list
def password(self): if not self._valid: Logger.error("Invalid keystore!") return "" return self._password
def _get_master_key_encrypted(self): if "MasterKey" not in self._store_dict.keys(): Logger.error("keystore_dat dose not contain key MasterKey") return None return self._store_dict["MasterKey"]
def _get_password_hash(self): if "PasswordHash" not in self._store_dict.keys(): Logger.error("keystore_dat dose not contain key PasswordHash") return None return self._store_dict["PasswordHash"]
def export_private_key(self): if not self._valid: Logger.error("Invalid keystore!") return None return self.main_account().private_key()
def __repr__(self): if not self._valid: Logger.error("Invalid keystore!") return "" return json.dumps(self.key_store_dict(), indent=4)