def _transaction_from_explorer_transaction( self, etxn, endpoint="/?", resp=None): # keyword parameters for error handling purposes only if resp == None: resp = jsobj.new_dict() # parse the transactions transaction = transactions.from_json(obj=etxn['rawtransaction'], id=etxn['id']) # add the parent (coin) outputs coininputoutputs = etxn.get_or('coininputoutputs', None) or [] if len(transaction.coin_inputs) != len(coininputoutputs): raise tferrors.ExplorerInvalidResponse( "amount of coin inputs and parent outputs are not matching: {} != {}" .format(len(transaction.coin_inputs), len(coininputoutputs)), endpoint, resp) for (idx, co) in enumerate(coininputoutputs): co = CoinOutput.from_json(obj=co) co.id = transaction.coin_inputs[idx].parentid transaction.coin_inputs[idx].parent_output = co # add the coin output ids coinoutputids = etxn.get_or('coinoutputids', None) or [] if len(transaction.coin_outputs) != len(coinoutputids): raise tferrors.ExplorerInvalidResponse( "amount of coin outputs and output identifiers are not matching: {} != {}" .format(len(transaction.coin_outputs), len(coinoutputids)), endpoint, resp) for (idx, id) in enumerate(coinoutputids): transaction.coin_outputs[idx].id = Hash.from_json(obj=id) # add the parent (blockstake) outputs blockstakeinputoutputs = etxn.get_or('blockstakeinputoutputs', None) or [] if len(transaction.blockstake_inputs) != len(blockstakeinputoutputs): raise tferrors.ExplorerInvalidResponse( "amount of blockstake inputs and parent outputs are not matching: {} != {}" .format(len(transaction.blockstake_inputs), len(blockstakeinputoutputs)), endpoint, resp) for (idx, bso) in enumerate(blockstakeinputoutputs): bso = BlockstakeOutput.from_json(obj=bso) bso.id = transaction.blockstake_inputs[idx].parentid transaction.blockstake_inputs[idx].parent_output = bso # add the blockstake output ids blockstakeoutputids = etxn.get_or('blockstakeoutputids', None) or [] if len(transaction.blockstake_outputs) != len(blockstakeoutputids): raise tferrors.ExplorerInvalidResponse( "amount of blokstake outputs and output identifiers are not matching: {} != {}" .format(len(transaction.blockstake_inputs), len(blockstakeoutputids)), endpoint, resp) for (idx, id) in enumerate(blockstakeoutputids): transaction.blockstake_outputs[idx].id = Hash.from_json(obj=id) # set the unconfirmed state transaction.unconfirmed = etxn.get_or('unconfirmed', False) # set the blockid and height of the transaction only if confirmed if not transaction.unconfirmed: transaction.height = int(etxn.get_or('height', -1)) transaction.blockid = etxn.get_or('parent', None) # return the transaction return transaction
def _block_get_parse_cb(self, result): endpoint, block = result try: # parse the transactions transactions = [] for etxn in block['transactions']: # parse the explorer transaction transaction = self._transaction_from_explorer_transaction( etxn, endpoint=endpoint, resp=block) # append the transaction to the list of transactions transactions.append(transaction) rawblock = block['rawblock'] # parse the parent id parentid = Hash.from_json(obj=rawblock['parentid']) # parse the miner payouts miner_payouts = [] minerpayoutids = block.get_or('minerpayoutids', None) or [] eminerpayouts = rawblock.get_or('minerpayouts', None) or [] if len(eminerpayouts) != len(minerpayoutids): raise tferrors.ExplorerInvalidResponse( "amount of miner payouts and payout ids are not matching: {} != {}" .format(len(eminerpayouts), len(minerpayoutids)), endpoint, block) for idx, mp in enumerate(eminerpayouts): id = Hash.from_json(minerpayoutids[idx]) value = Currency.from_json(mp['value']) unlockhash = UnlockHash.from_json(mp['unlockhash']) miner_payouts.append( ExplorerMinerPayout(id=id, value=value, unlockhash=unlockhash)) # get the timestamp and height height = int(block['height']) timestamp = int(rawblock['timestamp']) # get the block's identifier blockid = Hash.from_json(block['blockid']) # for all transactions assign these properties for transaction in transactions: _assign_block_properties_to_transacton(transaction, block) transaction.height = height transaction.blockid = blockid # return the block, as reported by the explorer return ExplorerBlock(id=blockid, parentid=parentid, height=height, timestamp=timestamp, transactions=transactions, miner_payouts=miner_payouts) except KeyError as exc: raise tferrors.ExplorerInvalidResponse(str(exc), endpoint, block) from exc
def get_block_prop(result): _, result = result block = result.get_or('block', None) if block == None: raise tferrors.ExplorerInvalidResponse( "block property is undefined", endpoint, result) return (endpoint, block)
def cb(result): _, result = result try: hash_type = result['hashtype'] if hash_type != expected_hash_type: raise tferrors.ExplorerInvalidResponse( "expected hash type '{}', not '{}'".format( expected_hash_type, hash_type), endpoint, result) tresp = result['transactions'] lresp = len(tresp) if lresp not in (1, 2): raise tferrors.ExplorerInvalidResponse( "expected one or two transactions to be returned, not {}" .format(lresp), endpoint, result) # parse the transaction(s) creation_txn = tresp[0] spend_txn = None if lresp == 2: if tresp[1]['height'] > creation_txn['height']: spend_txn = tresp[1] else: spend_txn = creation_txn creation_txn = tresp[1] creation_txn = self._transaction_from_explorer_transaction( creation_txn, endpoint=endpoint, resp=result) if spend_txn != None: spend_txn = self._transaction_from_explorer_transaction( spend_txn, endpoint=endpoint, resp=result) # collect the output output = None for out in (creation_txn.coin_outputs if hash_type == 'coinoutputid' else creation_txn.blockstake_outputs): if str(out.id) == id: output = out break if output == None: raise tferrors.ExplorerInvalidResponse( "expected output {} to be part of creation Tx, but it wasn't" .format(id), endpoint, result) # return the output and related transaction(s) return ExplorerOutputResult(output, creation_txn, spend_txn) except KeyError as exc: # return a KeyError as an invalid Explorer Response raise tferrors.ExplorerInvalidResponse(str(exc), endpoint, result) from exc
def cb(result): _, transaction = result try: return Hash(value=transaction['transactionid']).__str__() except (KeyError, ValueError, TypeError) as exc: # return a KeyError as an invalid Explorer Response raise tferrors.ExplorerInvalidResponse(str(exc), endpoint, transaction) from exc
def get_block_prop(result): _, result = result try: if result['hashtype'] != 'blockid': raise tferrors.ExplorerInvalidResponse( "expected hash type 'blockid' not '{}'".format( result['hashtype']), endpoint, result) block = result['block'] if block['blockid'] != blockid: raise tferrors.ExplorerInvalidResponse( "expected block ID '{}' not '{}'".format( blockid.__str__(), block['blockid']), endpoint, result) return (endpoint, block) except KeyError as exc: raise tferrors.ExplorerInvalidResponse(str(exc), endpoint, result) from exc
def cb(result): _, result = result try: if result['hashtype'] != 'transactionid': raise tferrors.ExplorerInvalidResponse( "expected hash type 'transactionid' not '{}'".format( result['hashtype']), endpoint, result) txnresult = result['transaction'] if txnresult['id'] != txid: raise tferrors.ExplorerInvalidResponse( "expected transaction ID '{}' not '{}'".format( txid, txnresult['id']), endpoint, result) return self._transaction_from_explorer_transaction( txnresult, endpoint=endpoint, resp=result) except KeyError as exc: # return a KeyError as an invalid Explorer Response raise tferrors.ExplorerInvalidResponse(str(exc), endpoint, result) from exc
def cb(result): _, resp = result try: # return the decoded mint condition return ConditionTypes.from_json(obj=resp['mintcondition']) except KeyError as exc: # return a KeyError as an invalid Explorer Response raise tferrors.ExplorerInvalidResponse(str(exc), endpoint, resp) from exc
def cb(result): _, resp = result try: # parse the unconfirmed transactions unconfirmed_transactions = [] resp_transactions = resp['transactions'] if resp_transactions != None and jsobj.is_js_arr( resp_transactions): for etxn in resp_transactions: # parse the (raw) transaction transaction = transactions.from_json(obj=etxn) # compute the transactionID manually transaction.id = transaction.transaction_id_new() # force it to be unconfirmed transaction.unconfirmed = True # append the transaction to the list of transactions unconfirmed_transactions.append(transaction) return unconfirmed_transactions except (KeyError, ValueError, TypeError) as exc: # return a KeyError as an invalid Explorer Response raise tferrors.ExplorerInvalidResponse(str(exc), endpoint, transaction) from exc
def cb(result): _, resp = result try: if resp['hashtype'] != 'unlockhash': raise tferrors.ExplorerInvalidResponse( "expected hash type 'unlockhash' not '{}'".format( resp['hashtype']), endpoint, resp) # parse the transactions transactions = [] resp_transactions = resp['transactions'] if resp_transactions != None and jsobj.is_js_arr( resp_transactions): for etxn in resp_transactions: # parse the explorer transaction transaction = self._transaction_from_explorer_transaction( etxn, endpoint=endpoint, resp=resp) # append the transaction to the list of transactions transactions.append(transaction) # collect all multisig addresses multisig_addresses = [ UnlockHash.from_json(obj=uh) for uh in resp.get_or('multisigaddresses', None) or [] ] for addr in multisig_addresses: if addr.uhtype.__ne__(UnlockHashType.MULTI_SIG): raise tferrors.ExplorerInvalidResponse( "invalid unlock hash type {} for MultiSignature Address (expected: 3)" .format(addr.uhtype.value), endpoint, resp) erc20_info = None if 'erc20info' in resp: info = resp['erc20info'] erc20_info = ERC20AddressInfo( address_tft=UnlockHash.from_json(info['tftaddress']), address_erc20=ERC20Address.from_json( info['erc20address']), confirmations=int(info['confirmations']), ) # sort the transactions by height def txn_arr_sort(a, b): height_a = pow(2, 64) if a.height < 0 else a.height height_b = pow(2, 64) if b.height < 0 else b.height if height_a < height_b: return -1 if height_a > height_b: return 1 tx_order_a = pow( 2, 64) if a.transaction_order < 0 else a.transaction_order tx_order_b = pow( 2, 64) if b.transaction_order < 0 else b.transaction_order if tx_order_a < tx_order_b: return -1 if tx_order_a > tx_order_b: return 1 return 0 transactions = jsarr.sort(transactions, txn_arr_sort, reverse=True) # return explorer data for the unlockhash return ExplorerUnlockhashResult( unlockhash=UnlockHash.from_json(unlockhash), transactions=transactions, multisig_addresses=multisig_addresses, erc20_info=erc20_info, ) except KeyError as exc: # return a KeyError as an invalid Explorer Response raise tferrors.ExplorerInvalidResponse(str(exc), endpoint, resp) from exc