wallet: use lock when modifying frozen_{addresses,coins}
This commit is contained in:
@@ -43,6 +43,7 @@ from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, List, Optional, Tuple, Union, NamedTuple, Sequence, Dict, Any, Set
|
||||
from abc import ABC, abstractmethod
|
||||
import itertools
|
||||
import threading
|
||||
|
||||
from aiorpcx import TaskGroup
|
||||
|
||||
@@ -285,13 +286,15 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||
self.use_change = db.get('use_change', True)
|
||||
self.multiple_change = db.get('multiple_change', False)
|
||||
self._labels = db.get_dict('labels')
|
||||
self.frozen_addresses = set(db.get('frozen_addresses', []))
|
||||
self.frozen_coins = set(db.get('frozen_coins', [])) # set of txid:vout strings
|
||||
self._frozen_addresses = set(db.get('frozen_addresses', []))
|
||||
self._frozen_coins = set(db.get('frozen_coins', [])) # set of txid:vout strings
|
||||
self.fiat_value = db.get_dict('fiat_value')
|
||||
self.receive_requests = db.get_dict('payment_requests') # type: Dict[str, Invoice]
|
||||
self.invoices = db.get_dict('invoices') # type: Dict[str, Invoice]
|
||||
self._reserved_addresses = set(db.get('reserved_addresses', []))
|
||||
|
||||
self._freeze_lock = threading.Lock() # for mutating/iterating frozen_{addresses,coins}
|
||||
|
||||
self._prepare_onchain_invoice_paid_detection()
|
||||
self.calc_unused_change_addresses()
|
||||
# save wallet type the first time
|
||||
@@ -657,8 +660,10 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||
|
||||
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,
|
||||
excluded_addresses=self.frozen_addresses,
|
||||
excluded_addresses=frozen_addresses,
|
||||
mature_only=True,
|
||||
confirmed_only=confirmed_only,
|
||||
nonlocal_only=nonlocal_only)
|
||||
@@ -678,11 +683,16 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||
return self.get_receiving_addresses(slice_start=0, slice_stop=1)[0]
|
||||
|
||||
def get_frozen_balance(self):
|
||||
if not self.frozen_coins: # shortcut
|
||||
return self.get_balance(self.frozen_addresses)
|
||||
with self._freeze_lock:
|
||||
frozen_addresses = self._frozen_addresses.copy()
|
||||
frozen_coins = self._frozen_coins.copy()
|
||||
if not frozen_coins: # shortcut
|
||||
return self.get_balance(frozen_addresses)
|
||||
c1, u1, x1 = self.get_balance()
|
||||
c2, u2, x2 = self.get_balance(excluded_addresses=self.frozen_addresses,
|
||||
excluded_coins=self.frozen_coins)
|
||||
c2, u2, x2 = self.get_balance(
|
||||
excluded_addresses=frozen_addresses,
|
||||
excluded_coins=frozen_coins,
|
||||
)
|
||||
return c1-c2, u1-u2, x1-x2
|
||||
|
||||
def balance_at_timestamp(self, domain, target_timestamp):
|
||||
@@ -1309,33 +1319,33 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||
return tx
|
||||
|
||||
def is_frozen_address(self, addr: str) -> bool:
|
||||
return addr in self.frozen_addresses
|
||||
return addr in self._frozen_addresses
|
||||
|
||||
def is_frozen_coin(self, utxo: PartialTxInput) -> bool:
|
||||
prevout_str = utxo.prevout.to_str()
|
||||
return prevout_str in self.frozen_coins
|
||||
return prevout_str in self._frozen_coins
|
||||
|
||||
def set_frozen_state_of_addresses(self, addrs, freeze: bool):
|
||||
def set_frozen_state_of_addresses(self, addrs: Sequence[str], freeze: bool) -> bool:
|
||||
"""Set frozen state of the addresses to FREEZE, True or False"""
|
||||
if all(self.is_mine(addr) for addr in addrs):
|
||||
# FIXME take lock?
|
||||
if freeze:
|
||||
self.frozen_addresses |= set(addrs)
|
||||
else:
|
||||
self.frozen_addresses -= set(addrs)
|
||||
self.db.put('frozen_addresses', list(self.frozen_addresses))
|
||||
return True
|
||||
with self._freeze_lock:
|
||||
if freeze:
|
||||
self._frozen_addresses |= set(addrs)
|
||||
else:
|
||||
self._frozen_addresses -= set(addrs)
|
||||
self.db.put('frozen_addresses', list(self._frozen_addresses))
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_frozen_state_of_coins(self, utxos: Sequence[PartialTxInput], freeze: bool):
|
||||
def set_frozen_state_of_coins(self, utxos: Sequence[PartialTxInput], freeze: bool) -> None:
|
||||
"""Set frozen state of the utxos to FREEZE, True or False"""
|
||||
utxos = {utxo.prevout.to_str() for utxo in utxos}
|
||||
# FIXME take lock?
|
||||
if freeze:
|
||||
self.frozen_coins |= set(utxos)
|
||||
else:
|
||||
self.frozen_coins -= set(utxos)
|
||||
self.db.put('frozen_coins', list(self.frozen_coins))
|
||||
with self._freeze_lock:
|
||||
if freeze:
|
||||
self._frozen_coins |= set(utxos)
|
||||
else:
|
||||
self._frozen_coins -= set(utxos)
|
||||
self.db.put('frozen_coins', list(self._frozen_coins))
|
||||
|
||||
def is_address_reserved(self, addr: str) -> bool:
|
||||
# note: atm 'reserved' status is only taken into consideration for 'change addresses'
|
||||
|
||||
Reference in New Issue
Block a user