コード例 #1
0
    def get_transaction(self, txid):
        url = '{api_url}/tx/{txid}?verbose=3'.format(api_url=self.url,
                                                     txid=txid)
        try:
            LOG.info('GET %s' % url)
            r = requests.get(url)
            data = r.json()
        except Exception as ex:
            LOG.error('Unable to get transaction %s from BTC.com: %s' %
                      (txid, ex))
            return {
                'error': 'Unable to get transaction %s from BTC.com' % txid
            }

        data = data['data'] if data['data'] is not None else {}

        # todo check key names , test by setting testnet wrong on explorers
        tx = TX()
        tx.txid = txid
        tx.wtxid = data['witness_hash']
        tx.lock_time = data['lock_time']
        tx.block_height = data[
            'block_height'] if 'block_height' in data and data[
                'block_height'] != -1 else None
        tx.confirmations = data[
            'confirmations'] if 'confirmations' in data else None

        for item in data['inputs']:
            tx_input = TxInput()
            tx_input.address = item['prev_addresses'][0] if len(
                item['prev_addresses']) > 0 else None
            tx_input.value = item['prev_value']
            tx_input.txid = item['prev_tx_hash']
            tx_input.n = item['prev_position'] if item[
                'prev_position'] is not -1 else None
            tx_input.script = item['script_hex']
            tx_input.sequence = item['sequence']

            tx.inputs.append(tx_input)

        for i, item in enumerate(data['outputs']):
            tx_output = TxOutput()
            tx_output.address = item['addresses'][0] if len(
                item['addresses']) > 0 else None
            tx_output.value = item['value']
            tx_output.n = i
            tx_output.spent = False if item['spent_by_tx'] is None else True
            tx_output.script = item['script_hex']

            if item['script_hex'][:2] == '6a':
                tx_output.op_return = tx.decode_op_return(item['script_hex'])

            tx.outputs.append(tx_output)

        return {'transaction': tx.json_encodable()}
コード例 #2
0
    def test_op_return_script_with_strings_of_various_lengths(self):

        for x in range(1, 81):
            message = 'a' * x

            script = op_return_script(hex_data=binascii.hexlify(message.encode()).decode())
            print(message)
            print(script)

            assert TX().decode_op_return(hex_data=script) == message
コード例 #3
0
    def get_transaction(self, txid):
        url = self.url + '/tx/' + str(txid)
        try:
            LOG.info('GET %s' % url)
            r = requests.get(url)
            data = r.json()
        except Exception as ex:
            LOG.error('Unable to get transaction %s from %s: %s' %
                      (txid, self.url, ex))
            return {
                'error':
                'Unable to get transaction %s from %s' % (txid, self.url)
            }

        tx = TX()
        tx.txid = txid
        tx.block_height = data['blockheight'] if 'blockheight' in data else None
        tx.lock_time = data['locktime']

        for item in data['vin']:
            tx_input = TxInput()
            tx_input.address = item['addr'] if 'addr' in item else None
            tx_input.value = item['valueSat'] if 'valueSat' in item else 0
            tx_input.txid = item['txid'] if 'txid' in item else None
            tx_input.n = item['n'] if 'coinbase' not in item else None
            tx_input.script = item['scriptSig'][
                'hex'] if 'scriptSig' in item else None
            if 'coinbase' in item:
                tx_input.script = item['coinbase']
            tx_input.sequence = item['sequence']

            tx.inputs.append(tx_input)

        for item in data['vout']:
            tx_output = TxOutput()
            tx_output.address = item['scriptPubKey']['addresses'][
                0] if 'addresses' in item['scriptPubKey'] else None
            tx_output.value = int(float(item['value']) * 1e8)
            tx_output.n = item['n']
            tx_output.spent = True if 'spentTxId' in item and item[
                'spentTxId'] is not None else False
            tx_output.script = item['scriptPubKey']['hex']
            if item['scriptPubKey']['hex'][:2] == '6a':
                tx_output.op_return = tx.decode_op_return(
                    item['scriptPubKey']['hex'])

            tx.outputs.append(tx_output)

        tx.confirmations = data[
            'confirmations'] if 'confirmations' in data else None

        return {'transaction': tx.json_encodable()}
