Ejemplo n.º 1
0
 def query_utxo_set(self, txout, includeconf=False):
     if not isinstance(txout, list):
         txout = [txout]
     txids = [h[:64] for h in txout]
     txids = list(set(txids))  # remove duplicates
     # self.BLOCKR_MAX_ADDR_REQ_COUNT = 2
     if len(txids) > self.BLOCKR_MAX_ADDR_REQ_COUNT:
         txids = chunks(txids, self.BLOCKR_MAX_ADDR_REQ_COUNT)
     else:
         txids = [txids]
     data = []
     for ids in txids:
         blockr_url = 'https://' + self.blockr_domain + '.blockr.io/api/v1/tx/info/'
         blockr_data = btc.make_request_blockr(blockr_url + ','.join(
             ids))['data']
         if not isinstance(blockr_data, list):
             blockr_data = [blockr_data]
         data += blockr_data
     result = []
     for txo in txout:
         txdata = [d for d in data if d['tx'] == txo[:64]][0]
         vout = [v for v in txdata['vouts'] if v['n'] == int(txo[65:])][0]
         if "is_spent" in vout and vout['is_spent'] == 1:
             result.append(None)
         else:
             result_dict = {'value': int(Decimal(vout['amount']) * Decimal(
                 '1e8')),
                            'address': vout['address'],
                            'script': vout['extras']['script']}
             if includeconf:
                 result_dict['confirms'] = int(txdata['confirmations'])
             result.append(result_dict)
     return result
Ejemplo n.º 2
0
    def sync_addresses(self, wallet):
        log.info('downloading wallet history')
        # sets Wallet internal indexes to be at the next unused address
        for mix_depth in range(wallet.max_mix_depth):
            for forchange in [0, 1]:
                unused_addr_count = 0
                last_used_addr = ''
                while (unused_addr_count < wallet.gaplimit or
                       not is_index_ahead_of_cache(wallet, mix_depth,
                                                   forchange)):
                    addrs = [wallet.get_new_addr(mix_depth, forchange)
                             for _ in range(self.BLOCKR_MAX_ADDR_REQ_COUNT)]

                    # TODO send a pull request to pybitcointools
                    # because this surely should be possible with a function from it
                    blockr_url = 'https://' + self.blockr_domain
                    blockr_url += '.blockr.io/api/v1/address/txs/'

                    data = btc.make_request_blockr(blockr_url + ','.join(addrs))['data']
                    for dat in data:
                        if dat['nb_txs'] != 0:
                            last_used_addr = dat['address']
                            unused_addr_count = 0
                        else:
                            unused_addr_count += 1
                if last_used_addr == '':
                    wallet.index[mix_depth][forchange] = 0
                else:
                    next_avail_idx = max([wallet.addr_cache[last_used_addr][
                        2] + 1, wallet.index_cache[mix_depth][forchange]])
                    wallet.index[mix_depth][forchange] = next_avail_idx
Ejemplo n.º 3
0
    def sync_unspent(self, wallet):
        # finds utxos in the wallet
        st = time.time()
        # dont refresh unspent dict more often than 10 minutes
        rate_limit_time = 10 * 60
        if st - self.last_sync_unspent < rate_limit_time:
            log.info(
                'blockr sync_unspent() happened too recently (%dsec), skipping'
                % (st - self.last_sync_unspent))
            return
        wallet.unspent = {}

        addrs = wallet.addr_cache.keys()
        if len(addrs) == 0:
            log.info('no tx used')
            return
        i = 0
        while i < len(addrs):
            inc = min(len(addrs) - i, self.BLOCKR_MAX_ADDR_REQ_COUNT)
            req = addrs[i:i + inc]
            i += inc

            # TODO send a pull request to pybitcointools
            # unspent() doesnt tell you which address, you get a bunch of utxos
            # but dont know which privkey to sign with

            blockr_url = 'https://' + self.blockr_domain + \
                         '.blockr.io/api/v1/address/unspent/'
            data = btc.make_request_blockr(blockr_url + ','.join(req))['data']
            if 'unspent' in data:
                data = [data]
            for dat in data:
                for u in dat['unspent']:
                    wallet.unspent[u['tx'] + ':' + str(u['n'])] = {
                        'address': dat['address'],
                        'value': int(u['amount'].replace('.', ''))
                    }
        for u in wallet.spent_utxos:
            wallet.unspent.pop(u, None)

        self.last_sync_unspent = time.time()
        log.debug('blockr sync_unspent took ' + str((self.last_sync_unspent - st
                                                    )) + 'sec')
Ejemplo n.º 4
0
def test_blockr_error_429(make_request):
    error = {
        u'code': 429,
        u'data': None,
        u'message': u'Too many requests. Wait a bit...',
        u'status': u'error'
    }
    success = {
        u'code': 200,
        u'data': {
            u'address':
            u'mqG1k82TDWfxSYFyDRkomjYonDUYjPRbsb',
            u'limit_txs':
            200,
            u'nb_txs':
            1,
            u'nb_txs_displayed':
            1,
            u'txs': [{
                u'amount':
                1,
                u'amount_multisig':
                0,
                u'confirmations':
                400,
                u'time_utc':
                u'2016-09-15T19:46:14Z',
                u'tx':
                u'6a1bfbdd011cbb2ab2a000d477bd6372150238b4c24e43a850220dba4dbf2c0d'
            }]
        },
        u'message': u'',
        u'status': u'success'
    }
    make_request.side_effect = map(json.dumps, [error] * 3 + [success])

    d = btc.make_request_blockr(blockr_root_url + "address/txs/",
                                "mqG1k82TDWfxSYFyDRkomjYonDUYjPRbsb")
    assert d['code'] == 200
    assert d['data'] is not None
