Exemple #1
0
 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
Exemple #2
0
 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
Exemple #3
0
 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)
Exemple #4
0
 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
Exemple #5
0
 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
Exemple #6
0
 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
Exemple #7
0
 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
Exemple #8
0
 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
Exemple #9
0
 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
Exemple #10
0
        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