Browse Source

Avoid change address reuse if possible

As discussed on #electrum yesterday.
Increase change gap limit to 6.
Choose the next unused change address, if any, otherwise pick
one at random from the gap limit.
283
Neil Booth 10 years ago
parent
commit
4eaff5678d
  1. 21
      lib/wallet.py

21
lib/wallet.py

@ -142,7 +142,7 @@ class Abstract_Wallet(object):
def __init__(self, storage): def __init__(self, storage):
self.storage = storage self.storage = storage
self.electrum_version = ELECTRUM_VERSION self.electrum_version = ELECTRUM_VERSION
self.gap_limit_for_change = 3 # constant self.gap_limit_for_change = 6 # constant
# saved fields # saved fields
self.seed_version = storage.get('seed_version', NEW_SEED_VERSION) self.seed_version = storage.get('seed_version', NEW_SEED_VERSION)
self.use_change = storage.get('use_change',True) self.use_change = storage.get('use_change',True)
@ -170,7 +170,7 @@ class Abstract_Wallet(object):
self.unverified_tx = {} self.unverified_tx = {}
# Verified transactions. Each value is a (height, timestamp, block_pos) tuple. Access with self.lock. # Verified transactions. Each value is a (height, timestamp, block_pos) tuple. Access with self.lock.
self.verified_tx = storage.get('verified_tx3',{}) self.verified_tx = storage.get('verified_tx3',{})
# there is a difference between wallet.up_to_date and interface.is_up_to_date() # there is a difference between wallet.up_to_date and interface.is_up_to_date()
# interface.is_up_to_date() returns true when all requests have been answered and processed # interface.is_up_to_date() returns true when all requests have been answered and processed
# wallet.up_to_date is true when the wallet is synchronized (stronger requirement) # wallet.up_to_date is true when the wallet is synchronized (stronger requirement)
@ -398,7 +398,7 @@ class Abstract_Wallet(object):
if tx_hash not in self.verified_tx and tx_height <= self.get_local_height(): if tx_hash not in self.verified_tx and tx_height <= self.get_local_height():
txs.append((tx_hash, tx_height)) txs.append((tx_hash, tx_height))
return txs return txs
def undo_verifications(self, height): def undo_verifications(self, height):
'''Used by the verifier when a reorg has happened''' '''Used by the verifier when a reorg has happened'''
txs = [] txs = []
@ -690,7 +690,7 @@ class Abstract_Wallet(object):
_type, x, v = txo _type, x, v = txo
if _type == 'address': if _type == 'address':
addr = x addr = x
elif _type == 'pubkey': elif _type == 'pubkey':
addr = public_key_to_bc_address(x.decode('hex')) addr = public_key_to_bc_address(x.decode('hex'))
else: else:
addr = None addr = None
@ -887,10 +887,17 @@ class Abstract_Wallet(object):
# send change to one of the accounts involved in the tx # send change to one of the accounts involved in the tx
address = inputs[0].get('address') address = inputs[0].get('address')
account, _ = self.get_address_index(address) account, _ = self.get_address_index(address)
if not self.use_change or not self.accounts[account].has_change(): if self.use_change and self.accounts[account].has_change():
change_addr = address # New change addresses are created only after a few confirmations.
# Choose an unused change address if any, otherwise take one at random
change_addrs = self.accounts[account].get_addresses(1)[-self.gap_limit_for_change:]
for change_addr in change_addrs:
if self.get_num_tx(change_addr) == 0:
break
else:
change_addr = random.choice(change_addrs)
else: else:
change_addr = self.accounts[account].get_addresses(1)[-self.gap_limit_for_change] change_addr = address
# if change is above dust threshold, add a change output. # if change is above dust threshold, add a change output.
change_amount = total - ( amount + fee ) change_amount = total - ( amount + fee )

Loading…
Cancel
Save