Skip to content

Commit

Permalink
added update_cache_index() code, which stores the pointers of the add…
Browse files Browse the repository at this point in the history
…resses we're up to in the HD wallet
  • Loading branch information
chris-belcher committed May 19, 2015
1 parent e0c0317 commit b3dc7c7
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 17 deletions.
26 changes: 14 additions & 12 deletions lib/blockchaininterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ class BlockchainInterface(object):
def __init__(self):
pass

def sync_wallet(self, wallet, gaplimit=6):
self.sync_addresses(wallet, gaplimit)
def sync_wallet(self, wallet):
self.sync_addresses(wallet)
self.sync_unspent(wallet)

@abc.abstractmethod
def sync_addresses(self, wallet, gaplimit=6):
def sync_addresses(self, wallet):
'''Finds which addresses have been used and sets wallet.index appropriately'''
pass

Expand Down Expand Up @@ -69,28 +69,31 @@ def __init__(self, testnet = False):
self.blockr_domain = 'tbtc' if testnet else 'btc'
self.last_sync_unspent = 0

def sync_addresses(self, wallet, gaplimit=6):
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 < gaplimit:
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 unused_addr_count >= gaplimit:
break
if last_used_addr == '':
wallet.index[mix_depth][forchange] = 0
else:
Expand Down Expand Up @@ -365,7 +368,7 @@ def add_watchonly_addresses(self, addr_list, wallet_name):
print 'now restart bitcoind with -rescan'
sys.exit(0)

def sync_addresses(self, wallet, gaplimit=6):
def sync_addresses(self, wallet):
common.debug('requesting wallet history')
wallet_name = self.get_wallet_name(wallet)
addr_req_count = 50
Expand All @@ -392,7 +395,8 @@ def sync_addresses(self, wallet, gaplimit=6):
last_used_addr = ''
breakloop = False
while not breakloop:
if unused_addr_count >= gaplimit:
if unused_addr_count >= wallet.gaplimit and\
wallet.index[mix_depth][forchange] >= wallet.index_cache[mix_depth][forchange]:
break
mix_change_addrs = [wallet.get_new_addr(mix_depth, forchange) for i in range(addr_req_count)]
for mc_addr in mix_change_addrs:
Expand All @@ -402,11 +406,9 @@ def sync_addresses(self, wallet, gaplimit=6):
break
if mc_addr in used_addr_list:
last_used_addr = mc_addr
unused_addr_count = 0
else:
unused_addr_count += 1
if unused_addr_count >= gaplimit:
breakloop = True
break

if last_used_addr == '':
wallet.index[mix_depth][forchange] = 0
Expand Down
29 changes: 26 additions & 3 deletions lib/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,11 @@ def debug_dump_object(obj, skip_fields=[]):
debug(str(v))

class Wallet(object):
def __init__(self, seedarg, max_mix_depth=2):
def __init__(self, seedarg, max_mix_depth=2, gaplimit=6):
self.max_mix_depth = max_mix_depth
self.seed = self.get_seed(seedarg)
master = btc.bip32_master_key(self.seed)
self.gaplimit = gaplimit
seed = self.get_seed(seedarg)
master = btc.bip32_master_key(seed)
m_0 = btc.bip32_ckd(master, 0)
mixing_depth_keys = [btc.bip32_ckd(m_0, c) for c in range(max_mix_depth)]
self.keys = [(btc.bip32_ckd(m, 0), btc.bip32_ckd(m, 1)) for m in mixing_depth_keys]
Expand All @@ -123,6 +124,8 @@ def __init__(self, seedarg, max_mix_depth=2):
self.spent_utxos = []

def get_seed(self, seedarg):
self.path = None
self.index_cache = [[0, 0]]*self.max_mix_depth
path = os.path.join('wallets', seedarg)
if not os.path.isfile(path):
if get_network() == 'testnet':
Expand All @@ -131,6 +134,7 @@ def get_seed(self, seedarg):
else:
raise IOError('wallet file not found')
#debug('seedarg interpreted as wallet file name')
self.path = path
try:
import aes
except ImportError:
Expand All @@ -144,12 +148,30 @@ def get_seed(self, seedarg):
print 'wallet network(%s) does not match joinmarket configured network(%s)' % (
walletdata['network'], get_network())
sys.exit(0)
if 'index_cache' in walletdata:
self.index_cache = walletdata['index_cache']
print 'index cache = ' + str(self.index_cache)
password = getpass.getpass('Enter wallet decryption passphrase: ')
password_key = btc.bin_dbl_sha256(password)
decrypted_seed = aes.decryptData(password_key, walletdata['encrypted_seed']
.decode('hex')).encode('hex')
return decrypted_seed

def update_cache_index(self):
if not self.path:
return
if not os.path.isfile(self.path):
return
fd = open(self.path, 'r')
walletfile = fd.read()
fd.close()
walletdata = json.loads(walletfile)
walletdata['index_cache'] = self.index
walletfile = json.dumps(walletdata)
fd = open(self.path, 'w')
fd.write(walletfile)
fd.close()

def get_key(self, mixing_depth, forchange, i):
return btc.bip32_extract_key(btc.bip32_ckd(self.keys[mixing_depth][forchange], i))

Expand All @@ -161,6 +183,7 @@ def get_new_addr(self, mixing_depth, forchange):
addr = self.get_addr(mixing_depth, forchange, index[forchange])
self.addr_cache[addr] = (mixing_depth, forchange, index[forchange])
index[forchange] += 1
#self.update_cache_index()
return addr

def get_receive_addr(self, mixing_depth):
Expand Down
1 change: 1 addition & 0 deletions lib/maker.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def __init__(self, maker, nick, oid, amount, taker_pk):
self.cjfee = order['cjfee']
debug('new cjorder nick=%s oid=%d amount=%d' % (nick, oid, amount))
self.utxos, self.cj_addr, self.change_addr = maker.oid_to_order(self, oid, amount)
self.maker.wallet.update_cache_index()
if not self.utxos:
self.maker.msgchan.send_error(nick, 'unable to fill order constrained by dust avoidance')
#TODO make up orders offers in a way that this error cant appear
Expand Down
4 changes: 2 additions & 2 deletions wallet-tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@
else:
seed = args[0]
method = ('display' if len(args) == 1 else args[1].lower())
wallet = Wallet(seed, options.maxmixdepth)
wallet = Wallet(seed, options.maxmixdepth, options.gaplimit)
if method != 'showseed':
common.bc_interface.sync_wallet(wallet, options.gaplimit)
common.bc_interface.sync_wallet(wallet)

if method == 'display' or method == 'displayall':
total_balance = 0
Expand Down

0 comments on commit b3dc7c7

Please sign in to comment.