move synchronize_account logic to account.py
This commit is contained in:
parent
3dc69df702
commit
0b7f8e74d5
|
@ -75,11 +75,37 @@ class Account(object):
|
||||||
def redeem_script(self, for_change, n):
|
def redeem_script(self, for_change, n):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def synchronize_sequence(self, wallet, for_change):
|
||||||
|
limit = self.gap_limit_for_change if for_change else self.gap_limit
|
||||||
|
while True:
|
||||||
|
addresses = self.get_addresses(for_change)
|
||||||
|
if len(addresses) < limit:
|
||||||
|
address = self.create_new_address(for_change)
|
||||||
|
wallet.add_address(address)
|
||||||
|
continue
|
||||||
|
if map( lambda a: wallet.address_is_old(a), addresses[-limit:] ) == limit*[False]:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
address = self.create_new_address(for_change)
|
||||||
|
wallet.add_address(address)
|
||||||
|
|
||||||
|
def synchronize(self, wallet):
|
||||||
|
self.synchronize_sequence(wallet, False)
|
||||||
|
self.synchronize_sequence(wallet, True)
|
||||||
|
|
||||||
|
|
||||||
class PendingAccount(Account):
|
class PendingAccount(Account):
|
||||||
def __init__(self, v):
|
def __init__(self, v):
|
||||||
self.pending_address = v['pending']
|
self.pending_address = v['pending']
|
||||||
|
|
||||||
|
def synchronize(self, wallet):
|
||||||
|
if wallet.address_is_old(self.pending_address):
|
||||||
|
print_error( "creating account", account_id )
|
||||||
|
xpub = wallet.master_public_keys[account_id]
|
||||||
|
account = BIP32_Account({'xpub':xpub})
|
||||||
|
wallet.add_account(account_id, account)
|
||||||
|
#self.next_addresses.pop(account_id)
|
||||||
|
|
||||||
def get_addresses(self, is_change):
|
def get_addresses(self, is_change):
|
||||||
return [self.pending_address]
|
return [self.pending_address]
|
||||||
|
|
||||||
|
@ -102,6 +128,9 @@ class ImportedAccount(Account):
|
||||||
def __init__(self, d):
|
def __init__(self, d):
|
||||||
self.keypairs = d['imported']
|
self.keypairs = d['imported']
|
||||||
|
|
||||||
|
def synchronize(self, wallet):
|
||||||
|
return
|
||||||
|
|
||||||
def get_addresses(self, for_change):
|
def get_addresses(self, for_change):
|
||||||
return [] if for_change else sorted(self.keypairs.keys())
|
return [] if for_change else sorted(self.keypairs.keys())
|
||||||
|
|
||||||
|
@ -151,6 +180,8 @@ class ImportedAccount(Account):
|
||||||
|
|
||||||
class OldAccount(Account):
|
class OldAccount(Account):
|
||||||
""" Privatekey(type,n) = Master_private_key + H(n|S|type) """
|
""" Privatekey(type,n) = Master_private_key + H(n|S|type) """
|
||||||
|
gap_limit = 5
|
||||||
|
gap_limit_for_change = 3
|
||||||
|
|
||||||
def __init__(self, v):
|
def __init__(self, v):
|
||||||
Account.__init__(self, v)
|
Account.__init__(self, v)
|
||||||
|
@ -248,6 +279,8 @@ class OldAccount(Account):
|
||||||
|
|
||||||
|
|
||||||
class BIP32_Account(Account):
|
class BIP32_Account(Account):
|
||||||
|
gap_limit = 20
|
||||||
|
gap_limit_for_change = 3
|
||||||
|
|
||||||
def __init__(self, v):
|
def __init__(self, v):
|
||||||
Account.__init__(self, v)
|
Account.__init__(self, v)
|
||||||
|
|
130
lib/wallet.py
130
lib/wallet.py
|
@ -166,8 +166,6 @@ class Abstract_Wallet(object):
|
||||||
|
|
||||||
self.fee_per_kb = int(storage.get('fee_per_kb', 10000))
|
self.fee_per_kb = int(storage.get('fee_per_kb', 10000))
|
||||||
|
|
||||||
self.next_addresses = storage.get('next_addresses',{})
|
|
||||||
|
|
||||||
# This attribute is set when wallet.start_threads is called.
|
# This attribute is set when wallet.start_threads is called.
|
||||||
self.synchronizer = None
|
self.synchronizer = None
|
||||||
|
|
||||||
|
@ -333,15 +331,10 @@ class Abstract_Wallet(object):
|
||||||
run_hook('set_label', name, text, changed)
|
run_hook('set_label', name, text, changed)
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
def addresses(self, include_change = True, _next=True):
|
def addresses(self, include_change = True):
|
||||||
o = []
|
o = []
|
||||||
for a in self.accounts.keys():
|
for a in self.accounts.keys():
|
||||||
o += self.get_account_addresses(a, include_change)
|
o += self.get_account_addresses(a, include_change)
|
||||||
|
|
||||||
if _next:
|
|
||||||
for addr in self.next_addresses.values():
|
|
||||||
if addr not in o:
|
|
||||||
o += [addr]
|
|
||||||
return o
|
return o
|
||||||
|
|
||||||
def is_mine(self, address):
|
def is_mine(self, address):
|
||||||
|
@ -360,11 +353,6 @@ class Abstract_Wallet(object):
|
||||||
for addr in addresses:
|
for addr in addresses:
|
||||||
if address == addr:
|
if address == addr:
|
||||||
return account, (for_change, addresses.index(addr))
|
return account, (for_change, addresses.index(addr))
|
||||||
|
|
||||||
for k,v in self.next_addresses.items():
|
|
||||||
if v == address:
|
|
||||||
return k, (0,0)
|
|
||||||
|
|
||||||
raise Exception("Address not found", address)
|
raise Exception("Address not found", address)
|
||||||
|
|
||||||
def get_private_key(self, address, password):
|
def get_private_key(self, address, password):
|
||||||
|
@ -1161,37 +1149,18 @@ class Deterministic_Wallet(Abstract_Wallet):
|
||||||
if account is None:
|
if account is None:
|
||||||
account = self.default_account()
|
account = self.default_account()
|
||||||
address = account.create_new_address(for_change)
|
address = account.create_new_address(for_change)
|
||||||
|
self.add_address(address)
|
||||||
|
return address
|
||||||
|
|
||||||
|
def add_address(self, address):
|
||||||
self.history[address] = []
|
self.history[address] = []
|
||||||
if self.synchronizer:
|
if self.synchronizer:
|
||||||
self.synchronizer.add(address)
|
self.synchronizer.add(address)
|
||||||
self.save_accounts()
|
self.save_accounts()
|
||||||
return address
|
|
||||||
|
|
||||||
def synchronize_sequence(self, account, for_change):
|
|
||||||
limit = self.gap_limit_for_change if for_change else self.gap_limit
|
|
||||||
while True:
|
|
||||||
addresses = account.get_addresses(for_change)
|
|
||||||
if len(addresses) < limit:
|
|
||||||
self.create_new_address(account, for_change)
|
|
||||||
continue
|
|
||||||
if map( lambda a: self.address_is_old(a), addresses[-limit:] ) == limit*[False]:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
self.create_new_address(account, for_change)
|
|
||||||
|
|
||||||
def check_pending_accounts(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def synchronize_account(self, account):
|
|
||||||
self.synchronize_sequence(account, 0)
|
|
||||||
self.synchronize_sequence(account, 1)
|
|
||||||
|
|
||||||
def synchronize(self):
|
def synchronize(self):
|
||||||
self.check_pending_accounts()
|
|
||||||
for account in self.accounts.values():
|
for account in self.accounts.values():
|
||||||
if type(account) in [ImportedAccount, PendingAccount]:
|
account.synchronize(self)
|
||||||
continue
|
|
||||||
self.synchronize_account(account)
|
|
||||||
|
|
||||||
def restore(self, callback):
|
def restore(self, callback):
|
||||||
from i18n import _
|
from i18n import _
|
||||||
|
@ -1359,15 +1328,38 @@ class BIP32_Simple_Wallet(BIP32_Wallet):
|
||||||
class BIP32_HD_Wallet(BIP32_Wallet):
|
class BIP32_HD_Wallet(BIP32_Wallet):
|
||||||
# wallet that can create accounts
|
# wallet that can create accounts
|
||||||
|
|
||||||
def create_main_account(self, password):
|
|
||||||
# First check the password is valid (this raises if it isn't).
|
|
||||||
if not self.is_watching_only():
|
|
||||||
self.check_password(password)
|
|
||||||
self.create_account('Main account', password)
|
|
||||||
|
|
||||||
def can_create_accounts(self):
|
def can_create_accounts(self):
|
||||||
return self.root_name in self.master_private_keys.keys()
|
return self.root_name in self.master_private_keys.keys()
|
||||||
|
|
||||||
|
def num_accounts(self):
|
||||||
|
keys = []
|
||||||
|
for k, v in self.accounts.items():
|
||||||
|
if type(v) != BIP32_Account:
|
||||||
|
continue
|
||||||
|
keys.append(k)
|
||||||
|
i = 0
|
||||||
|
while True:
|
||||||
|
account_id = '%d'%i
|
||||||
|
if account_id not in keys:
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
return i
|
||||||
|
|
||||||
|
def next_account_address(self, password):
|
||||||
|
account_id = '%d'%self.num_accounts()
|
||||||
|
account = self.make_account(account_id, password)
|
||||||
|
addr = account.first_address()
|
||||||
|
return account_id, addr
|
||||||
|
|
||||||
|
def make_account(self, account_id, password):
|
||||||
|
"""Creates and saves the master keys, but does not save the account"""
|
||||||
|
derivation = self.root_name + "%d'"%int(account_id)
|
||||||
|
xpub, xprv = self.derive_xkeys(self.root_name, derivation, password)
|
||||||
|
self.add_master_public_key(derivation, xpub)
|
||||||
|
self.add_master_private_key(derivation, xprv, password)
|
||||||
|
account = BIP32_Account({'xpub':xpub})
|
||||||
|
return account
|
||||||
|
|
||||||
def create_account(self, name, password):
|
def create_account(self, name, password):
|
||||||
account_id = "%d"%self.num_accounts()
|
account_id = "%d"%self.num_accounts()
|
||||||
account = self.make_account(account_id, password)
|
account = self.make_account(account_id, password)
|
||||||
|
@ -1375,7 +1367,14 @@ class BIP32_HD_Wallet(BIP32_Wallet):
|
||||||
if name:
|
if name:
|
||||||
self.set_label(account_id, name)
|
self.set_label(account_id, name)
|
||||||
# add address of the next account
|
# add address of the next account
|
||||||
_, _ = self.next_account_address(password)
|
account_id, addr = self.next_account_address(password)
|
||||||
|
self.storage.put('next_address',(account_id, addr))
|
||||||
|
|
||||||
|
def create_main_account(self, password):
|
||||||
|
# First check the password is valid (this raises if it isn't).
|
||||||
|
if not self.is_watching_only():
|
||||||
|
self.check_password(password)
|
||||||
|
self.create_account('Main account', password)
|
||||||
|
|
||||||
def account_is_pending(self, k):
|
def account_is_pending(self, k):
|
||||||
return type(self.accounts.get(k)) == PendingAccount
|
return type(self.accounts.get(k)) == PendingAccount
|
||||||
|
@ -1391,49 +1390,6 @@ class BIP32_HD_Wallet(BIP32_Wallet):
|
||||||
self.accounts[account_id] = PendingAccount({'pending':addr})
|
self.accounts[account_id] = PendingAccount({'pending':addr})
|
||||||
self.save_accounts()
|
self.save_accounts()
|
||||||
|
|
||||||
def check_pending_accounts(self):
|
|
||||||
for account_id, addr in self.next_addresses.items():
|
|
||||||
if self.address_is_old(addr):
|
|
||||||
print_error( "creating account", account_id )
|
|
||||||
xpub = self.master_public_keys[account_id]
|
|
||||||
account = BIP32_Account({'xpub':xpub})
|
|
||||||
self.add_account(account_id, account)
|
|
||||||
self.next_addresses.pop(account_id)
|
|
||||||
|
|
||||||
def next_account_address(self, password):
|
|
||||||
account_id = '%d'%self.num_accounts()
|
|
||||||
addr = self.next_addresses.get(account_id)
|
|
||||||
if not addr:
|
|
||||||
account = self.make_account(account_id, password)
|
|
||||||
addr = account.first_address()
|
|
||||||
self.next_addresses[account_id] = addr
|
|
||||||
self.storage.put('next_addresses', self.next_addresses)
|
|
||||||
return account_id, addr
|
|
||||||
|
|
||||||
def make_account(self, account_id, password):
|
|
||||||
"""Creates and saves the master keys, but does not save the account"""
|
|
||||||
derivation = self.root_name + "%d'"%int(account_id)
|
|
||||||
xpub, xprv = self.derive_xkeys(self.root_name, derivation, password)
|
|
||||||
self.add_master_public_key(derivation, xpub)
|
|
||||||
if xprv:
|
|
||||||
self.add_master_private_key(derivation, xprv, password)
|
|
||||||
|
|
||||||
account = BIP32_Account({'xpub':xpub})
|
|
||||||
return account
|
|
||||||
|
|
||||||
def num_accounts(self):
|
|
||||||
keys = []
|
|
||||||
for k, v in self.accounts.items():
|
|
||||||
if type(v) != BIP32_Account:
|
|
||||||
continue
|
|
||||||
keys.append(k)
|
|
||||||
i = 0
|
|
||||||
while True:
|
|
||||||
account_id = '%d'%i
|
|
||||||
if account_id not in keys:
|
|
||||||
break
|
|
||||||
i += 1
|
|
||||||
return i
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue