def _rlptx_to_txobject(self, rlp_data: bytes) -> TxObject: """ Transform an rlp encoded byte array transaction to a transaction object """ # decode the rlp raw = rlp.decode(rlp_data) tag = _int_decode(raw[0]) vsn = _int_decode(raw[1]) # TODO: verify that the schema is there descriptor = tx_descriptors.get((tag, vsn)) if descriptor is None: # the transaction is not defined raise TypeError(f"Unknown transaction tag/version: {tag}/{vsn}") schema = descriptor.get("schema") tx_data = {"tag": tag, "type": idf.TRANSACTION_TAG_TO_TYPE.get(tag)} for label, fn in schema.items(): if fn.field_type == _INT: tx_data[label] = _int_decode(raw[fn.index]) if fn.field_type == _ID: tx_data[label] = _id_decode(raw[fn.index]) elif fn.field_type == _ENC: tx_data[label] = encode(fn.encoding_prefix, raw[fn.index]) elif fn.field_type == _OTTL_TYPE: ttl_type = _int_decode(raw[fn.index]) tx_data[fn.index] = idf.ORACLE_TTL_TYPES_REV.get(ttl_type) elif fn.field_type == _SG: # signatures are always a list tx_data[label] = [ encode(idf.SIGNATURE, sg) for sg in raw[fn.index] ] elif fn.field_type == _VM_ABI: vml = len(raw[fn.index]) # vm/abi are encoded in the same 32bit length block tx_data["vm_version"] = _int_decode(raw[fn.index][0:vml - 2]) tx_data["abi_version"] = _int_decode(raw[fn.index][vml - 2:]) elif fn.field_type == _BIN: # this are byte arrays tx_data[label] = _binary_decode(raw[fn.index], data_type=fn.data_type) elif fn.field_type == _PTR: # this are name pointers tx_data[label] = [{ "key": _binary_decode(p[0], data_type=str), "id": _id_decode(p[1]) } for p in raw[fn.index]] elif fn.field_type == _TX: # this can be raw or tx object tx_data[label] = self._rlptx_to_txobject(raw[fn.index]) # re-encode the decode object compute_hash = True if tag == idf.OBJECT_TAG_SIGNED_TRANSACTION else False return self._txdata_to_txobject(tx_data, descriptor, compute_hash=compute_hash)
def encode_signed_transaction(self, transaction, signature): """prepare a signed transaction message""" tag = bytes([idf.OBJECT_TAG_SIGNED_TRANSACTION]) vsn = bytes([idf.VSN]) encoded_signed_tx = encode_rlp(idf.TRANSACTION, [tag, vsn, [signature], transaction]) encoded_signature = encode(idf.SIGNATURE, signature) return encoded_signed_tx, encoded_signature
def tx_spend(self, sender_id, recipient_id, amount, payload, fee, ttl, nonce) -> TxObject: """ create a spend transaction :param sender_id: the public key of the sender :param recipient_id: the public key of the recipient :param amount: the amount to send :param payload: the payload associated with the data :param fee: the fee for the transaction :param ttl: the absolute ttl of the transaction :param nonce: the nonce of the transaction """ # use internal endpoints transaction body = dict( tag=idf.OBJECT_TAG_SPEND_TRANSACTION, version=idf.VSN, recipient_id=recipient_id, amount=amount, fee=fee, sender_id=sender_id, payload=encode(idf.BYTE_ARRAY, payload), ttl=ttl, nonce=nonce, ) return self._build_txobject(body)
def encode_signed_transaction(self, transaction, signature): """prepare a signed transaction message""" tag = bytes([OBJECT_TAG_SIGNED_TRANSACTION]) vsn = bytes([VSN]) encoded_signed_tx = hashing.encode_rlp( "tx", [tag, vsn, [signature], transaction]) encoded_signature = hashing.encode("sg", signature) return encoded_signed_tx, encoded_signature
def _txdata_to_txobject(self, data: dict, descriptor: dict, metadata: dict = {}, compute_hash=True) -> TxObject: # initialize the right data size # this is PYTHON to POSTBODY schema = descriptor.get("schema", []) raw_data = [0] * (len(schema) + 1) # the +1 is for the tag # set the tx tag first raw_data[0] = _int(data.get("tag")) # parse fields and encode them for label, fn in schema.items(): if fn.field_type == _INT: raw_data[fn.index] = _int(data.get(label, 0)) elif fn.field_type == _ID: raw_data[fn.index] = _id(data.get(label)) elif fn.field_type == _ENC: raw_data[fn.index] = decode(data.get(label)) elif fn.field_type == _OTTL_TYPE: raw_data[fn.index] = _int(idf.ORACLE_TTL_TYPES.get(data.get(label))) elif fn.field_type == _SG: # signatures are always a list raw_data[fn.index] = [decode(sg) for sg in data.get(label, [])] elif fn.field_type == _VM_ABI: # vm/abi are encoded in the same 32bit length block raw_data[fn.index] = _int(data.get("vm_version")) + _int(data.get("abi_version"), 2) elif fn.field_type == _BIN: # this are binary string #TODO: may be byte array raw_data[fn.index] = _binary(data.get(label)) elif fn.field_type == _PTR: # this are name pointers raw_data[fn.index] = [[_binary(p.get("key")), _id(p.get("id"))] for p in data.get(label, [])] elif fn.field_type == _TX: # this can be raw or tx object tx = data.get(label).tx if hasattr(data.get(label), "tx") else data.get(label) raw_data[fn.index] = decode(tx) # encode the transaction in rlp rlp_tx = rlp.encode(raw_data) # encode the tx in base64 rlp_b64_tx = encode(idf.TRANSACTION, rlp_tx) # copy the data before modifying tx_data = copy.deepcopy(data) # build the tx object txo = TxObject( data=namedtupled.map(tx_data, _nt_name="TxData"), tx=rlp_b64_tx, ) # compute the tx hash if compute_hash: txo.hash = hash_encode(idf.TRANSACTION_HASH, rlp_tx) # copy the metadata if exists or initialize it if None tx_meta = copy.deepcopy(metadata) if metadata is not None else {} # compute the minimum fee if descriptor.get("fee") is not None: tx_meta["min_fee"] = self.compute_min_fee(data, descriptor, raw_data) # only set the metadata if it is not empty txo.set_metadata(tx_meta) return txo
def signed_tx_to_obj(tx_str): tx = hashing.decode_rlp(tx_str) if hashing._int_decode(tx[0]) != 11: raise Exception("invalid tag") if len(tx) != 4: raise Exception("invalid tx") return transactions._tx_native(op=transactions.UNPACK_TX, tx=hashing.encode("tx", tx[3]))
def sign_transaction(self, transaction: TxObject, metadata: dict = None) -> str: """ Sign, encode and compute the hash of a transaction :param tx: the TxObject to be signed :param metadata: additional data to include in the output of the signed transaction object :return: encoded_signed_tx, encoded_signature, tx_hash """ # get the transaction as byte list tx_raw = decode(transaction.tx) # sign the transaction signature = self.account.sign(_binary(self.network_id) + tx_raw) # pack and encode the transaction return encode(idf.SIGNATURE, signature)
def __init__(self, signing_key, verifying_key, **kwargs): # distinguish from poa / ga # TODO: handle the case that they are not set self.nonce = kwargs.get("nonce", 0) self.balance = kwargs.get("balance", 0) self.kind = kwargs.get("kind", ACCOUNT_KIND_BASIC) self.contract_id = kwargs.get("contract_id") self.auth_fun = kwargs.get("auth_fun") self.address = kwargs.get("id") self.signing_key = signing_key self.verifying_key = verifying_key if verifying_key is not None: pub_key = self.verifying_key.encode(encoder=RawEncoder) self.address = hashing.encode(ACCOUNT_ID, pub_key)
def sign_transaction(self, transaction: TxObject, metadata: dict = None) -> str: """ Sign, encode and compute the hash of a transaction Args: tx (TxObject): the TxObject to be signed Returns: the encoded and prefixed signature """ # get the transaction as byte list tx_raw = decode(transaction.tx) # sign the transaction signature = self.account.sign(_binary(self.network_id) + tx_raw) # pack and encode the transaction return encode(idf.SIGNATURE, signature)
def test_hashing_base58_encode(): inputs = [ { "data": "test".encode("utf-8"), "prefix": "tt", "hash": "LUC1eAJa5jW", "match": True, "raise_error": False, }, { "data": "test".encode("utf-8"), "prefix": "tt", "hash": "LUC1eAJa", "match": False, "raise_error": True, }, { "data": "aeternity".encode("utf-8"), "prefix": "aa", "hash": "97Wv2fcowb3y3qVnDC", "match": True, "raise_error": False, }, ] for i in inputs: try: h = hashing._base58_encode(i.get("data")) assert (h == i.get("hash")) is i.get("match") e = hashing.encode(i.get("prefix"), i.get("data")) assert (e == f'{i.get("prefix")}_{i.get("hash")}') is i.get("match") o = hashing._base58_decode(i.get("hash")) assert (o == i.get("data")) is i.get("match") except Exception as e: assert i.get("raise_error") is True
def test_evm_encode_calldata(): contract = EPOCH_CLI.Contract(aer_identity_contract, abi=Contract.EVM) result = contract.encode_calldata('main', '1') assert result is not None assert result == hashing.encode('cb', 'main1')
def __init__(self, signing_key, verifying_key): self.signing_key = signing_key self.verifying_key = verifying_key pub_key = self.verifying_key.encode(encoder=RawEncoder) self.address = hashing.encode("ak", pub_key)
def _tx_native(op, **kwargs): def std_fee(tx_raw, fee_idx, base_gas_multiplier=1): # calculates the standard minimum transaction fee tx_copy = tx_raw # create a copy of the input tx_copy[fee_idx] = _int(0, 8) # replace fee with a byte array of lenght 8 return (defaults.BASE_GAS * base_gas_multiplier + len(rlp.encode(tx_copy)) * defaults.GAS_PER_BYTE) * defaults.GAS_PRICE def contract_fee(tx_raw, fee_idx, gas, base_gas_multiplier=1): # estimate the contract creation fee tx_copy = tx_raw # create a copy of the input tx_copy[fee_idx] = _int(0, 8) # replace fee with a byte array of lenght 8 return (defaults.BASE_GAS * base_gas_multiplier + gas + len(rlp.encode(tx_copy)) * defaults.GAS_PER_BYTE) * defaults.GAS_PRICE def oracle_fee(tx_raw, fee_idx, relative_ttl): # estimate oracle fees tx_copy = tx_raw # create a copy of the input tx_copy[fee_idx] = _int(0, 8) # replace fee with a byte array of lenght 8 fee = (defaults.BASE_GAS + len(rlp.encode(tx_copy)) * defaults.GAS_PER_BYTE) fee += math.ceil(32000 * relative_ttl / math.floor(60 * 24 * 365 / defaults.KEY_BLOCK_INTERVAL)) return fee * defaults.GAS_PRICE def build_tx_object(tx_data, tx_raw, fee_idx, min_fee): if tx_data.get("fee") < min_fee: tx_native[fee_idx] = _int(min_fee) tx_data["fee"] = min_fee tx_encoded = encode_rlp(idf.TRANSACTION, tx_native) tx = dict( data=tx_data, tx=tx_encoded, hash=TxBuilder.compute_tx_hash(tx_encoded), ) return namedtupled.map(tx, _nt_name="TxObject") # prepare tag and version if op == PACK_TX: tag = kwargs.get("tag", 0) vsn = kwargs.get("vsn", 1) tx_data = kwargs elif op == UNPACK_TX: tx_native = decode_rlp(kwargs.get("tx", [])) tag = _int_decode(tx_native[0]) else: raise Exception("Invalid operation") # check the tags if tag == idf.OBJECT_TAG_SPEND_TRANSACTION: tx_field_fee_index = 5 if op == PACK_TX: # pack transaction tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ACCOUNT, kwargs.get("sender_id")), _id(idf.ID_TAG_ACCOUNT, kwargs.get("recipient_id")), _int(kwargs.get("amount")), _int(kwargs.get("fee")), # index 5 _int(kwargs.get("ttl")), _int(kwargs.get("nonce")), _binary(kwargs.get("payload")) ] min_fee = std_fee(tx_native, tx_field_fee_index) elif op == UNPACK_TX: # unpack transaction tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), sender_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]), recipient_id=encode(idf.ACCOUNT_ID, tx_native[3][1:]), amount=_int_decode(tx_native[4]), fee=_int_decode(tx_native[5]), ttl=_int_decode(tx_native[6]), nonce=_int_decode(tx_native[7]), payload=_binary_decode(tx_native[8]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) elif tag == idf.OBJECT_TAG_NAME_SERVICE_PRECLAIM_TRANSACTION: tx_field_fee_index = 5 if op == PACK_TX: # pack transaction tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")), _int(kwargs.get("nonce")), _id(idf.ID_TAG_COMMITMENT, kwargs.get("commitment_id")), _int(kwargs.get("fee")), _int(kwargs.get("ttl")) ] min_fee = std_fee(tx_native, tx_field_fee_index) elif op == UNPACK_TX: # unpack transaction tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]), nonce=_int_decode(tx_native[3]), commitment_id=encode(idf.COMMITMENT, tx_native[4][1:]), fee=_int_decode(tx_native[5]), ttl=_int_decode(tx_native[6]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) elif tag == idf.OBJECT_TAG_NAME_SERVICE_CLAIM_TRANSACTION: tx_field_fee_index = 6 if op == PACK_TX: # pack transaction tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")), _int(kwargs.get("nonce")), decode(kwargs.get("name")), _binary(kwargs.get("name_salt")), _int(kwargs.get("fee")), _int(kwargs.get("ttl")) ] min_fee = std_fee(tx_native, tx_field_fee_index) elif op == UNPACK_TX: # unpack transaction tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]), nonce=_int_decode(tx_native[3]), name=_binary_decode(tx_native[4], str), name_salt=_binary_decode(tx_native[5], int), fee=_int_decode(tx_native[6]), ttl=_int_decode(tx_native[7]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) elif tag == idf.OBJECT_TAG_NAME_SERVICE_UPDATE_TRANSACTION: tx_field_fee_index = 8 if op == PACK_TX: # pack transaction # first asseble the pointers def pointer_tag(pointer): return { "account_pubkey": idf.ID_TAG_ACCOUNT, "oracle_pubkey": idf.ID_TAG_ORACLE, "contract_pubkey": idf.ID_TAG_CONTRACT, "channel_pubkey": idf.ID_TAG_CHANNEL }.get(pointer.get("key")) ptrs = [[_binary(p.get("key")), _id(pointer_tag(p), p.get("id"))] for p in kwargs.get("pointers", [])] # then build the transaction tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")), _int(kwargs.get("nonce")), _id(idf.ID_TAG_NAME, kwargs.get("name_id")), _int(kwargs.get("name_ttl")), ptrs, _int(kwargs.get("client_ttl")), _int(kwargs.get("fee")), _int(kwargs.get("ttl")) ] min_fee = std_fee(tx_native, tx_field_fee_index) elif op == UNPACK_TX: # unpack transaction tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]), nonce=_int_decode(tx_native[3]), name=encode(idf.NAME, tx_native[4][1:]), name_ttl=_int_decode(tx_native[5]), pointers=[], # TODO: decode pointers client_ttl=_int_decode(tx_native[7]), fee=_int_decode(tx_native[8]), ttl=_int_decode(tx_native[9]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) elif tag == idf.OBJECT_TAG_NAME_SERVICE_TRANSFER_TRANSACTION: tx_field_fee_index = 6 if op == PACK_TX: # pack transaction tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")), _int(kwargs.get("nonce")), _id(idf.ID_TAG_NAME, kwargs.get("name_id")), _id(idf.ID_TAG_ACCOUNT, kwargs.get("recipient_id")), _int(kwargs.get("fee")), _int(kwargs.get("ttl")), ] min_fee = std_fee(tx_native, tx_field_fee_index) elif op == UNPACK_TX: # unpack transaction tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]), nonce=_int_decode(tx_native[3]), name=encode(idf.NAME, tx_native[4][1:]), recipient_id=encode(idf.ACCOUNT_ID, tx_native[5][1:]), fee=_int_decode(tx_native[6]), ttl=_int_decode(tx_native[7]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) elif tag == idf.OBJECT_TAG_NAME_SERVICE_REVOKE_TRANSACTION: tx_field_fee_index = 5 if op == PACK_TX: # pack transaction tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")), _int(kwargs.get("nonce")), _id(idf.ID_TAG_NAME, kwargs.get("name_id")), _int(kwargs.get("fee")), _int(kwargs.get("ttl")), ] min_fee = std_fee(tx_native, tx_field_fee_index) elif op == UNPACK_TX: # unpack transaction tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]), nonce=_int_decode(tx_native[3]), name=encode(idf.NAME, tx_native[4][1:]), fee=_int_decode(tx_native[5]), ttl=_int_decode(tx_native[6]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) elif tag == idf.OBJECT_TAG_CONTRACT_CREATE_TRANSACTION: tx_field_fee_index = 6 if op == PACK_TX: # pack transaction tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ACCOUNT, kwargs.get("owner_id")), _int(kwargs.get("nonce")), _binary(decode(kwargs.get("code"))), _int(kwargs.get("vm_version")) + _int(kwargs.get("abi_version"), 2), _int(kwargs.get("fee")), _int(kwargs.get("ttl")), _int(kwargs.get("deposit")), _int(kwargs.get("amount")), _int(kwargs.get("gas")), _int(kwargs.get("gas_price")), _binary(decode(kwargs.get("call_data"))), ] # TODO: verify the fee caluclation for the contract min_fee = contract_fee(tx_native, tx_field_fee_index, kwargs.get("gas"), base_gas_multiplier=5) elif op == UNPACK_TX: # unpack transaction vml = len(tx_native[5]) # this is used to extract the abi and vm version from the 5th field tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), owner_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]), nonce=_int_decode(tx_native[3]), code=encode(idf.BYTECODE, tx_native[4][1:]), vm_version=_int_decode(tx_native[5][0:vml - 2]), abi_version=_int_decode(tx_native[5][vml - 2:]), fee=_int_decode(tx_native[6]), ttl=_int_decode(tx_native[7]), deposit=_int_decode(tx_native[8]), amount=_int_decode(tx_native[9]), gas=_int_decode(tx_native[10]), gas_price=_int_decode(tx_native[11]), call_data=encode(idf.BYTECODE, tx_native[12][1:]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) elif tag == idf.OBJECT_TAG_CONTRACT_CALL_TRANSACTION: tx_field_fee_index = 6 if op == PACK_TX: # pack transaction tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ACCOUNT, kwargs.get("caller_id")), _int(kwargs.get("nonce")), _id(idf.ID_TAG_CONTRACT, kwargs.get("contract_id")), _int(kwargs.get("abi_version")), _int(kwargs.get("fee")), _int(kwargs.get("ttl")), _int(kwargs.get("amount")), _int(kwargs.get("gas")), _int(kwargs.get("gas_price")), _binary(decode(kwargs.get("call_data"))), ] min_fee = contract_fee(tx_native, tx_field_fee_index, kwargs.get("gas"), base_gas_multiplier=30) elif op == UNPACK_TX: # unpack transaction vml = len(tx_native[5]) # this is used to extract the abi and vm version from the 5th field tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), caller_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]), nonce=_int_decode(tx_native[3]), contract_id=encode(idf.CONTRACT_ID, tx_native[4][1:]), abi_version=_int_decode(tx_native[5]), fee=_int_decode(tx_native[6]), ttl=_int_decode(tx_native[7]), amount=_int_decode(tx_native[8]), gas=_int_decode(tx_native[9]), gas_price=_int_decode(tx_native[10]), call_data=encode(idf.BYTECODE, tx_native[11][1:]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) elif tag == idf.OBJECT_TAG_CHANNEL_CREATE_TRANSACTION: tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ACCOUNT, kwargs.get("initiator")), _int(kwargs.get("initiator_amount")), _id(idf.ID_TAG_ACCOUNT, kwargs.get("responder")), _int(kwargs.get("responder_amount")), _int(kwargs.get("channel_reserve")), _int(kwargs.get("lock_period")), _int(kwargs.get("ttl")), _int(kwargs.get("fee")), # _[id(delegate_ids)], TODO: handle delegate ids _binary(kwargs.get("state_hash")), _int(kwargs.get("nonce")), ] tx_field_fee_index = 9 min_fee = std_fee(tx_native, tx_field_fee_index) elif tag == idf.OBJECT_TAG_CHANNEL_DEPOSIT_TRANSACTION: tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")), _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")), _int(kwargs.get("amount")), _int(kwargs.get("ttl")), _int(kwargs.get("fee")), _binary(kwargs.get("state_hash")), _int(kwargs.get("round")), _int(kwargs.get("nonce")), ] tx_field_fee_index = 6 min_fee = std_fee(tx_native, tx_field_fee_index) elif tag == idf.OBJECT_TAG_CHANNEL_WITHDRAW_TRANSACTION: tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")), _id(idf.ID_TAG_ACCOUNT, kwargs.get("to_id")), _int(kwargs.get("amount")), _int(kwargs.get("ttl")), _int(kwargs.get("fee")), _binary(kwargs.get("state_hash")), _int(kwargs.get("round")), _int(kwargs.get("nonce")), ] tx_field_fee_index = 6 min_fee = std_fee(tx_native, tx_field_fee_index) elif tag == idf.OBJECT_TAG_CHANNEL_CLOSE_MUTUAL_TRANSACTION: tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")), _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")), _int(kwargs.get("initiator_amount_final")), _int(kwargs.get("responder_amount_final")), _int(kwargs.get("ttl")), _int(kwargs.get("fee")), _int(kwargs.get("nonce")), ] tx_field_fee_index = 7 min_fee = std_fee(tx_native, tx_field_fee_index) elif tag == idf.OBJECT_TAG_CHANNEL_CLOSE_SOLO_TRANSACTION: tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")), _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")), _binary(kwargs.get("payload")), # _poi(kwargs.get("poi")), TODO: implement support for _poi _int(kwargs.get("ttl")), _int(kwargs.get("fee")), _int(kwargs.get("nonce")), ] tx_field_fee_index = 7 min_fee = std_fee(tx_native, tx_field_fee_index) elif tag == idf.OBJECT_TAG_CHANNEL_SLASH_TRANSACTION: tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")), _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")), _binary(kwargs.get("payload")), # _poi(kwargs.get("poi")), TODO: implement support for _poi _int(kwargs.get("ttl")), _int(kwargs.get("fee")), _int(kwargs.get("nonce")), ] tx_field_fee_index = 7 min_fee = std_fee(tx_native, tx_field_fee_index) elif tag == idf.OBJECT_TAG_CHANNEL_SETTLE_TRANSACTION: tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")), _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")), _int(kwargs.get("initiator_amount_final")), _int(kwargs.get("responder_amount_final")), _int(kwargs.get("ttl")), _int(kwargs.get("fee")), _int(kwargs.get("nonce")), ] tx_field_fee_index = 7 min_fee = std_fee(tx_native, tx_field_fee_index) elif tag == idf.OBJECT_TAG_CHANNEL_SNAPSHOT_TRANSACTION: tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")), _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")), _binary(kwargs.get("payload")), _int(kwargs.get("ttl")), _int(kwargs.get("fee")), _int(kwargs.get("nonce")), ] tx_field_fee_index = 6 min_fee = std_fee(tx_native, tx_field_fee_index) elif tag == idf.OBJECT_TAG_CHANNEL_FORCE_PROGRESS_TRANSACTION: tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_CHANNEL, kwargs.get("channel_id")), _id(idf.ID_TAG_ACCOUNT, kwargs.get("from_id")), _binary(kwargs.get("payload")), _int(kwargs.get("round")), _binary(kwargs.get("update")), _binary(kwargs.get("state_hash")), # _trees(kwargs.get("offchain_trees")), TODO: implement support for _trees _int(kwargs.get("ttl")), _int(kwargs.get("fee")), _int(kwargs.get("nonce")), ] tx_field_fee_index = 9 min_fee = std_fee(tx_native, tx_field_fee_index) elif tag == idf.OBJECT_TAG_ORACLE_REGISTER_TRANSACTION: tx_field_fee_index = 9 if op == PACK_TX: # pack transaction oracle_ttl = kwargs.get("oracle_ttl", {}) tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ACCOUNT, kwargs.get("account_id")), _int(kwargs.get("nonce")), _binary(kwargs.get("query_format")), _binary(kwargs.get("response_format")), _int(kwargs.get("query_fee")), _int(0 if oracle_ttl.get("type") == idf.ORACLE_TTL_TYPE_DELTA else 1), _int(oracle_ttl.get("value")), _int(kwargs.get("fee")), _int(kwargs.get("ttl")), _int(kwargs.get("vm_version")), ] min_fee = oracle_fee(tx_native, tx_field_fee_index, oracle_ttl.get("value")) elif op == UNPACK_TX: # unpack transaction vml = len(tx_native[5]) # this is used to extract the abi and vm version from the 5th field tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), account_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]), nonce=_int_decode(tx_native[3]), query_format=_binary_decode(tx_native[4]), response_format=_binary_decode(tx_native[5]), query_fee=_int_decode(tx_native[6]), oracle_ttl=dict( type=idf.ORACLE_TTL_TYPE_DELTA if _int_decode(tx_native[7]) else idf.ORACLE_TTL_TYPE_BLOCK, value=_int_decode(tx_native[8]), ), fee=_int_decode(tx_native[9]), ttl=_int_decode(tx_native[10]), vm_version=_int_decode(tx_native[11]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) elif tag == idf.OBJECT_TAG_ORACLE_QUERY_TRANSACTION: tx_field_fee_index = 11 if op == PACK_TX: # pack transaction query_ttl = kwargs.get("query_ttl", {}) response_ttl = kwargs.get("response_ttl", {}) tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ACCOUNT, kwargs.get("sender_id")), _int(kwargs.get("nonce")), _id(idf.ID_TAG_ORACLE, kwargs.get("oracle_id")), _binary(kwargs.get("query")), _int(kwargs.get("query_fee")), _int(0 if query_ttl.get("type") == idf.ORACLE_TTL_TYPE_DELTA else 1), _int(query_ttl.get("value")), _int(0 if response_ttl.get("type") == idf.ORACLE_TTL_TYPE_DELTA else 1), _int(response_ttl.get("value")), _int(kwargs.get("fee")), _int(kwargs.get("ttl")), ] min_fee = oracle_fee(tx_native, tx_field_fee_index, query_ttl.get("value")) elif op == UNPACK_TX: # unpack transaction vml = len(tx_native[5]) # this is used to extract the abi and vm version from the 5th field tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), sender_id=encode(idf.ACCOUNT_ID, tx_native[2][1:]), nonce=_int_decode(tx_native[3]), oracle_id=encode(idf.ORACLE_ID, tx_native[4][1:]), query=_binary_decode(tx_native[5]), query_fee=_int_decode(tx_native[6]), query_ttl=dict( type=idf.ORACLE_TTL_TYPE_DELTA if _int_decode(tx_native[7]) else idf.ORACLE_TTL_TYPE_BLOCK, value=_int_decode(tx_native[8]), ), response_ttl=dict( type=idf.ORACLE_TTL_TYPE_DELTA if _int_decode(tx_native[9]) else idf.ORACLE_TTL_TYPE_BLOCK, value=_int_decode(tx_native[10]), ), fee=_int_decode(tx_native[11]), ttl=_int_decode(tx_native[12]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) elif tag == idf.OBJECT_TAG_ORACLE_RESPONSE_TRANSACTION: tx_field_fee_index = 8 if op == PACK_TX: # pack transaction response_ttl = kwargs.get("response_ttl", {}) tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ORACLE, kwargs.get("oracle_id")), _int(kwargs.get("nonce")), decode(kwargs.get("query_id")), _binary(kwargs.get("response")), _int(0 if response_ttl.get("type") == idf.ORACLE_TTL_TYPE_DELTA else 1), _int(response_ttl.get("value")), _int(kwargs.get("fee")), _int(kwargs.get("ttl")), ] min_fee = oracle_fee(tx_native, tx_field_fee_index, response_ttl.get("value")) elif op == UNPACK_TX: # unpack transaction vml = len(tx_native[5]) # this is used to extract the abi and vm version from the 5th field tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), oracle_id=encode(idf.ORACLE_ID, tx_native[2][1:]), nonce=_int_decode(tx_native[3]), query_id=encode(idf.ORACLE_QUERY_ID, tx_native[4][1:]), response=_binary(tx_native[5]), response_ttl=dict( type=idf.ORACLE_TTL_TYPE_DELTA if _int_decode(tx_native[6]) else idf.ORACLE_TTL_TYPE_BLOCK, value=_int_decode(tx_native[7]), ), fee=_int_decode(tx_native[8]), ttl=_int_decode(tx_native[9]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) elif tag == idf.OBJECT_TAG_ORACLE_EXTEND_TRANSACTION: tx_field_fee_index = 6 if op == PACK_TX: # pack transaction oracle_ttl = kwargs.get("oracle_ttl", {}) tx_native = [ _int(tag), _int(vsn), _id(idf.ID_TAG_ORACLE, kwargs.get("oracle_id")), _int(kwargs.get("nonce")), _int(0 if oracle_ttl.get("type", {}) == idf.ORACLE_TTL_TYPE_DELTA else 1), _int(oracle_ttl.get("value")), _int(kwargs.get("fee")), _int(kwargs.get("ttl")), ] min_fee = oracle_fee(tx_native, tx_field_fee_index, oracle_ttl.get("value")) elif op == UNPACK_TX: # unpack transaction vml = len(tx_native[5]) # this is used to extract the abi and vm version from the 5th field tx_data = dict( tag=tag, vsn=_int_decode(tx_native[1]), oracle_id=encode(idf.ORACLE_ID, tx_native[2][1:]), nonce=_int_decode(tx_native[3]), oracle_ttl=dict( type=idf.ORACLE_TTL_TYPE_DELTA if _int_decode(tx_native[4]) else idf.ORACLE_TTL_TYPE_BLOCK, value=_int_decode(tx_native[5]), ), fee=_int_decode(tx_native[6]), ttl=_int_decode(tx_native[7]), ) min_fee = tx_data.get("fee") else: raise Exception("Invalid operation") return build_tx_object(tx_data, tx_native, tx_field_fee_index, min_fee) else: raise UnsupportedTransactionType(f"Unusupported transaction tag {tag}")
def _test_oracle_response(query, expected): r = query.get_response_object() assert r.oracle_id == query.oracle_id assert r.id == query.id assert r.response == hashing.encode("or", expected)
def __init__(self, signing_key, verifying_key): self.signing_key = signing_key self.verifying_key = verifying_key pub_key = self.verifying_key.encode(encoder=RawEncoder) self.address = hashing.encode(ACCOUNT_ID, pub_key) self.nonce = 0
def _encode_name(cls, name): if isinstance(name, str): name = name.encode('ascii') return hashing.encode('nm', name)