def sync_addresses(self, wallet): common.debug('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\ wallet.index[mix_depth][forchange] <= wallet.index_cache[mix_depth][forchange]: addrs = [wallet.get_new_addr(mix_depth, forchange) for i 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 = 'http://' + self.blockr_domain + '.blockr.io/api/v1/address/txs/' #print 'downloading, lastusedaddr = ' + last_used_addr + ' unusedaddrcount= ' + str(unused_addr_count) res = btc.make_request(blockr_url+','.join(addrs)) data = json.loads(res)['data'] for dat in data: #if forchange == 0: # print ' nbtxs ' + str(dat['nb_txs']) + ' addr=' + dat['address'] + ' unused=' + str(unused_addr_count) 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: wallet.index[mix_depth][forchange] = wallet.addr_cache[last_used_addr][2] + 1
def query_utxo_set(self, txout): 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 = common.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 = json.loads( btc.make_request(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 vout['is_spent'] == 1: result.append(None) else: result.append({ 'value': int(Decimal(vout['amount']) * Decimal('1e8')), 'address': vout['address'], 'script': vout['extras']['script'] }) return result
def sync_addresses(self, wallet): common.debug('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 i 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.io/api/v1/address/txs/' #print 'downloading, lastusedaddr = ' + last_used_addr + ' unusedaddrcount= ' + str(unused_addr_count) res = btc.make_request(blockr_url + ','.join(addrs)) data = json.loads(res)['data'] for dat in data: #if forchange == 0: # print ' nbtxs ' + str(dat['nb_txs']) + ' addr=' + dat['address'] + ' unused=' + str(unused_addr_count) 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: wallet.index[mix_depth][ forchange] = wallet.addr_cache[last_used_addr][2] + 1
def query_utxo_set(self, txout): 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 = json.loads( btc.make_request(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 vout['is_spent'] == 1: result.append(None) else: result.append({'value': int(Decimal(vout['amount']) * Decimal( '1e8')), 'address': vout['address'], 'script': vout['extras']['script']}) return result
def sync_addresses(self, wallet): log.debug('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/' res = btc.make_request(blockr_url + ','.join(addrs)) data = json.loads(res)['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
def estimate_fee_per_kb(self, N): bcypher_fee_estimate_url = 'https://api.blockcypher.com/v1/btc/main' bcypher_data = json.loads(btc.make_request(bcypher_fee_estimate_url)) log.debug("Got blockcypher result: " + pprint.pformat(bcypher_data)) if N <= 2: fee_per_kb = bcypher_data["high_fee_per_kb"] elif N <= 4: fee_per_kb = bcypher_data["medium_fee_per_kb"] else: fee_per_kb = bcypher_data["low_fee_per_kb"] return fee_per_kb
def estimate_fee_per_kb(self, N): bcypher_fee_estimate_url = 'https://api.blockcypher.com/v1/btc/main' bcypher_data = json.loads(btc.make_request(bcypher_fee_estimate_url)) log.debug("Got blockcypher result: "+pprint.pformat(bcypher_data)) if N<=2: fee_per_kb = bcypher_data["high_fee_per_kb"] elif N <=4: fee_per_kb = bcypher_data["medium_fee_per_kb"] else: fee_per_kb = bcypher_data["low_fee_per_kb"] return fee_per_kb
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.debug( '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.debug('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/' res = btc.make_request(blockr_url + ','.join(req)) data = json.loads(res)['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')
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.debug( '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.debug('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/' res = btc.make_request(blockr_url + ','.join(req)) data = json.loads(res)['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')
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: common.debug('checking for unconfirmed tx timed out') return blockr_url = 'https://' + self.blockr_domain + '.blockr.io/api/v1/address/unspent/' random.shuffle(self.output_addresses ) #seriously weird bug with blockr.io data = json.loads( btc.make_request(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) common.debug('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.io/api/v1/tx/raw/' data = json.loads( btc.make_request(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']]) common.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: common.debug('checking for confirmed tx timed out') return blockr_url = 'https://' + self.blockr_domain + '.blockr.io/api/v1/address/txs/' data = json.loads( btc.make_request( 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) common.debug('sharedtxid = ' + str(shared_txid)) if len(shared_txid) == 0: continue blockr_url = 'https://' + self.blockr_domain + '.blockr.io/api/v1/tx/raw/' data = json.loads( btc.make_request(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']]) common.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)
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.debug('checking for unconfirmed tx timed out') 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 = json.loads( btc.make_request(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.debug('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 = json.loads(btc.make_request(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.debug('checking for confirmed tx timed out') return blockr_url = 'https://' + self.blockr_domain blockr_url += '.blockr.io/api/v1/address/txs/' data = json.loads(btc.make_request(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.debug('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 = json.loads( btc.make_request( 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)
def test_blockr_bad_request(): with pytest.raises(Exception) as e_info: btc.make_request(blockr_root_url + "address/txs/", "0000")
def test_blockr_bad_request(): with pytest.raises(Exception) as e_info: btc.make_request(blockr_root_url+"address/txs/", "0000")