コード例 #4
0
    def test_op_return_script_with_random_string(self):

        for x in range(10000):
            print('')
            random_length = randint(1, 81)
            random_string = "".join(choice('abcdefghijklmnopqrstuvwxyz') for i in range(random_length))

            script = op_return_script(hex_data=binascii.hexlify(random_string.encode()).decode())
            print(random_string)
            print(script)

            assert TX().decode_op_return(hex_data=script) == random_string
コード例 #5
0
    def get_transaction(self, txid):
        url = '{api_url}/rawtx/{txid}'.format(api_url=self.url, txid=txid)
        try:
            LOG.info('GET %s' % url)
            r = requests.get(url)
            data = r.json()
        except Exception as ex:
            LOG.error('Unable to get tx %s from Blockchain.info: %s' %
                      (txid, ex))
            return {'error': 'Unable to get tx %s from Blockchain.info' % txid}

        tx = TX()
        tx.txid = txid
        tx.lock_time = data['lock_time']
        tx.block_height = data[
            'block_height'] if 'block_height' in data else None
        tx.confirmations = self.get_latest_block_height(
        ) - tx.block_height + 1 if tx.block_height is not None else 0

        for item in data['inputs']:
            tx_input = TxInput()
            tx_input.address = item['prev_out'][
                'addr'] if 'prev_out' in item else None
            tx_input.value = item['prev_out'][
                'value'] if 'prev_out' in item else 0
            tx_input.n = item['prev_out']['n'] if 'prev_out' in item else None
            tx_input.txid = ''  # Blockchain.info does not provide the txid of a tx input only their own tx_index, can be resolved for example via https://testnet.blockchain.info/tx-index/197277768?format=json but this would require too many http requests!!!
            tx_input.script = item['script']
            tx_input.sequence = item['sequence']

            tx.inputs.append(tx_input)

        for item in data['out']:
            tx_output = TxOutput()
            tx_output.address = item['addr'] if 'addr' in item else None
            tx_output.value = item['value']
            tx_output.n = item['n']
            tx_output.spent = item['spent']
            tx_output.script = item['script']
            if item['script'][:2] == '6a':
                tx_output.op_return = tx.decode_op_return(item['script'])

            tx.outputs.append(tx_output)

        return {'transaction': tx.json_encodable()}
コード例 #6
0
    def parse_transaction(self, data, latest_block_height=None):
        if latest_block_height is None:
            url = self.url + '/blocks/tip/height'
            LOG.info('GET %s' % url)
            try:
                r = requests.get(url)
                latest_block_height = int(r.text)
            except Exception as ex:
                LOG.error(
                    'Unable to get latest block_height from Blockstream.info: %s'
                    % ex)
                return {
                    'error':
                    'Unable to get latest block_height from Blockstream.info'
                }

        tx = TX()
        tx.txid = data['txid']
        tx.lock_time = data['locktime']
        tx.block_height = data['status'][
            'block_height'] if 'block_height' in data['status'] else None
        tx.confirmations = latest_block_height - tx.block_height + 1 if tx.block_height is not None else 0

        for item in data['vin']:
            tx_input = TxInput()
            tx_input.address = item['prevout']['scriptpubkey_address'] if item[
                'prevout'] is not None else None
            tx_input.value = item['prevout']['value'] if item[
                'prevout'] is not None else 0
            tx_input.n = item['vout'] if item['is_coinbase'] is False else None
            tx_input.txid = item['txid']
            tx_input.script = item['scriptsig']
            tx_input.sequence = item['sequence']

            tx.inputs.append(tx_input)

        for i, item in enumerate(data['vout']):
            tx_output = TxOutput()
            tx_output.address = item[
                'scriptpubkey_address'] if 'scriptpubkey_address' in item else None
            tx_output.value = item['value']
            tx_output.n = i
            tx_output.spent = None  # Blockstream does not provide information if a tx output has been spent
            tx_output.script = item['scriptpubkey']
            if item['scriptpubkey'][:2] == '6a':
                tx_output.op_return = tx.decode_op_return(item['scriptpubkey'])

            tx.outputs.append(tx_output)

        return tx
