mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-02 10:15:20 +00:00
let DB handle addresses
This commit is contained in:
parent
2abc4f6334
commit
56ced1dfd5
2 changed files with 102 additions and 72 deletions
|
@ -667,6 +667,73 @@ class JsonDB(PrintError):
|
|||
self.data[name] = {}
|
||||
return self.data[name]
|
||||
|
||||
@locked
|
||||
def num_change_addresses(self):
|
||||
return len(self.change_addresses)
|
||||
|
||||
@locked
|
||||
def num_receiving_addresses(self):
|
||||
return len(self.receiving_addresses)
|
||||
|
||||
@locked
|
||||
def get_change_addresses(self):
|
||||
return list(self.change_addresses)
|
||||
|
||||
@locked
|
||||
def get_receiving_addresses(self):
|
||||
return list(self.receiving_addresses)
|
||||
|
||||
@modifier
|
||||
def add_change_address(self, addr):
|
||||
self._addr_to_addr_index[addr] = (True, len(self.change_addresses))
|
||||
self.change_addresses.append(addr)
|
||||
|
||||
@modifier
|
||||
def add_receiving_address(self, addr):
|
||||
self._addr_to_addr_index[addr] = (False, len(self.receiving_addresses))
|
||||
self.receiving_addresses.append(addr)
|
||||
|
||||
@locked
|
||||
def get_address_index(self, address):
|
||||
return self._addr_to_addr_index.get(address)
|
||||
|
||||
@modifier
|
||||
def add_imported_address(self, addr, d):
|
||||
self.imported_addresses[addr] = d
|
||||
|
||||
@modifier
|
||||
def remove_imported_address(self, addr):
|
||||
self.imported_addresses.pop(addr)
|
||||
|
||||
@locked
|
||||
def has_imported_address(self, addr):
|
||||
return addr in self.imported_addresses
|
||||
|
||||
@locked
|
||||
def get_imported_addresses(self):
|
||||
return list(sorted(self.imported_addresses.keys()))
|
||||
|
||||
@locked
|
||||
def get_imported_address(self, addr):
|
||||
return self.imported_addresses.get(addr)
|
||||
|
||||
def load_addresses(self, wallet_type):
|
||||
""" called from Abstract_Wallet.__init__ """
|
||||
if wallet_type == 'imported':
|
||||
self.imported_addresses = self.get_data_ref('addresses')
|
||||
else:
|
||||
self.get_data_ref('addresses')
|
||||
for name in ['receiving', 'change']:
|
||||
if name not in self.data['addresses']:
|
||||
self.data['addresses'][name] = []
|
||||
self.change_addresses = self.data['addresses']['change']
|
||||
self.receiving_addresses = self.data['addresses']['receiving']
|
||||
self._addr_to_addr_index = {} # key: address, value: (is_change, index)
|
||||
for i, addr in enumerate(self.receiving_addresses):
|
||||
self._addr_to_addr_index[addr] = (False, i)
|
||||
for i, addr in enumerate(self.change_addresses):
|
||||
self._addr_to_addr_index[addr] = (True, i)
|
||||
|
||||
@profiler
|
||||
def load_transactions(self):
|
||||
# references in self.data
|
||||
|
|
|
@ -195,6 +195,9 @@ class Abstract_Wallet(AddressSynchronizer):
|
|||
if storage.requires_upgrade():
|
||||
raise Exception("storage must be upgraded before constructing wallet")
|
||||
|
||||
# load addresses needs to be called before constructor for sanity checks
|
||||
storage.db.load_addresses(self.wallet_type)
|
||||
|
||||
AddressSynchronizer.__init__(self, storage)
|
||||
|
||||
# saved fields
|
||||
|
@ -219,7 +222,6 @@ class Abstract_Wallet(AddressSynchronizer):
|
|||
|
||||
def load_and_cleanup(self):
|
||||
self.load_keystore()
|
||||
self.load_addresses()
|
||||
self.test_addresses_sanity()
|
||||
super().load_and_cleanup()
|
||||
|
||||
|
@ -235,15 +237,6 @@ class Abstract_Wallet(AddressSynchronizer):
|
|||
def basename(self):
|
||||
return os.path.basename(self.storage.path)
|
||||
|
||||
def save_addresses(self):
|
||||
self.storage.put('addresses', {'receiving':self.receiving_addresses, 'change':self.change_addresses})
|
||||
|
||||
def load_addresses(self):
|
||||
d = self.storage.get('addresses', {})
|
||||
if type(d) != dict: d={}
|
||||
self.receiving_addresses = d.get('receiving', [])
|
||||
self.change_addresses = d.get('change', [])
|
||||
|
||||
def test_addresses_sanity(self):
|
||||
addrs = self.get_receiving_addresses()
|
||||
if len(addrs) > 0:
|
||||
|
@ -320,11 +313,7 @@ class Abstract_Wallet(AddressSynchronizer):
|
|||
return
|
||||
|
||||
def is_mine(self, address):
|
||||
try:
|
||||
self.get_address_index(address)
|
||||
except KeyError:
|
||||
return False
|
||||
return True
|
||||
return bool(self.get_address_index(address))
|
||||
|
||||
def is_change(self, address):
|
||||
if not self.is_mine(address):
|
||||
|
@ -1127,12 +1116,7 @@ class Abstract_Wallet(AddressSynchronizer):
|
|||
return True
|
||||
|
||||
def get_sorted_requests(self, config):
|
||||
def f(addr):
|
||||
try:
|
||||
return self.get_address_index(addr)
|
||||
except:
|
||||
return
|
||||
keys = map(lambda x: (f(x), x), self.receive_requests.keys())
|
||||
keys = map(lambda x: (self.get_address_index(x), x), self.receive_requests.keys())
|
||||
sorted_keys = sorted(filter(lambda x: x[0] is not None, keys))
|
||||
return [self.get_payment_request(x[1], config) for x in sorted_keys]
|
||||
|
||||
|
@ -1327,19 +1311,13 @@ class Imported_Wallet(Simple_Wallet):
|
|||
|
||||
def load_keystore(self):
|
||||
self.keystore = load_keystore(self.storage, 'keystore') if self.storage.get('keystore') else None
|
||||
# fixme: a reference to addresses is needed
|
||||
if self.keystore:
|
||||
self.keystore.addresses = self.db.imported_addresses
|
||||
|
||||
def save_keystore(self):
|
||||
self.storage.put('keystore', self.keystore.dump())
|
||||
|
||||
def load_addresses(self):
|
||||
self.addresses = self.storage.get('addresses', {})
|
||||
# fixme: a reference to addresses is needed
|
||||
if self.keystore:
|
||||
self.keystore.addresses = self.addresses
|
||||
|
||||
def save_addresses(self):
|
||||
self.storage.put('addresses', self.addresses)
|
||||
|
||||
def can_import_address(self):
|
||||
return self.is_watching_only()
|
||||
|
||||
|
@ -1366,7 +1344,7 @@ class Imported_Wallet(Simple_Wallet):
|
|||
|
||||
def get_addresses(self):
|
||||
# note: overridden so that the history can be cleared
|
||||
return sorted(self.addresses.keys())
|
||||
return self.db.get_imported_addresses()
|
||||
|
||||
def get_receiving_addresses(self):
|
||||
return self.get_addresses()
|
||||
|
@ -1382,13 +1360,14 @@ class Imported_Wallet(Simple_Wallet):
|
|||
if not bitcoin.is_address(address):
|
||||
bad_addr.append((address, _('invalid address')))
|
||||
continue
|
||||
if address in self.addresses:
|
||||
if self.db.has_imported_address(address):
|
||||
bad_addr.append((address, _('address already in wallet')))
|
||||
continue
|
||||
good_addr.append(address)
|
||||
self.addresses[address] = {}
|
||||
self.db.add_imported_address(address, {})
|
||||
self.add_address(address)
|
||||
self.save_addresses()
|
||||
if write_to_disk:
|
||||
self.storage.write()
|
||||
return good_addr, bad_addr
|
||||
|
||||
def import_address(self, address: str) -> str:
|
||||
|
@ -1399,7 +1378,7 @@ class Imported_Wallet(Simple_Wallet):
|
|||
raise BitcoinException(str(bad_addr[0][1]))
|
||||
|
||||
def delete_address(self, address):
|
||||
if address not in self.addresses:
|
||||
if not self.db.has_imported_address(address):
|
||||
return
|
||||
transactions_to_remove = set() # only referred to by this address
|
||||
transactions_new = set() # txs that are not only referred to by address
|
||||
|
@ -1424,7 +1403,7 @@ class Imported_Wallet(Simple_Wallet):
|
|||
self.remove_payment_request(address, {})
|
||||
self.set_frozen_state([address], False)
|
||||
pubkey = self.get_public_key(address)
|
||||
self.addresses.pop(address)
|
||||
self.db.remove_imported_address(address)
|
||||
if pubkey:
|
||||
# delete key iff no other address uses it (e.g. p2pkh and p2wpkh for same key)
|
||||
for txin_type in bitcoin.WIF_SCRIPT_TYPES.keys():
|
||||
|
@ -1433,19 +1412,23 @@ class Imported_Wallet(Simple_Wallet):
|
|||
except NotImplementedError:
|
||||
pass
|
||||
else:
|
||||
if addr2 in self.addresses:
|
||||
if self.db.has_imported_address(addr2):
|
||||
break
|
||||
else:
|
||||
self.keystore.delete_imported_key(pubkey)
|
||||
self.save_keystore()
|
||||
self.save_addresses()
|
||||
self.storage.write()
|
||||
|
||||
def is_mine(self, address):
|
||||
return self.db.has_imported_address(address)
|
||||
|
||||
def get_address_index(self, address):
|
||||
# returns None is address is not mine
|
||||
return self.get_public_key(address)
|
||||
|
||||
def get_public_key(self, address):
|
||||
return self.addresses[address].get('pubkey')
|
||||
x = self.db.get_imported_address(address)
|
||||
return x.get('pubkey') if x else None
|
||||
|
||||
def import_private_keys(self, keys: List[str], password: Optional[str], *,
|
||||
write_to_disk=True) -> Tuple[List[str], List[Tuple[str, str]]]:
|
||||
|
@ -1462,10 +1445,9 @@ class Imported_Wallet(Simple_Wallet):
|
|||
continue
|
||||
addr = bitcoin.pubkey_to_address(txin_type, pubkey)
|
||||
good_addr.append(addr)
|
||||
self.addresses[addr] = {'type':txin_type, 'pubkey':pubkey, 'redeem_script':None}
|
||||
self.db.add_imported_address(addr, {'type':txin_type, 'pubkey':pubkey, 'redeem_script':None})
|
||||
self.add_address(addr)
|
||||
self.save_keystore()
|
||||
self.save_addresses()
|
||||
if write_to_disk:
|
||||
self.storage.write()
|
||||
return good_addr, bad_keys
|
||||
|
@ -1478,12 +1460,12 @@ class Imported_Wallet(Simple_Wallet):
|
|||
raise BitcoinException(str(bad_keys[0][1]))
|
||||
|
||||
def get_redeem_script(self, address):
|
||||
d = self.addresses[address]
|
||||
d = self.db.get_imported_address(address)
|
||||
redeem_script = d['redeem_script']
|
||||
return redeem_script
|
||||
|
||||
def get_txin_type(self, address):
|
||||
return self.addresses[address].get('type', 'address')
|
||||
return self.db.get_imported_address(address).get('type', 'address')
|
||||
|
||||
def add_input_sig_info(self, txin, address):
|
||||
if self.is_watching_only():
|
||||
|
@ -1492,7 +1474,7 @@ class Imported_Wallet(Simple_Wallet):
|
|||
txin['signatures'] = [None]
|
||||
return
|
||||
if txin['type'] in ['p2pkh', 'p2wpkh', 'p2wpkh-p2sh']:
|
||||
pubkey = self.addresses[address]['pubkey']
|
||||
pubkey = self.db.get_imported_address(address)['pubkey']
|
||||
txin['num_sig'] = 1
|
||||
txin['x_pubkeys'] = [pubkey]
|
||||
txin['signatures'] = [None]
|
||||
|
@ -1500,8 +1482,8 @@ class Imported_Wallet(Simple_Wallet):
|
|||
raise NotImplementedError('imported wallets for p2sh are not implemented')
|
||||
|
||||
def pubkeys_to_address(self, pubkey):
|
||||
for addr, v in self.addresses.items():
|
||||
if v.get('pubkey') == pubkey:
|
||||
for addr in self.db.get_imported_addresses():
|
||||
if self.db.get_imported_address(addr)['pubkey'] == pubkey:
|
||||
return addr
|
||||
|
||||
class Deterministic_Wallet(Abstract_Wallet):
|
||||
|
@ -1525,10 +1507,10 @@ class Deterministic_Wallet(Abstract_Wallet):
|
|||
return out
|
||||
|
||||
def get_receiving_addresses(self):
|
||||
return self.receiving_addresses
|
||||
return self.db.get_receiving_addresses()
|
||||
|
||||
def get_change_addresses(self):
|
||||
return self.change_addresses
|
||||
return self.db.get_change_addresses()
|
||||
|
||||
@profiler
|
||||
def try_detecting_internal_addresses_corruption(self):
|
||||
|
@ -1557,18 +1539,10 @@ class Deterministic_Wallet(Abstract_Wallet):
|
|||
|
||||
def change_gap_limit(self, value):
|
||||
'''This method is not called in the code, it is kept for console use'''
|
||||
if value >= self.gap_limit:
|
||||
if value >= self.min_acceptable_gap():
|
||||
self.gap_limit = value
|
||||
self.storage.put('gap_limit', self.gap_limit)
|
||||
return True
|
||||
elif value >= self.min_acceptable_gap():
|
||||
addresses = self.get_receiving_addresses()
|
||||
k = self.num_unused_trailing_addresses(addresses)
|
||||
n = len(addresses) - k + value
|
||||
self.receiving_addresses = self.receiving_addresses[0:n]
|
||||
self.gap_limit = value
|
||||
self.storage.put('gap_limit', self.gap_limit)
|
||||
self.save_addresses()
|
||||
self.storage.write()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
@ -1595,14 +1569,6 @@ class Deterministic_Wallet(Abstract_Wallet):
|
|||
nmax = max(nmax, n)
|
||||
return nmax + 1
|
||||
|
||||
def load_addresses(self):
|
||||
super().load_addresses()
|
||||
self._addr_to_addr_index = {} # key: address, value: (is_change, index)
|
||||
for i, addr in enumerate(self.receiving_addresses):
|
||||
self._addr_to_addr_index[addr] = (False, i)
|
||||
for i, addr in enumerate(self.change_addresses):
|
||||
self._addr_to_addr_index[addr] = (True, i)
|
||||
|
||||
def derive_address(self, for_change, n):
|
||||
x = self.derive_pubkeys(for_change, n)
|
||||
return self.pubkeys_to_address(x)
|
||||
|
@ -1610,12 +1576,9 @@ class Deterministic_Wallet(Abstract_Wallet):
|
|||
def create_new_address(self, for_change=False):
|
||||
assert type(for_change) is bool
|
||||
with self.lock:
|
||||
addr_list = self.change_addresses if for_change else self.receiving_addresses
|
||||
n = len(addr_list)
|
||||
n = self.db.num_change_addresses() if for_change else self.db.num_receiving_addresses()
|
||||
address = self.derive_address(for_change, n)
|
||||
addr_list.append(address)
|
||||
self._addr_to_addr_index[address] = (for_change, n)
|
||||
self.save_addresses()
|
||||
self.db.add_change_address(address) if for_change else self.db.add_receiving_address(address)
|
||||
self.add_address(address)
|
||||
if for_change:
|
||||
# note: if it's actually used, it will get filtered later
|
||||
|
@ -1652,7 +1615,7 @@ class Deterministic_Wallet(Abstract_Wallet):
|
|||
return True
|
||||
|
||||
def get_address_index(self, address):
|
||||
return self._addr_to_addr_index[address]
|
||||
return self.db.get_address_index(address)
|
||||
|
||||
def get_master_public_keys(self):
|
||||
return [self.get_master_public_key()]
|
||||
|
|
Loading…
Add table
Reference in a new issue