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