コード例 #7
0
    def get_transactions(self, address):
        limit = 10  # number of tx given by insight is 10
        n_tx = None
        transactions = []

        i = 0
        while n_tx is None or len(transactions) < n_tx:
            url = self.url + '/addrs/' + address + '/txs?from=' + str(
                limit * i) + '&to=' + str(limit * (i + 1))
            try:
                LOG.info('GET %s' % url)
                r = requests.get(url)
                data = r.json()
            except Exception as ex:
                LOG.error(
                    'Unable to get transactions of address %s from %s: %s' %
                    (address, url, ex))
                return {
                    'error':
                    'Unable to get transactions of address %s from %s' %
                    (address, url)
                }

            if all(key in data for key in ('totalItems', 'items')):
                n_tx = data['totalItems']
                transactions += data['items']
                i += 1
            else:
                return {'error': 'Received Invalid data: %s' % data}

        txs = []
        for transaction in transactions:
            tx = TX()
            tx.txid = transaction['txid']
            tx.lock_time = transaction['locktime']
            tx.confirmations = transaction['confirmations']
            tx.block_height = transaction['blockheight']

            for item in transaction['vin']:
                tx_input = TxInput()
                tx_input.address = item['addr'] if 'addr' in item else None
                tx_input.value = item['valueSat'] if 'value' in item else 0
                tx_input.txid = item['txid'] if 'txid' in item else None
                tx_input.n = item['vout'] if 'coinbase' not in item else None
                tx_input.script = item['scriptSig'][
                    'hex'] if 'scriptSig' in item else None
                if 'coinbase' in item:
                    tx_input.script = item['coinbase']
                tx_input.sequence = item['sequence']

                tx.inputs.append(tx_input)

            for item in transaction['vout']:
                tx_output = TxOutput()
                tx_output.address = item['scriptPubKey']['addresses'][
                    0] if 'addresses' in item['scriptPubKey'] else None
                tx_output.value = int(
                    int(item['value'][:-9]) * 1e8 + int(item['value'][-8:]))
                tx_output.n = item['n']
                tx_output.spent = True if 'spentTxId' in item and item[
                    'spentTxId'] is not None else False
                tx_output.script = item['scriptPubKey']['hex']
                if item['scriptPubKey']['hex'][:2] == '6a':
                    tx_output.op_return = tx.decode_op_return(
                        item['scriptPubKey']['hex'])

                tx.outputs.append(tx_output)

            # Only add confirmed txs
            if tx.block_height != -1:
                txs.insert(0, tx.to_dict(address))
            else:
                # subtract 1 from total txs because it is unconfirmed
                n_tx -= 1

        if n_tx != len(txs):
            return {
                'error':
                'Not all transactions are retrieved! expected {expected} but only got {received}'
                .format(expected=n_tx, received=len(txs))
            }
        else:
            return {'transactions': txs}