Ejemplo n.º 5
0
def test_blockr_error_429(make_request):
    error = {u'code': 429,
             u'data': None,
             u'message': u'Too many requests. Wait a bit...',
             u'status': u'error'}
    success = {u'code': 200,
               u'data': {u'address': u'mqG1k82TDWfxSYFyDRkomjYonDUYjPRbsb',
                         u'limit_txs': 200,
                         u'nb_txs': 1,
                         u'nb_txs_displayed': 1,
                         u'txs': [{u'amount': 1,
                                   u'amount_multisig': 0,
                                   u'confirmations': 400,
                                   u'time_utc': u'2016-09-15T19:46:14Z',
                                   u'tx': u'6a1bfbdd011cbb2ab2a000d477bd6372150238b4c24e43a850220dba4dbf2c0d'}]},
               u'message': u'',
               u'status': u'success'}
    make_request.side_effect = map(json.dumps, [error]*3 + [success])

    d = btc.make_request_blockr(blockr_root_url + "address/txs/", "mqG1k82TDWfxSYFyDRkomjYonDUYjPRbsb")
    assert d['code'] == 200
    assert d['data'] is not None
Ejemplo n.º 6
0
def test_blockr_bad_request():
    with pytest.raises(Exception) as e_info:
        btc.make_request_blockr(blockr_root_url+"address/txs/", "0000")
Ejemplo n.º 7
0
def test_blockr_bad_request():
    with pytest.raises(Exception) as e_info:
        btc.make_request_blockr(blockr_root_url + "address/txs/", "0000")
Ejemplo n.º 8
0
            def run(self):
                st = int(time.time())
                unconfirmed_txid = None
                unconfirmed_txhex = None
                while not unconfirmed_txid:
                    time.sleep(unconfirm_poll_period)
                    if int(time.time()) - st > unconfirm_timeout:
                        log.warn('checking for unconfirmed tx timed out')
                        if self.timeoutfun:
                            self.timeoutfun(False)
                        return
                    blockr_url = 'https://' + self.blockr_domain
                    blockr_url += '.blockr.io/api/v1/address/unspent/'
                    random.shuffle(self.output_addresses
                                  )  # seriously weird bug with blockr.io
                    data = btc.make_request_blockr(blockr_url + ','.join(
                        self.output_addresses) + '?unconfirmed=1')['data']

                    shared_txid = None
                    for unspent_list in data:
                        txs = set([str(txdata['tx'])
                                   for txdata in unspent_list['unspent']])
                        if not shared_txid:
                            shared_txid = txs
                        else:
                            shared_txid = shared_txid.intersection(txs)
                    log.info('sharedtxid = ' + str(shared_txid))
                    if len(shared_txid) == 0:
                        continue
                    time.sleep(
                        2
                    )  # here for some race condition bullshit with blockr.io
                    blockr_url = 'https://' + self.blockr_domain
                    blockr_url += '.blockr.io/api/v1/tx/raw/'
                    data = btc.make_request_blockr(blockr_url + ','.join(
                        shared_txid))['data']
                    if not isinstance(data, list):
                        data = [data]
                    for txinfo in data:
                        txhex = str(txinfo['tx']['hex'])
                        outs = set([(sv['script'], sv['value'])
                                    for sv in btc.deserialize(txhex)['outs']])
                        log.debug('unconfirm query outs = ' + str(outs))
                        if outs == self.tx_output_set:
                            unconfirmed_txid = txinfo['tx']['txid']
                            unconfirmed_txhex = str(txinfo['tx']['hex'])
                            break

                self.unconfirmfun(
                    btc.deserialize(unconfirmed_txhex), unconfirmed_txid)

                st = int(time.time())
                confirmed_txid = None
                confirmed_txhex = None
                while not confirmed_txid:
                    time.sleep(confirm_poll_period)
                    if int(time.time()) - st > confirm_timeout:
                        log.warn('checking for confirmed tx timed out')
                        if self.timeoutfun:
                            self.timeoutfun(True)
                        return
                    blockr_url = 'https://' + self.blockr_domain
                    blockr_url += '.blockr.io/api/v1/address/txs/'
                    data = btc.make_request_blockr(blockr_url + ','.join(
                        self.output_addresses))['data']
                    shared_txid = None
                    for addrtxs in data:
                        txs = set(str(txdata['tx'])
                                  for txdata in addrtxs['txs'])
                        if not shared_txid:
                            shared_txid = txs
                        else:
                            shared_txid = shared_txid.intersection(txs)
                    log.info('sharedtxid = ' + str(shared_txid))
                    if len(shared_txid) == 0:
                        continue
                    blockr_url = 'https://' + self.blockr_domain
                    blockr_url += '.blockr.io/api/v1/tx/raw/'
                    data = btc.make_request_blockr(blockr_url + ','.join(
                        shared_txid))['data']
                    if not isinstance(data, list):
                        data = [data]
                    for txinfo in data:
                        txhex = str(txinfo['tx']['hex'])
                        outs = set([(sv['script'], sv['value'])
                                    for sv in btc.deserialize(txhex)['outs']])
                        log.debug('confirm query outs = ' + str(outs))
                        if outs == self.tx_output_set:
                            confirmed_txid = txinfo['tx']['txid']
                            confirmed_txhex = str(txinfo['tx']['hex'])
                            break
                self.confirmfun(
                    btc.deserialize(confirmed_txhex), confirmed_txid, 1)