@ -45,6 +45,7 @@ from abc import ABC, abstractmethod
import itertools
import threading
import enum
import asyncio
from aiorpcx import timeout_after , TaskTimeout , ignore_after
@ -260,7 +261,7 @@ class TxWalletDetails(NamedTuple):
is_lightning_funding_tx : bool
class Abstract_Wallet ( AddressSynchronizer , A BC ) :
class Abstract_Wallet ( ABC ) :
"""
Wallet classes are created to handle various address generation methods .
Completion states ( watching - only , single account , no seed , etc ) are handled inside classes .
@ -285,7 +286,13 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
# load addresses needs to be called before constructor for sanity checks
db . load_addresses ( self . wallet_type )
self . keystore = None # type: Optional[KeyStore] # will be set by load_keystore
AddressSynchronizer . __init__ ( self , db )
self . network = None
self . adb = AddressSynchronizer ( db )
for addr in self . get_addresses ( ) :
self . adb . add_address ( addr )
self . lock = self . adb . lock
self . transaction_lock = self . adb . transaction_lock
# saved fields
self . use_change = db . get ( ' use_change ' , True )
@ -309,6 +316,24 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
self . _coin_price_cache = { }
self . lnworker = None
self . load_keystore ( )
self . test_addresses_sanity ( )
# callbacks
util . register_callback ( self . on_adb_set_up_to_date , [ ' adb_set_up_to_date ' ] )
util . register_callback ( self . on_adb_added_tx , [ ' adb_added_tx ' ] )
util . register_callback ( self . on_adb_added_verified_tx , [ ' adb_added_verified_tx ' ] )
util . register_callback ( self . on_adb_removed_verified_tx , [ ' adb_removed_verified_tx ' ] )
async def main ( self ) :
from aiorpcx import run_in_thread
# calls synchronize
while True :
await asyncio . sleep ( 0.1 )
# note: we only generate new HD addresses if the existing ones
# have history that are mined and SPV-verified. This inherently couples
# the Sychronizer and the Verifier.
num_new_addrs = await run_in_thread ( self . synchronize )
up_to_date = self . adb . is_up_to_date ( ) and num_new_addrs == 0
def save_db ( self ) :
if self . storage :
@ -367,9 +392,13 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
async def stop ( self ) :
""" Stop all networking and save DB to disk. """
util . unregister_callback ( self . on_adb_set_up_to_date )
util . unregister_callback ( self . on_adb_added_tx )
util . unregister_callback ( self . on_adb_added_verified_tx )
util . unregister_callback ( self . on_adb_removed_verified_tx )
try :
async with ignore_after ( 5 ) :
await super ( ) . stop ( )
await self . adb . stop ( )
if self . network :
if self . lnworker :
await self . lnworker . stop ( )
@ -379,28 +408,56 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
self . save_keystore ( )
self . save_db ( )
def set_up_to_date ( self , b ) :
super ( ) . set_up_to_date ( b )
if b : self . save_db ( )
def is_up_to_date ( self ) :
return self . adb . is_up_to_date ( )
def on_adb_set_up_to_date ( self , event , adb ) :
if adb != self . adb :
return
if adb . is_up_to_date ( ) :
self . save_db ( )
util . trigger_callback ( ' wallet_updated ' , self )
util . trigger_callback ( ' status ' )
def on_adb_added_tx ( self , event , adb , tx_hash ) :
if self . adb != adb :
return
tx = self . db . get_transaction ( tx_hash )
if not tx :
raise Exception ( tx_hash )
self . _maybe_set_tx_label_based_on_invoices ( tx )
if self . lnworker :
self . lnworker . maybe_add_backup_from_tx ( tx )
self . _update_request_statuses_touched_by_tx ( tx_hash )
util . trigger_callback ( ' new_transaction ' , self , tx )
def on_adb_added_verified_tx ( self , event , adb , tx_hash ) :
if adb != self . adb :
return
self . _update_request_statuses_touched_by_tx ( tx_hash )
tx_mined_status = self . adb . get_tx_height ( tx_hash )
util . trigger_callback ( ' verified ' , self , tx_hash , tx_mined_status )
def on_adb_removed_verified_tx ( self , event , adb , tx_hash ) :
if adb != self . adb :
return
self . _update_request_statuses_touched_by_tx ( tx_hash )
def clear_history ( self ) :
super ( ) . clear_history ( )
self . adb . clear_history ( )
self . save_db ( )
def start_network ( self , network ) :
AddressSynchronizer . start_network ( self , network )
self . network = network
if network :
asyncio . run_coroutine_threadsafe ( self . main ( ) , self . network . asyncio_loop )
self . adb . start_network ( network )
if self . lnworker :
self . lnworker . start_network ( network )
# only start gossiping when we already have channels
if self . db . get ( ' channels ' ) :
self . network . start_gossip ( )
def load_and_cleanup ( self ) :
self . load_keystore ( )
self . test_addresses_sanity ( )
super ( ) . load_and_cleanup ( )
@abstractmethod
def load_keystore ( self ) - > None :
pass
@ -450,7 +507,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
self . _not_old_change_addresses = [ addr for addr in self . _not_old_change_addresses
if not self . address_is_old ( addr ) ]
unused_addrs = [ addr for addr in self . _not_old_change_addresses
if not self . is_used ( addr ) and not self . is_address_reserved ( addr ) ]
if not self . adb . is_used ( addr ) and not self . is_address_reserved ( addr ) ]
return unused_addrs
def is_deterministic ( self ) - > bool :
@ -537,6 +594,10 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
return False
return self . get_address_index ( address ) [ 0 ] == 1
@abstractmethod
def get_addresses ( self ) - > Sequence [ str ] :
pass
@abstractmethod
def get_address_index ( self , address : str ) - > Optional [ AddressIndexGeneric ] :
pass
@ -595,7 +656,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
return bool ( self . lnworker . swap_manager . get_swap_by_tx ( tx ) ) if self . lnworker else False
def get_tx_info ( self , tx : Transaction ) - > TxWalletDetails :
tx_wallet_delta = self . get_wallet_delta ( tx )
tx_wallet_delta = self . adb . get_wallet_delta ( tx )
is_relevant = tx_wallet_delta . is_relevant
is_any_input_ismine = tx_wallet_delta . is_any_input_ismine
is_swap = self . is_swap_tx ( tx )
@ -606,11 +667,11 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
can_cpfp = False
tx_hash = tx . txid ( ) # note: txid can be None! e.g. when called from GUI tx dialog
is_lightning_funding_tx = self . is_lightning_funding_tx ( tx_hash )
tx_we_already_have_in_db = self . db . get_transaction ( tx_hash )
tx_we_already_have_in_db = self . adb . db . get_transaction ( tx_hash )
can_save_as_local = ( is_relevant and tx . txid ( ) is not None
and ( tx_we_already_have_in_db is None or not tx_we_already_have_in_db . is_complete ( ) ) )
label = ' '
tx_mined_status = self . get_tx_height ( tx_hash )
tx_mined_status = self . adb . get_tx_height ( tx_hash )
can_remove = ( ( tx_mined_status . height in [ TX_HEIGHT_FUTURE , TX_HEIGHT_LOCAL ] )
# otherwise 'height' is unreliable (typically LOCAL):
and is_relevant
@ -628,7 +689,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
elif tx_mined_status . height in ( TX_HEIGHT_UNCONF_PARENT , TX_HEIGHT_UNCONFIRMED ) :
status = _ ( ' Unconfirmed ' )
if fee is None :
fee = self . get_tx_fee ( tx_hash )
fee = self . adb . get_tx_fee ( tx_hash )
if fee and self . network and self . config . has_fee_mempool ( ) :
size = tx . estimated_size ( )
fee_per_byte = fee / size
@ -682,11 +743,22 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
is_lightning_funding_tx = is_lightning_funding_tx ,
)
def get_balance ( self , * * kwargs ) :
domain = self . get_addresses ( )
return self . adb . get_balance ( domain , * * kwargs )
def get_addr_balance ( self , address ) :
return self . adb . get_balance ( [ address ] )
def get_utxos ( self , * * kwargs ) :
domain = self . get_addresses ( )
return self . adb . get_utxos ( domain = domain , * * kwargs )
def get_spendable_coins ( self , domain , * , nonlocal_only = False ) - > Sequence [ PartialTxInput ] :
confirmed_only = self . config . get ( ' confirmed_only ' , False )
with self . _freeze_lock :
frozen_addresses = self . _frozen_addresses . copy ( )
utxos = self . get_utxos ( domain ,
utxos = self . get_utxos (
excluded_addresses = frozen_addresses ,
mature_only = True ,
confirmed_funding_only = confirmed_only ,
@ -714,7 +786,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
frozen_coins = { utxo . prevout . to_str ( ) for utxo in self . get_utxos ( )
if self . is_frozen_coin ( utxo ) }
if not frozen_coins : # shortcut
return self . get_balance ( frozen_addresses )
return self . adb . get_balance ( frozen_addresses )
c1 , u1 , x1 = self . get_balance ( )
c2 , u2 , x2 = self . get_balance (
excluded_addresses = frozen_addresses ,
@ -739,7 +811,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
def balance_at_timestamp ( self , domain , target_timestamp ) :
# we assume that get_history returns items ordered by block height
# we also assume that block timestamps are monotonic (which is false...!)
h = self . get_history ( domain = domain )
h = self . adb . get_history ( domain = domain )
balance = 0
for hist_item in h :
balance = hist_item . balance
@ -749,8 +821,10 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
return balance
def get_onchain_history ( self , * , domain = None ) :
if domain is None :
domain = self . get_addresses ( )
monotonic_timestamp = 0
for hist_item in self . get_history ( domain = domain ) :
for hist_item in self . adb . get_history ( domain = domain ) :
monotonic_timestamp = max ( monotonic_timestamp , ( hist_item . tx_mined_status . timestamp or 999_999_999_999 ) )
yield {
' txid ' : hist_item . txid ,
@ -768,7 +842,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
}
def create_invoice ( self , * , outputs : List [ PartialTxOutput ] , message , pr , URI ) - > Invoice :
height = self . get_local_height ( )
height = self . adb . get_local_height ( )
if pr :
return Invoice . from_bip70_payreq ( pr , height = height )
amount_msat = 0
@ -801,7 +875,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
key = self . get_key_for_outgoing_invoice ( invoice )
if not invoice . is_lightning ( ) :
if self . is_onchain_invoice_paid ( invoice , 0 ) :
self . logger . info ( " saving invoice... but it is already paid! " )
_ logger. info ( " saving invoice... but it is already paid! " )
with self . transaction_lock :
for txout in invoice . get_outputs ( ) :
self . _invoices_from_scriptpubkey_map [ txout . scriptpubkey ] . add ( key )
@ -888,7 +962,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
prevouts_and_values = self . db . get_prevouts_by_scripthash ( scripthash )
total_received = 0
for prevout , v in prevouts_and_values :
tx_height = self . get_tx_height ( prevout . txid . hex ( ) )
tx_height = self . adb . get_tx_height ( prevout . txid . hex ( ) )
if tx_height . height > 0 and tx_height . height < = invoice . height :
continue
if tx_height . conf < conf :
@ -917,14 +991,15 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
self . set_label ( tx_hash , " ; " . join ( labels ) )
return bool ( labels )
def add_transaction ( self , tx , * , allow_unrelated = False ) :
is_known = bool ( self . db . get_transaction ( tx . txid ( ) ) )
tx_was_added = super ( ) . add_transaction ( tx , allow_unrelated = allow_unrelated )
if tx_was_added and not is_known :
self . _maybe_set_tx_label_based_on_invoices ( tx )
if self . lnworker :
self . lnworker . maybe_add_backup_from_tx ( tx )
return tx_was_added
# fixme: this needs a callback
#def add_transaction(self, tx, *, allow_unrelated=False):
# is_known = bool(self.db.get_transaction(tx.txid()))
# tx_was_added = self.adb.add_transaction(tx, allow_unrelated=allow_unrelated)
# if tx_was_added and not is_known:
# self._maybe_set_tx_label_based_on_invoices(tx)
# if self.lnworker:
# self.lnworker.maybe_add_backup_from_tx(tx)
# return tx_was_added
@profiler
def get_full_history ( self , fx = None , * , onchain_domain = None , include_lightning = True ) :
@ -1076,13 +1151,11 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
end_timestamp = last_item [ ' timestamp ' ]
start_coins = self . get_utxos (
domain = None ,
block_height = start_height ,
confirmed_funding_only = True ,
confirmed_spending_only = True ,
nonlocal_only = True )
end_coins = self . get_utxos (
domain = None ,
block_height = end_height ,
confirmed_funding_only = True ,
confirmed_spending_only = True ,
@ -1130,7 +1203,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
}
def acquisition_price ( self , coins , price_func , ccy ) :
return Decimal ( sum ( self . coin_price ( coin . prevout . txid . hex ( ) , price_func , ccy , self . get_txin_value ( coin ) ) for coin in coins ) )
return Decimal ( sum ( self . coin_price ( coin . prevout . txid . hex ( ) , price_func , ccy , self . adb . get_txin_value ( coin ) ) for coin in coins ) )
def liquidation_price ( self , coins , price_func , timestamp ) :
p = price_func ( timestamp )
@ -1204,7 +1277,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
is_final = tx and tx . is_final ( )
if not is_final :
extra . append ( ' rbf ' )
fee = self . get_tx_fee ( tx_hash )
fee = self . adb . get_tx_fee ( tx_hash )
if fee is not None :
size = tx . estimated_size ( )
fee_per_byte = fee / size
@ -1238,7 +1311,8 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
def get_unconfirmed_base_tx_for_batching ( self ) - > Optional [ Transaction ] :
candidate = None
for hist_item in self . get_history ( ) :
domain = self . get_addresses ( )
for hist_item in self . adb . get_history ( domain ) :
# tx should not be mined yet
if hist_item . tx_mined_status . conf > 0 : continue
# conservative future proofing of code: only allow known unconfirmed types
@ -1259,7 +1333,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
for output_idx , o in enumerate ( tx . outputs ( ) ) ] ) :
continue
# all inputs should be is_mine
if not all ( [ self . is_mine ( self . get_txin_address ( txin ) ) for txin in tx . inputs ( ) ] ) :
if not all ( [ self . is_mine ( self . adb . get_txin_address ( txin ) ) for txin in tx . inputs ( ) ] ) :
continue
# do not mutate LN funding txs, as that would change their txid
if self . is_lightning_funding_tx ( txid ) :
@ -1392,7 +1466,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
if self . config . get ( ' batch_rbf ' , False ) and base_tx :
# make sure we don't try to spend change from the tx-to-be-replaced:
coins = [ c for c in coins if c . prevout . txid . hex ( ) != base_tx . txid ( ) ]
is_local = self . get_tx_height ( base_tx . txid ( ) ) . height == TX_HEIGHT_LOCAL
is_local = self . adb . get_tx_height ( base_tx . txid ( ) ) . height == TX_HEIGHT_LOCAL
base_tx = PartialTransaction . from_tx ( base_tx )
base_tx . add_info_from_wallet ( self )
base_tx_fee = base_tx . get_fee ( )
@ -1512,7 +1586,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
# we should typically have the funding tx available;
# might not have it e.g. while not up_to_date
return True
if any ( self . is_mine ( self . get_txin_address ( txin ) )
if any ( self . is_mine ( self . adb . get_txin_address ( txin ) )
for txin in funding_tx . inputs ( ) ) :
return False
return True
@ -1565,12 +1639,12 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
needs_spv_check = not self . config . get ( " skipmerklecheck " , False )
for tx_hash , tx_height in h :
if needs_spv_check :
tx_age = self . get_tx_height ( tx_hash ) . conf
tx_age = self . adb . get_tx_height ( tx_hash ) . conf
else :
if tx_height < = 0 :
tx_age = 0
else :
tx_age = self . get_local_height ( ) - tx_height + 1
tx_age = self . adb . get_local_height ( ) - tx_height + 1
max_conf = max ( max_conf , tx_age )
return max_conf > = req_conf
@ -1835,7 +1909,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
break
else :
raise CannotCPFP ( _ ( " Could not find suitable output " ) )
coins = self . get_addr_utxo ( address )
coins = self . adb . get_addr_utxo ( address )
item = coins . get ( TxOutpoint . from_str ( txid + ' : %d ' % i ) )
if not item :
raise CannotCPFP ( _ ( " Could not find coins for output " ) )
@ -1881,7 +1955,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
raise CannotDoubleSpendTx ( _ ( " The new fee rate needs to be higher than the old fee rate. " ) )
# grab all ismine inputs
inputs = [ txin for txin in tx . inputs ( )
if self . is_mine ( self . get_txin_address ( txin ) ) ]
if self . is_mine ( self . adb . get_txin_address ( txin ) ) ]
value = sum ( [ txin . value_sats ( ) for txin in inputs ] )
# figure out output address
old_change_addrs = [ o . address for o in tx . outputs ( ) if self . is_mine ( o . address ) ]
@ -1925,7 +1999,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
# in which case we might include a WITNESS_UTXO.
address = address or txin . address
if txin . witness_utxo is None and txin . is_segwit ( ) and address :
received , spent = self . get_addr_io ( address )
received , spent = self . adb . get_addr_io ( address )
item = received . get ( txin . prevout . to_str ( ) )
if item :
txin_value = item [ 1 ]
@ -1949,7 +2023,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
only_der_suffix : bool = False ,
ignore_network_issues : bool = True ,
) - > None :
address = self . get_txin_address ( txin )
address = self . adb . get_txin_address ( txin )
# note: we add input utxos regardless of is_mine
self . _add_input_utxo_info ( txin , ignore_network_issues = ignore_network_issues , address = address )
is_mine = self . is_mine ( address )
@ -2006,8 +2080,8 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
raw_tx = self . network . run_from_another_thread (
self . network . get_transaction ( tx_hash , timeout = 10 ) )
except NetworkException as e :
self . logger . info ( f ' got network error getting input txn. err: { repr ( e ) } . txid: { tx_hash } . '
f ' if you are intentionally offline, consider using the --offline flag ' )
_ logger. info ( f ' got network error getting input txn. err: { repr ( e ) } . txid: { tx_hash } . '
f ' if you are intentionally offline, consider using the --offline flag ' )
if not ignore_network_issues :
raise e
else :
@ -2082,7 +2156,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
# TODO we should index receive_requests by id
# add lightning requests. (use as key)
in_use_by_request = set ( self . receive_requests . keys ( ) )
return [ addr for addr in domain if not self . is_used ( addr )
return [ addr for addr in domain if not self . adb . is_used ( addr )
and addr not in in_use_by_request ]
@check_returned_address_for_corruption
@ -2105,7 +2179,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
raise Exception ( " no receiving addresses in wallet?! " )
choice = domain [ 0 ]
for addr in domain :
if not self . is_used ( addr ) :
if not self . adb . is_used ( addr ) :
if addr not in self . receive_requests . keys ( ) :
return addr
else :
@ -2128,12 +2202,12 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
def get_onchain_request_status ( self , r : Invoice ) - > Tuple [ bool , Optional [ int ] ] :
address = r . get_address ( )
amount = int ( r . get_amount_sat ( ) or 0 )
received , sent = self . get_addr_io ( address )
received , sent = self . adb . get_addr_io ( address )
l = [ ]
for txo , x in received . items ( ) :
h , v , is_cb = x
txid , n = txo . split ( ' : ' )
tx_height = self . get_tx_height ( txid )
tx_height = self . adb . get_tx_height ( txid )
height = tx_height . height
if height > 0 and height < = r . height :
continue
@ -2276,19 +2350,6 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
d [ ' bip70 ' ] = x . bip70
return d
def receive_tx_callback ( self , tx_hash , tx , tx_height ) :
super ( ) . receive_tx_callback ( tx_hash , tx , tx_height )
self . _update_request_statuses_touched_by_tx ( tx_hash )
def add_verified_tx ( self , tx_hash , info ) :
super ( ) . add_verified_tx ( tx_hash , info )
self . _update_request_statuses_touched_by_tx ( tx_hash )
def undo_verifications ( self , blockchain , above_height ) :
reorged_txids = super ( ) . undo_verifications ( blockchain , above_height )
for txid in reorged_txids :
self . _update_request_statuses_touched_by_tx ( txid )
def _update_request_statuses_touched_by_tx ( self , tx_hash : str ) - > None :
# FIXME in some cases if tx2 replaces unconfirmed tx1 in the mempool, we are not called.
# For a given receive request, if tx1 touches it but tx2 does not, then
@ -2310,7 +2371,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
fallback_address = address if self . config . get ( ' bolt11_fallback ' , True ) else None
lightning_invoice = self . lnworker . add_request ( amount_sat , message , exp_delay , fallback_address ) if lightning else None
outputs = [ PartialTxOutput . from_address_and_value ( address , amount_sat ) ] if address else [ ]
height = self . get_local_height ( )
height = self . adb . get_local_height ( )
req = Invoice (
outputs = outputs ,
message = message ,
@ -2502,7 +2563,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
def price_at_timestamp ( self , txid , price_func ) :
""" Returns fiat price of bitcoin at the time tx got confirmed. """
timestamp = self . get_tx_height ( txid ) . timestamp
timestamp = self . adb . get_tx_height ( txid ) . timestamp
return price_func ( timestamp if timestamp else time . time ( ) )
def average_price ( self , txid , price_func , ccy ) - > Decimal :
@ -2663,6 +2724,9 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
else :
return allow_send , long_warning , short_warning
def synchronize ( self ) - > int :
""" Returns the number of new addresses we generated. """
return 0
class Simple_Wallet ( Abstract_Wallet ) :
# wallet with a single keystore
@ -2766,7 +2830,7 @@ class Imported_Wallet(Simple_Wallet):
continue
good_addr . append ( address )
self . db . add_imported_address ( address , { } )
self . add_address ( address )
self . adb . ad d_address ( address )
if write_to_disk :
self . save_db ( )
return good_addr , bad_addr
@ -2787,7 +2851,7 @@ class Imported_Wallet(Simple_Wallet):
transactions_new = set ( ) # txs that are not only referred to by address
with self . lock :
for addr in self . db . get_history ( ) :
details = self . get_address_history ( addr )
details = self . adb . get_address_history ( addr )
if addr == address :
for tx_hash , height in details :
transactions_to_remove . add ( tx_hash )
@ -2797,7 +2861,7 @@ class Imported_Wallet(Simple_Wallet):
transactions_to_remove - = transactions_new
self . db . remove_addr_history ( address )
for tx_hash in transactions_to_remove :
self . _remove_transaction ( tx_hash )
self . adb . _remove_transaction ( tx_hash )
self . set_label ( address , None )
self . remove_payment_request ( address )
self . set_frozen_state_of_addresses ( [ address ] , False )
@ -2831,7 +2895,7 @@ class Imported_Wallet(Simple_Wallet):
def calc_unused_change_addresses ( self ) - > Sequence [ str ] :
with self . lock :
unused_addrs = [ addr for addr in self . get_change_addresses ( )
if not self . is_used ( addr ) and not self . is_address_reserved ( addr ) ]
if not self . adb . is_used ( addr ) and not self . is_address_reserved ( addr ) ]
return unused_addrs
def is_mine ( self , address ) - > bool :
@ -2865,7 +2929,7 @@ class Imported_Wallet(Simple_Wallet):
addr = bitcoin . pubkey_to_address ( txin_type , pubkey )
good_addr . append ( addr )
self . db . add_imported_address ( addr , { ' type ' : txin_type , ' pubkey ' : pubkey } )
self . add_address ( addr )
self . adb . ad d_address ( addr )
self . save_keystore ( )
if write_to_disk :
self . save_db ( )
@ -3055,7 +3119,7 @@ class Deterministic_Wallet(Abstract_Wallet):
n = self . db . num_change_addresses ( ) if for_change else self . db . num_receiving_addresses ( )
address = self . derive_address ( int ( for_change ) , n )
self . db . add_change_address ( address ) if for_change else self . db . add_receiving_address ( address )
self . add_address ( address )
self . adb . ad d_address ( address )
if for_change :
# note: if it's actually "old", it will get filtered later
self . _not_old_change_addresses . append ( address )
@ -3081,7 +3145,7 @@ class Deterministic_Wallet(Abstract_Wallet):
break
return count
@AddressSynchronizer . with_local_height_cached
#@AddressSynchronizer.with_local_height_cached FIXME
def synchronize ( self ) :
count = 0
with self . lock :