def register_candidate(self, account: Account, peer_pubkey: str, init_pos: int, identity: Identity, password: str, key_no: int, payer: Account, gas_limit: int, gas_price: int): contract_address = bytearray.fromhex(self.CONTRACT_ADDRESS) param = { "peer_pubkey": peer_pubkey, "address": account.get_address().to_array(), "init_pos": init_pos, "ontid": identity.ont_id.encode(), "key_no": key_no } invoke_code = build_native_invoke_code(contract_address, bytes([0]), "registerCandidate", param) unix_time_now = int(time()) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer.get_address().to_array(), invoke_code, bytearray(), [], bytearray()) self.__sdk.sign_transaction(tx, account) ontid_acc = self.__sdk.wallet_manager.get_account( identity.ont_id, password) self.__sdk.add_sign_transaction(tx, ontid_acc) if account.get_address_base58() is not payer: self.__sdk.add_sign_transaction(tx, payer) res = self.__sdk.rpc.send_raw_transaction(tx) return tx.hash256_explorer()
def add_multi_sign_transaction(self, tx: Transaction, m: int, pubkeys: [], signer: Account): pubkeys = ProgramBuilder.sort_publickeys(pubkeys) tx_hash = tx.hash256_bytes() sig_data = signer.generate_signature(tx_hash, signer.get_signature_scheme()) if tx.sigs is None or len(tx.sigs) == 0: tx.sigs = [] elif len(tx.sigs) >= Common.TX_MAX_SIG_SIZE: raise SDKException( ErrorCode.param_err( 'the number of transaction signatures should not be over 16' )) else: for i in range(len(tx.sigs)): if tx.sigs[i].public_keys == pubkeys: if len(tx.sigs[i].sig_data) + 1 > len(pubkeys): raise SDKException( ErrorCode.param_err('too more sigData')) if tx.sigs[i].M != m: raise SDKException(ErrorCode.param_err('M error')) tx.sigs[i].sig_data.append(sig_data) return tx sig = Sig(pubkeys, m, [sig_data]) tx.sigs.append(sig) return tx
def withdraw(self, account: Account, peer_publickeys: list, withdraw_list: list, payer: Account, gas_limit: int, gas_price: int): contract_address = bytearray.fromhex(self.CONTRACT_ADDRESS) if len(peer_publickeys) != len(withdraw_list): raise Exception( "the length of peer_publickeys should equal the length of pos_lists" ) param = { "address": account.get_address().to_array(), "publickeys_length": len(peer_publickeys) } for i in range(len(peer_publickeys)): param["publickey" + str(i)] = peer_publickeys[i] param["pos_lists_length"] = len(withdraw_list) for i in range(len(withdraw_list)): param["pos_lists" + str(i)] = withdraw_list[i] invoke_code = build_native_invoke_code(contract_address, bytes([0]), "withdraw", param) unix_time_now = int(time()) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer.get_address().to_array(), invoke_code, bytearray(), [], bytearray()) self.__sdk.sign_transaction(tx, account) if payer is not None and account.get_address_base58( ) is not payer.get_address_base58(): self.__sdk.add_sign_transaction(tx, payer) self.__sdk.rpc.send_raw_transaction(tx) return tx.hash256_explorer()
def sign_transaction(self, tx: Transaction, signer: Account): tx_hash = tx.hash256() sig_data = signer.generate_signature(tx_hash, signer.get_signature_scheme()) sig = [Sig([signer.get_public_key()], 1, [sig_data])] tx.sigs = sig return tx
def add_multi_sign_transaction(tx: Transaction, m: int, pub_keys: list, signer: Account): """ This interface is used to generate an Transaction object which has multi signature. :param tx: a Transaction object which will be signed. :param m: the amount of signer. :param pub_keys: a list of public keys. :param signer: an Account object which will sign the transaction. :return: a Transaction object which has been signed. """ pub_keys = ProgramBuilder.sort_publickeys(pub_keys) tx_hash = tx.hash256_bytes() sig_data = signer.generate_signature(tx_hash, signer.get_signature_scheme()) if tx.sigs is None or len(tx.sigs) == 0: tx.sigs = [] elif len(tx.sigs) >= Common.TX_MAX_SIG_SIZE: raise SDKException( ErrorCode.param_err( 'the number of transaction signatures should not be over 16' )) else: for i in range(len(tx.sigs)): if tx.sigs[i].public_keys == pub_keys: if len(tx.sigs[i].sig_data) + 1 > len(pub_keys): raise SDKException( ErrorCode.param_err('too more sigData')) if tx.sigs[i].M != m: raise SDKException(ErrorCode.param_err('M error')) tx.sigs[i].sig_data.append(sig_data) return tx sig = Sig(pub_keys, m, [sig_data]) tx.sigs.append(sig) return tx
def change_max_authorization(self, account: Account, peer_publickey: str, max_authorize: int, payer: Account, gas_limit: int, gas_price: int): contract_address = bytearray.fromhex(self.CONTRACT_ADDRESS) param = {"peer_publickey": peer_publickey, "address": account.get_address().to_array(), "maxAuthorize": max_authorize} invoke_code = build_native_invoke_code(contract_address, bytes([0]), "changeMaxAuthorization", param) unix_time_now = int(time()) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer.get_address().to_array(), invoke_code, bytearray(), [], bytearray()) self.__sdk.sign_transaction(tx, account) if payer is not None and account.get_address_base58() is not payer.get_address_base58(): self.__sdk.add_sign_transaction(tx, payer) self.__sdk.rpc.send_raw_transaction(tx) return tx.hash256_explorer()
def withdraw_fee(self, account: Account, payer: Account, gas_limit: int, gas_price: int): contract_address = bytearray.fromhex(self.CONTRACT_ADDRESS) param = {"address": account.get_address().to_array()} invoke_code = build_native_invoke_code(contract_address, bytes([0]), "withdrawFee", param) unix_time_now = int(time()) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer.get_address().to_array(), invoke_code, bytearray(), [], bytearray()) self.__sdk.sign_transaction(tx, account) if payer is not None and account.get_address_base58() is not payer.get_address_base58(): self.__sdk.add_sign_transaction(tx, payer) self.__sdk.rpc.send_raw_transaction(tx) return tx.hash256_explorer()
def add_sign_transaction(self, tx: Transaction, signer: Account): if tx.sigs == None or len(tx.sigs) == 0: tx.sigs = [] elif len(tx.sigs) >= Common.TX_MAX_SIG_SIZE: raise Exception( "the number of transaction signatures should not be over 16") tx_hash = tx.hash256() sig_data = signer.generate_signature(tx_hash, signer.get_signature_scheme()) sig = Sig([signer.serialize_public_key()], 1, [sig_data]) tx.sigs.append(sig) return tx
def transfer_multi(self, transfer_list: list, payer_acct: Account, signers: list, gas_limit: int, gas_price: int): """ This interface is used to call the TransferMulti method in ope4 that allow transfer amount of token from multiple from-account to multiple to-account multiple times. :param transfer_list: a parameter list with each item contains three sub-items: base58 encode transaction sender address, base58 encode transaction receiver address, amount of token in transaction. :param payer_acct: an Account class that used to pay for the transaction. :param signers: a signer list used to sign this transaction which should contained all sender in args. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: the hexadecimal transaction hash value. """ func = InvokeFunction('transferMulti') for index, item in enumerate(transfer_list): Oep4.__b58_address_check(item[0]) Oep4.__b58_address_check(item[1]) if not isinstance(item[2], int): raise SDKException( ErrorCode.param_err( 'the data type of value should be int.')) if item[2] < 0: raise SDKException( ErrorCode.param_err( 'the value should be equal or great than 0.')) from_address_array = Address.b58decode(item[0]).to_bytes() to_address_array = Address.b58decode(item[1]).to_bytes() transfer_list[index] = [ from_address_array, to_address_array, item[2] ] for item in transfer_list: func.add_params_value(item) params = func.create_invoke_code() unix_time_now = int(time.time()) params.append(0x67) bytearray_contract_address = bytearray.fromhex( self.__hex_contract_address) bytearray_contract_address.reverse() for i in bytearray_contract_address: params.append(i) if len(signers) == 0: raise SDKException(ErrorCode.param_err('payer account is None.')) payer_address = payer_acct.get_address().to_bytes() tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer_address, params, bytearray(), []) for signer in signers: tx.add_sign_transaction(signer) tx_hash = self.__sdk.get_network().send_raw_transaction(tx) return tx_hash
def delegate(self, identity: Identity, password: str, key_no: int, contract_address: str, to_ont_id: str, role: str, period: int, level: int, payer: Account, gas_limit: int, gas_price: int): contract_address = bytearray.fromhex(contract_address) param = { "contract_address": contract_address, "ont_id": identity.ont_id.encode('utf-8'), "to_ont_id": to_ont_id.encode('utf-8'), "role": role.encode('utf-8'), "period": period, "level": level, "key_no": key_no } invoke_code = build_native_invoke_code( bytearray.fromhex(self.contract_address), bytes([0]), "delegate", param) unix_time_now = int(time()) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer.get_address().to_array(), invoke_code, bytearray(), [], bytearray()) account = self.__sdk.wallet_manager.get_account( identity.ont_id, password) self.__sdk.sign_transaction(tx, account) self.__sdk.add_sign_transaction(tx, payer) res = self.__sdk.rpc.send_raw_transaction(tx) return res
def send_raw_transaction_pre_exec(self, tx: Transaction): """ This interface is used to send the transaction that is prepare to execute. Args: tx (Transaction): Transaction object in ontology Python SDK. Return: the execution result of transaction that is prepare to execute. """ buf = tx.serialize() tx_data = buf.hex() payload = RpcClient.set_json_rpc_version(RPC_SEND_TRANSACTION, [tx_data, 1]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException(ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException(ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) res = json.loads(response.content.decode()) err = res["error"] if err > 0: try: result = res['result'] raise RuntimeError(result) except KeyError: raise RuntimeError('send raw transaction pre-execute error') if res["result"]["State"] == 0: raise RuntimeError("State = 0") return res["result"]["Result"]
def send_raw_transaction(self, tx: Transaction) -> str: """ This interface is used to send the transaction into the network. Args: tx (Transaction): Transaction object in ontology Python SDK. Return: a hexadecimal transaction hash value. """ buf = tx.serialize() tx_data = buf.hex() payload = RpcClient.set_json_rpc_version(RPC_SEND_TRANSACTION, [tx_data]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException(ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException(ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) data = json.loads(response.content.decode()) res = data["result"] if data["error"] != 0: raise SDKException(ErrorCode.other_error(res)) return res
def new_add_attribute_transaction(ont_id: str, hex_public_key: str, attribute_list: list, b58_payer_address: str, gas_limit: int, gas_price: int): """ This interface is used to generate a Transaction object which is used to add attribute. :param ont_id: ontid. :param hex_public_key: the hexadecimal public key in the form of string. :param attribute_list: a list of attributes we want to add. :param b58_payer_address: a base58 encode address which indicate who will pay for the transaction. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: a Transaction object which is used to add attribute. """ contract_address = ONTID_CONTRACT_ADDRESS args = {"ontid": ont_id.encode(), "length": len(attribute_list)} for i in range(len(attribute_list)): args["key" + str(i)] = bytes(attribute_list[i]["key"].encode()) args["type" + str(i)] = bytes(attribute_list[i]["type"].encode()) args["value" + str(i)] = bytes(attribute_list[i]["value"].encode()) args["pubkey"] = bytearray.fromhex(hex_public_key) invoke_code = build_vm.build_native_invoke_code( contract_address, bytes([0]), "addAttributes", args) unix_time_now = int(time()) array_payer_address = Address.b58decode(b58_payer_address).to_array() tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, array_payer_address, invoke_code, bytearray(), [], bytearray()) return tx
def new_add_recovery_transaction(ont_id: str, hex_public_key: str, b58_recovery_address: str, b58_payer_address: str, gas_limit: int, gas_price: int): """ This interface is used to generate a Transaction object which is used to add the recovery. :param ont_id: ontid. :param hex_public_key: the hexadecimal public key in the form of string. :param b58_recovery_address: a base58 encode address which indicate who is the recovery. :param b58_payer_address: a base58 encode address which indicate who will pay for the transaction. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: """ contract_address = ONTID_CONTRACT_ADDRESS bytes_recovery_address = Address.b58decode( b58_recovery_address).to_array() bytearray_public_key = bytearray.fromhex(hex_public_key) args = { "ontid": ont_id.encode(), "recovery": bytes_recovery_address, "pubkey": bytearray_public_key } invoke_code = build_vm.build_native_invoke_code( contract_address, bytes([0]), "addRecovery", args) unix_time_now = int(time()) bytes_payer_address = Address.b58decode(b58_payer_address).to_array() tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, bytes_payer_address, invoke_code, bytearray(), [], bytearray()) return tx
def new_add_public_key_transaction(ont_id: str, hex_public_key_or_recovery: str, hex_new_public_key: str, payer: str, gas_limit: int, gas_price: int): """ This interface is used to send a Transaction object which is used to add public key. :param ont_id: ontid. :param hex_public_key_or_recovery: the old hexadecimal public key in the form of string. :param hex_new_public_key: the new hexadecimal public key in the form of string. :param payer: an Account object which indicate who will pay for the transaction. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: a Transaction object which is used to add public key. """ contract_address = ONTID_CONTRACT_ADDRESS args = { "ontid": ont_id.encode(), "pubkey": bytearray.fromhex(hex_new_public_key), "pubkey_or_recovery": bytearray.fromhex(hex_public_key_or_recovery) } invoke_code = build_vm.build_native_invoke_code( contract_address, bytes([0]), "addKey", args) unix_time_now = int(time()) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, Address.b58decode(payer).to_array(), invoke_code, bytearray(), [], bytearray()) return tx
def query_allowance(self, asset: str, b58_from_address: str, b58_to_address: str) -> int: """ :param asset: a string which is used to indicate which asset's allowance we want to get. :param b58_from_address: a base58 encode address which indicate where the allowance from. :param b58_to_address: a base58 encode address which indicate where the allowance to. :return: the amount of allowance in the from of int. """ contract_address = self.get_asset_address(asset) raw_from = Address.b58decode(b58_from_address).to_bytes() raw_to = Address.b58decode(b58_to_address).to_bytes() args = {"from": raw_from, "to": raw_to} invoke_code = build_native_invoke_code(contract_address, b'\x00', "allowance", args) unix_time_now = int(time()) version = 0 tx_type = 0xd1 gas_price = 0 gas_limit = 0 attributes = bytearray() signers = list() tx = Transaction(version, tx_type, unix_time_now, gas_price, gas_limit, None, invoke_code, attributes, signers) response = self.__sdk.rpc.send_raw_transaction_pre_exec(tx) try: allowance = ContractDataParser.to_int(response['Result']) return allowance except SDKException: return 0
def new_withdraw_ong_transaction(self, b58_claimer_address: str, b58_recv_address: str, amount: int, b58_payer_address: str, gas_limit: int, gas_price: int) -> Transaction: """ This interface is used to generate a Transaction object that allow one account to withdraw an amount of ong and transfer them to receive address. :param b58_claimer_address: a base58 encode address which is used to indicate who is the claimer. :param b58_recv_address: a base58 encode address which is used to indicate who receive the claimed ong. :param amount: the amount of asset that will be claimed. :param b58_payer_address: a base58 encode address which indicate who will pay for the transaction. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: a Transaction object which can be used for withdraw ong. """ if not isinstance(b58_claimer_address, str) or not isinstance(b58_recv_address, str) or not isinstance( b58_payer_address, str): raise SDKException(ErrorCode.param_err('the data type of base58 encode address should be the string.')) if len(b58_claimer_address) != 34 or len(b58_recv_address) != 34 or len(b58_payer_address) != 34: raise SDKException(ErrorCode.param_err('the length of base58 encode address should be 34 bytes.')) if amount <= 0: raise SDKException(ErrorCode.other_error('the amount should be greater than than zero.')) if gas_price < 0: raise SDKException(ErrorCode.other_error('the gas price should be equal or greater than zero.')) if gas_limit < 0: raise SDKException(ErrorCode.other_error('the gas limit should be equal or greater than zero.')) ont_contract_address = self.get_asset_address('ont') ong_contract_address = self.get_asset_address("ong") args = {"sender": Address.b58decode(b58_claimer_address).to_bytes(), "from": ont_contract_address, "to": Address.b58decode(b58_recv_address).to_bytes(), "value": amount} invoke_code = build_native_invoke_code(ong_contract_address, b'\x00', "transferFrom", args) unix_time_now = int(time()) payer_array = Address.b58decode(b58_payer_address).to_bytes() return Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer_array, invoke_code, bytearray(), list())
def make_transfer(self, contract_address: str, new_admin_ont_id: str, key_no: str, payer: str, gas_limit: str,gas_price: str): param = {"contract_address": a2b_hex(contract_address.encode()), 'new_admin_ont_id': new_admin_ont_id.encode('utf-8'), 'key_no': key_no} invoke_code = build_native_invoke_code(bytearray.fromhex(self.contract_address), bytes([0]), "transfer", param) unix_time_now = int(time()) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer.get_address().to_array(), invoke_code, bytearray(), [], bytearray()) return tx
def query_balance(self, asset: str, b58_address: str) -> int: """ This interface is used to query the account's ONT or ONG balance. :param asset: a string which is used to indicate which asset we want to check the balance. :param b58_address: a base58 encode account address. :return: account balance. """ raw_address = Address.b58decode(b58_address).to_bytes() contract_address = self.get_asset_address(asset) invoke_code = build_native_invoke_code(contract_address, b'\x00', "balanceOf", raw_address) unix_time_now = int(time()) version = 0 tx_type = 0xd1 gas_price = 0 gas_limit = 0 attributes = bytearray() signers = list() tx = Transaction(version, tx_type, unix_time_now, gas_price, gas_limit, None, invoke_code, attributes, signers) response = self.__sdk.rpc.send_raw_transaction_pre_exec(tx) try: balance = ContractDataParser.to_int(response['Result']) return balance except SDKException: return 0
def assign_funcs_to_role(self, admin_identity: Identity, password: str, key_no: int, contract_address: str, role: str, function_name: list, payer: Account, gas_limit: int, gas_price: int): contract_address = bytearray.fromhex(contract_address) param = { "contract_address": contract_address, "ontid": admin_identity.ont_id.encode('utf-8'), "role": role.encode('utf-8') } param['length'] = len(function_name) for i in range(len(function_name)): param['name' + str(i)] = function_name[i] param['key_no'] = key_no invoke_code = build_native_invoke_code( bytearray.fromhex(self.contract_address), bytes([0]), "assignFuncsToRole", param) unix_time_now = int(time()) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer.get_address().to_array(), invoke_code, bytearray(), [], bytearray()) account = self.__sdk.wallet_manager.get_account( admin_identity.ont_id, password) self.__sdk.sign_transaction(tx, account) self.__sdk.add_sign_transaction(tx, payer) res = self.__sdk.rpc.send_raw_transaction(tx) return res
def new_remove_attribute_transaction(ont_id: str, hex_public_key: str, path: str, b58_payer_address: str, gas_limit: int, gas_price: int): """ This interface is used to generate a Transaction object which is used to remove attribute. :param ont_id: ontid. :param hex_public_key: the hexadecimal public key in the form of string. :param path: a string which is used to indicate which attribute we want to remove. :param b58_payer_address: a base58 encode address which indicate who will pay for the transaction. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: a Transaction object which is used to remove attribute. """ contract_address = ONTID_CONTRACT_ADDRESS args = { "ontid": ont_id.encode(), "key": bytes(path.encode()), "pubkey": bytearray.fromhex(hex_public_key) } invoke_code = build_vm.build_native_invoke_code( contract_address, bytes([0]), "removeAttribute", args) unix_time_now = int(time()) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, Address.b58decode(b58_payer_address).to_array(), invoke_code, bytearray(), [], bytearray()) return tx
def send_transaction(self, contract_address: bytes or bytearray, acct: Account, payer_acct: Account, gas_limit: int, gas_price: int, func: AbiFunction, pre_exec: bool): if func is not None: params = BuildParams.serialize_abi_function(func) else: params = bytearray() if pre_exec: if isinstance(contract_address, bytes): tx = NeoVm.make_invoke_transaction(bytearray(contract_address), bytearray(params), b'', 0, 0) elif isinstance(contract_address, bytearray): tx = NeoVm.make_invoke_transaction(contract_address, bytearray(params), b'', 0, 0) else: raise SDKException(ErrorCode.param_err('the data type of contract address is incorrect.')) if acct is not None: self.__sdk.sign_transaction(tx, acct) return self.__sdk.rpc.send_raw_transaction_pre_exec(tx) else: unix_time_now = int(time()) params.append(0x67) for i in contract_address: params.append(i) if payer_acct is None: raise SDKException(ErrorCode.param_err('payer account is None.')) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer_acct.get_address().to_array(), params, bytearray(), [], bytearray()) self.__sdk.sign_transaction(tx, acct) if acct.get_address_base58() != payer_acct.get_address_base58(): self.__sdk.add_sign_transaction(tx, payer_acct) return self.__sdk.rpc.send_raw_transaction(tx)
def send_transaction(self, contract_address: bytearray, acct: Account, payer_acct: Account, gas_limit: int, gas_price: int, func: AbiFunction, pre_exec: bool): params = bytearray() if func is not None: params = BuildParams.serialize_abi_function(func) if pre_exec: tx = NeoVm.make_invoke_transaction(bytearray(contract_address), bytearray(params), b'', 0, 0) if acct is not None: self.__sdk.sign_transaction(tx, acct) return self.__sdk.rpc.send_raw_transaction_pre_exec(tx) unix_time_now = int(time()) params.append(0x67) for i in contract_address: params.append(i) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer_acct.get_address().to_array(), params, bytearray(), [], bytearray()) if acct is not None: self.__sdk.sign_transaction(tx, acct) if payer_acct is not None and acct is not None and acct.get_address_base58( ) != payer_acct.get_address_base58(): self.__sdk.add_sign_transaction(tx, payer_acct) return self.__sdk.rpc.send_raw_transaction(tx)