コード例 #8
0
    def get_transactions(self, address):
        pagesize = 50  # max 50 for BTC.com
        n_tx = None
        transactions = []
        page = 1

        while n_tx is None or len(transactions) < n_tx:
            url = '{api_url}/address/{address}/tx?page={page}&pagesize={pagesize}&verbose=3'.format(
                api_url=self.url,
                address=address,
                page=page,
                pagesize=pagesize)
            try:
                LOG.info('GET %s' % url)
                r = requests.get(url)
                data = r.json()
            except Exception as ex:
                LOG.error(
                    'Unable to get transactions of address %s from BTC.com: %s'
                    % (address, ex))
                return {
                    'error':
                    'Unable to get transactions of address %s from BTC.com' %
                    address
                }

            data = data['data'] if data['data'] is not None else {}

            if all(key in data for key in ('total_count', 'list')):
                n_tx = data['total_count']
                transactions += data['list']
                page += 1
            else:
                return {'error': 'Received invalid data: %s' % data}

            if len(transactions) < n_tx:
                sleep(1)

        txs = []
        for transaction in transactions:
            tx = TX()
            tx.txid = transaction['hash']
            tx.block_height = transaction['block_height']
            tx.confirmations = transaction['confirmations']
            tx.wtxid = transaction['witness_hash']
            tx.lock_time = transaction['lock_time']

            for item in transaction['inputs']:
                tx_input = TxInput()
                tx_input.address = item['prev_addresses'][0] if len(
                    item['prev_addresses']) > 0 else None
                tx_input.value = item['prev_value']
                tx_input.txid = item['prev_tx_hash']
                tx_input.n = item['prev_position'] if item[
                    'prev_position'] is not -1 else None
                tx_input.script = item['script_hex']
                tx_input.sequence = item['sequence']

                tx.inputs.append(tx_input)

            for i, item in enumerate(transaction['outputs']):
                tx_output = TxOutput()
                tx_output.address = item['addresses'][0] if len(
                    item['addresses']) > 0 else None
                tx_output.value = item['value']
                tx_output.n = i
                tx_output.spent = False if item['spent_by_tx'] is None else True
                tx_output.script = item['script_hex']

                if item['script_hex'][:2] == '6a':
                    tx_output.op_return = tx.decode_op_return(
                        item['script_hex'])

                tx.outputs.append(tx_output)

            # Only append confirmed transactions
            if tx.block_height is not -1:
                txs.append(tx.to_dict(address))
            else:
                # subtract 1 from total txs because it is unconfirmed
                n_tx -= 1

        if n_tx != len(txs):
            return {
                'error':
                'BTC.com: Not all transactions are retrieved! expected {expected} but only got {received}'
                .format(expected=n_tx, received=len(txs))
            }
        else:
            return {'transactions': txs}
コード例 #9
0
    def get_transactions(self, address):
        limit = 50  # max number of tx given by blockchain.info is 50
        n_tx = None
        transactions = []
        latest_block_height = self.get_latest_block_height()
        if latest_block_height is None:
            return {'error': 'Unable to get latest block height'}

        i = 0
        while n_tx is None or len(transactions) < n_tx:
            url = '{api_url}/address/{address}?format=json&limit={limit}&offset={offset}'.format(
                api_url=self.url,
                address=address,
                limit=limit,
                offset=limit * i)
            try:
                LOG.info('GET %s' % url)
                r = requests.get(url)
                data = r.json()
            except Exception as ex:
                LOG.error(
                    'Unable to get transactions of address %s from %s: %s' %
                    (address, url, ex))
                return {
                    'error':
                    'Unable to get transactions of address %s from %s' %
                    (address, url)
                }

            if all(key in data for key in ('n_tx', 'txs')):
                n_tx = data['n_tx']
                transactions += data['txs']
                i += 1
            else:
                return {'error': 'Received Invalid data: %s' % data}

            if len(transactions) < n_tx:
                sleep(1)

        txs = []
        for transaction in transactions:
            tx = TX()
            tx.txid = transaction['hash']
            tx.lock_time = transaction['lock_time']
            tx.block_height = transaction[
                'block_height'] if 'block_height' in transaction else None
            tx.confirmations = (latest_block_height - tx.block_height
                                ) + 1 if 'block_height' in transaction else 0

            for item in transaction['inputs']:
                tx_input = TxInput()
                tx_input.address = item['prev_out'][
                    'addr'] if 'prev_out' in item else None
                tx_input.value = item['prev_out'][
                    'value'] if 'prev_out' in item else 0
                tx_input.txid = ''  # Blockchain.info does not provide the txid of a tx input only their own tx_index, can be resolved for example via https://testnet.blockchain.info/tx-index/197277768?format=json but this would require too many http requests!!!
                tx_input.n = item['prev_out'][
                    'n'] if 'prev_out' in item else None
                tx_input.script = item['script']
                tx_input.sequence = item['sequence']

                tx.inputs.append(tx_input)

            for item in transaction['out']:
                tx_output = TxOutput()
                tx_output.address = item['addr'] if 'addr' in item else None
                tx_output.value = item['value']
                tx_output.n = item['n']
                tx_output.spent = item['spent']
                tx_output.script = item['script']
                if item['script'][:2] == '6a':
                    tx_output.op_return = tx.decode_op_return(item['script'])

                tx.outputs.append(tx_output)

            # Only append confirmed transactions
            if tx.block_height is not None:
                txs.insert(0, tx.to_dict(address))
            else:
                # subtract 1 from total txs because it is unconfirmed
                n_tx -= 1

        if n_tx != len(txs):
            return {
                'error':
                'Not all transactions are retrieved! expected {expected} but only got {received}'
                .format(expected=n_tx, received=len(txs))
            }
        else:
            return {'transactions': txs}
