Merge pull request #10114 from SomberNight/202508_change_gap_limit_for_change
wallet: add internal support for changing gap_limit_for_change, and use it in tests
This commit is contained in:
@@ -391,7 +391,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
"""
|
||||
|
||||
max_change_outputs = 3
|
||||
gap_limit_for_change = 10
|
||||
gap_limit_for_change = None # type: int | None
|
||||
|
||||
txin_type: str
|
||||
wallet_type: str
|
||||
@@ -1840,19 +1840,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
else:
|
||||
change_addrs = [preferred_change_addr]
|
||||
elif self.use_change:
|
||||
# Recalc and get unused change addresses
|
||||
addrs = self.calc_unused_change_addresses()
|
||||
# New change addresses are created only after a few
|
||||
# confirmations.
|
||||
if addrs:
|
||||
# if there are any unused, select all
|
||||
change_addrs = addrs
|
||||
else:
|
||||
# if there are none, take one randomly from the last few
|
||||
if not allow_reusing_used_change_addrs:
|
||||
return []
|
||||
addrs = self.get_change_addresses(slice_start=-self.gap_limit_for_change)
|
||||
change_addrs = [random.choice(addrs)] if addrs else []
|
||||
change_addrs = self._get_change_addresses_we_can_use_now(allow_reuse=allow_reusing_used_change_addrs)
|
||||
for addr in change_addrs:
|
||||
assert is_address(addr), f"not valid bitcoin address: {addr}"
|
||||
# note that change addresses are not necessarily ismine
|
||||
@@ -1872,21 +1860,38 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
return addrs[0]
|
||||
return None
|
||||
|
||||
@check_returned_address_for_corruption
|
||||
def get_new_sweep_address_for_channel(self) -> str:
|
||||
addrs = self._get_change_addresses_we_can_use_now(allow_reuse=True)
|
||||
if addrs:
|
||||
return addrs[0]
|
||||
# fallback for e.g. imported wallets
|
||||
return self.get_receiving_address()
|
||||
|
||||
def _get_change_addresses_we_can_use_now(
|
||||
self,
|
||||
*,
|
||||
allow_reuse: bool = True,
|
||||
) -> Sequence[str]:
|
||||
# Recalc and get unused change addresses
|
||||
addrs = self.calc_unused_change_addresses()
|
||||
# New change addresses are created only after a few
|
||||
# confirmations.
|
||||
if addrs:
|
||||
selected_addr = addrs[0]
|
||||
# if there are any unused, select all
|
||||
change_addrs = addrs
|
||||
else:
|
||||
# if there are none, take one randomly from the last few
|
||||
addrs = self.get_change_addresses(slice_start=-self.gap_limit_for_change)
|
||||
if addrs:
|
||||
selected_addr = random.choice(addrs)
|
||||
else: # fallback for e.g. imported wallets
|
||||
selected_addr = self.get_receiving_address()
|
||||
assert is_address(selected_addr), f"not valid bitcoin address: {selected_addr}"
|
||||
return selected_addr
|
||||
if not allow_reuse:
|
||||
return []
|
||||
gap_limit = self.gap_limit_for_change or 0
|
||||
addrs = self.get_change_addresses(slice_start=-gap_limit)
|
||||
change_addrs = [random.choice(addrs)] if addrs else []
|
||||
for addr in change_addrs:
|
||||
assert is_address(addr), f"not valid bitcoin address: {addr}"
|
||||
# note that change addresses are not necessarily ismine
|
||||
# in which case this is a no-op
|
||||
self.check_address_for_corruption(addr)
|
||||
return change_addrs
|
||||
|
||||
def should_keep_reserve_utxo(
|
||||
self,
|
||||
@@ -3805,11 +3810,13 @@ class Imported_Wallet(Simple_Wallet):
|
||||
|
||||
|
||||
class Deterministic_Wallet(Abstract_Wallet):
|
||||
gap_limit_for_change: int
|
||||
|
||||
def __init__(self, db, *, config):
|
||||
self._ephemeral_addr_to_addr_index = {} # type: Dict[str, Sequence[int]]
|
||||
Abstract_Wallet.__init__(self, db, config=config)
|
||||
self.gap_limit = db.get('gap_limit', 20)
|
||||
self.gap_limit_for_change = db.get('gap_limit_for_change', 10)
|
||||
# generate addresses now. note that without libsecp this might block
|
||||
# for a few seconds!
|
||||
self.synchronize()
|
||||
@@ -4228,7 +4235,8 @@ def create_new_wallet(
|
||||
password: Optional[str] = None,
|
||||
encrypt_file: bool = True,
|
||||
seed_type: Optional[str] = None,
|
||||
gap_limit: Optional[int] = None
|
||||
gap_limit: Optional[int] = None,
|
||||
gap_limit_for_change: Optional[int] = None,
|
||||
) -> dict:
|
||||
"""Create a new wallet"""
|
||||
storage = WalletStorage(path, allow_partial_writes=config.WALLET_PARTIAL_WRITES)
|
||||
@@ -4244,6 +4252,8 @@ def create_new_wallet(
|
||||
db.put('lightning_xprv', k.get_lightning_xprv(None))
|
||||
if gap_limit is not None:
|
||||
db.put('gap_limit', gap_limit)
|
||||
if gap_limit_for_change is not None:
|
||||
db.put('gap_limit_for_change', gap_limit_for_change)
|
||||
wallet = Wallet(db, config=config)
|
||||
wallet.update_password(old_pw=None, new_pw=password, encrypt_storage=encrypt_file)
|
||||
wallet.synchronize()
|
||||
@@ -4261,6 +4271,7 @@ def restore_wallet_from_text(
|
||||
password: Optional[str] = None,
|
||||
encrypt_file: Optional[bool] = None,
|
||||
gap_limit: Optional[int] = None,
|
||||
gap_limit_for_change: Optional[int] = None,
|
||||
) -> dict:
|
||||
"""Restore a wallet from text. Text can be a seed phrase, a master
|
||||
public key, a master private key, a list of bitcoin addresses
|
||||
@@ -4304,6 +4315,8 @@ def restore_wallet_from_text(
|
||||
db.put('wallet_type', 'standard')
|
||||
if gap_limit is not None:
|
||||
db.put('gap_limit', gap_limit)
|
||||
if gap_limit_for_change is not None:
|
||||
db.put('gap_limit_for_change', gap_limit_for_change)
|
||||
wallet = Wallet(db, config=config)
|
||||
if db.storage:
|
||||
assert not db.storage.file_exists(), "file was created too soon! plaintext keys might have been written to disk"
|
||||
|
||||
Reference in New Issue
Block a user