コード例 #10
0
    def get_transaction(self, txid):
        url = '{api_url}/get_tx/{network}/{txid}'.format(api_url=self.url,
                                                         network=self.network,
                                                         txid=txid)
        try:
            LOG.info('GET %s' % url)
            r = requests.get(url)
            data = r.json()
        except Exception as ex:
            LOG.error('Unable to get transaction %s from Chain.so: %s' %
                      (txid, ex))
            return {
                'error': 'Unable to get transaction %s from Chain.so' % txid
            }

        if 'data' not in data:
            LOG.error('Invalid response data from Chain.so: %s' % data)
            return {'error': 'Invalid response data from Chain.so: %s' % data}

        data = data['data']

        tx = TX()
        tx.txid = txid

        block_data = self.get_block_by_hash(block_hash=data['blockhash'])
        if not ('block' in block_data and 'height' in block_data['block']):
            LOG.error(
                'Unable to get block %s to get the block height from chain.so'
                % data['blockhash'])
            return {
                'error':
                'Unable to get block %s to get the block height from chain.so'
                % data['blockhash']
            }

        tx.block_height = block_data['block']['height']
        tx.confirmations = data['confirmations']

        for item in data['inputs']:
            tx_input = TxInput()
            tx_input.address = item[
                'address'] if item['address'] != 'coinbase' else None
            tx_input.value = btc2satoshis(
                btc=item['value']) if item['address'] != 'coinbase' else 0
            tx_input.n = item['from_output']['output_no'] if item[
                'from_output'] is not None else None
            tx_input.txid = item['from_output']['txid'] if item[
                'from_output'] is not None else None
            tx_input.script = item['script']
            tx_input.sequence = None  # Chain.so does not provide the sequence

            tx.inputs.append(tx_input)

        for item in data['outputs']:
            tx_output = TxOutput()
            tx_output.address = item[
                'address'] if item['address'] != 'nonstandard' else None
            tx_output.value = btc2satoshis(btc=item['value'])
            tx_output.n = item['output_no']
            tx_output.spent = None  # Chain.so does not provide information if an output has been spent already or not
            tx_output.script = item['script']
            if item['script'][:10] == 'OP_RETURN ':
                tx_output.op_return = binascii.unhexlify(tx_output.script[10:])

                # Sometimes the unhexed data is encoded in another coded than utf-8 which could cause problems when converting to json later
                try:
                    tx_output.op_return = tx_output.op_return.decode('utf-8')
                except UnicodeDecodeError:
                    try:
                        tx_output.op_return = tx_output.op_return.decode(
                            'cp1252')
                    except Exception as ex:
                        LOG.error(
                            'Unable to decode OP_RETURN data %s in utf-8 or cp1252: %s'
                            % (tx_output.op_return, ex))
                        tx_output.op_return = 'Unable to decode hex data'

            tx.outputs.append(tx_output)

        return {'transaction': tx.json_encodable()}