Browse Source

wallet: (regression) fix get_spendable_coins when "domain" arg is given

`get_spendable_coins` was ignoring the "domain" param, and returning utxos for the whole wallet
patch-4
SomberNight 3 years ago
parent
commit
2c73e7f854
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 35
      electrum/tests/test_wallet_vertical.py
  2. 28
      electrum/wallet.py

35
electrum/tests/test_wallet_vertical.py

@ -2412,6 +2412,41 @@ class TestWalletSending(TestCaseForTestnet):
self.assertEqual('02000000000101ce010c0cab95cde544f713771916613a1a84c8787bbc95321854410b212aed9b0100000000fdffffff02cac00000000000001600147a65e09bb1da80abfc65d545388a2e61aab7c721eec100000000000016001405424089c64d39d9a498b6e1c8e646327431b240024730440220526eac6c56cba19842b67f6c9e45af113b1a2d44fb229335bdeaf08cb2cc164e0220087fba65619016fd3f62f6c8717070e48f94b45743b86d8e0517698d2b9c3afc012102d67eaa10463f5c786271feb9ae3456c27d35c3cf6c7d881617e915d1f32cb875c4951e00', self.assertEqual('02000000000101ce010c0cab95cde544f713771916613a1a84c8787bbc95321854410b212aed9b0100000000fdffffff02cac00000000000001600147a65e09bb1da80abfc65d545388a2e61aab7c721eec100000000000016001405424089c64d39d9a498b6e1c8e646327431b240024730440220526eac6c56cba19842b67f6c9e45af113b1a2d44fb229335bdeaf08cb2cc164e0220087fba65619016fd3f62f6c8717070e48f94b45743b86d8e0517698d2b9c3afc012102d67eaa10463f5c786271feb9ae3456c27d35c3cf6c7d881617e915d1f32cb875c4951e00',
str(tx_copy)) str(tx_copy))
@mock.patch.object(wallet.Abstract_Wallet, 'save_db')
def test_get_spendable_coins(self, mock_save_db):
wallet = self.create_standard_wallet_from_seed('frost repair depend effort salon ring foam oak cancel receive save usage',
config=self.config)
# bootstrap wallet (incoming funding_tx1)
funding_tx1 = Transaction('01000000000102acd6459dec7c3c51048eb112630da756f5d4cb4752b8d39aa325407ae0885cba020000001716001455c7f5e0631d8e6f5f05dddb9f676cec48845532fdffffffd146691ef6a207b682b13da5f2388b1f0d2a2022c8cfb8dc27b65434ec9ec8f701000000171600147b3be8a7ceaf15f57d7df2a3d216bc3c259e3225fdffffff02a9875b000000000017a914ea5a99f83e71d1c1dfc5d0370e9755567fe4a141878096980000000000160014d4ca56fcbad98fb4dcafdc573a75d6a6fffb09b702483045022100dde1ba0c9a2862a65791b8d91295a6603207fb79635935a67890506c214dd96d022046c6616642ef5971103c1db07ac014e63fa3b0e15c5729eacdd3e77fcb7d2086012103a72410f185401bb5b10aaa30989c272b554dc6d53bda6da85a76f662723421af024730440220033d0be8f74e782fbcec2b396647c7715d2356076b442423f23552b617062312022063c95cafdc6d52ccf55c8ee0f9ceb0f57afb41ea9076eb74fe633f59c50c6377012103b96a4954d834fbcfb2bbf8cf7de7dc2b28bc3d661c1557d1fd1db1bfc123a94abb391400')
funding_txid1 = funding_tx1.txid()
self.assertEqual('52e669a20a26c8b3df5b41e5e6309b18bcde8e1ad7ea17a18f63b6dc6c8becc0', funding_txid1)
wallet.adb.receive_tx_callback(funding_txid1, funding_tx1, TX_HEIGHT_UNCONFIRMED)
# another incoming transaction (funding_tx2)
funding_tx2 = Transaction('01000000000101c0ec8b6cdcb6638fa117ead71a8edebc189b30e6e5415bdfb3c8260aa269e6520000000017160014ba9ca815474a674ff1efb3fc82cf0f3460de8c57fdffffff0230390f000000000017a9148b59abaca8215c0d4b18cbbf715550aa2b50c85b87404b4c000000000016001483c3bc7234f17a209cc5dcce14903b54ee4dab9002473044022038a05f7d38bcf810dfebb39f1feda5cc187da4cf5d6e56986957ddcccedc75d302203ab67ccf15431b4e2aeeab1582b9a5a7821e7ac4be8ebf512505dbfdc7e094fd0121032168234e0ba465b8cedc10173ea9391725c0f6d9fa517641af87926626a5144abd391400')
funding_txid2 = funding_tx2.txid()
self.assertEqual('c36a6e1cd54df108e69574f70bc9b88dc13beddc70cfad9feb7f8f6593255d4a', funding_txid2)
wallet.adb.receive_tx_callback(funding_txid2, funding_tx2, TX_HEIGHT_UNCONFIRMED)
self.assertEqual((0, 15_000_000, 0), wallet.get_balance())
self.assertEqual(
{'c36a6e1cd54df108e69574f70bc9b88dc13beddc70cfad9feb7f8f6593255d4a:1',
'52e669a20a26c8b3df5b41e5e6309b18bcde8e1ad7ea17a18f63b6dc6c8becc0:1'},
{txi.prevout.to_str() for txi in wallet.get_spendable_coins()})
self.assertEqual(
{'52e669a20a26c8b3df5b41e5e6309b18bcde8e1ad7ea17a18f63b6dc6c8becc0:1'},
{txi.prevout.to_str() for txi in wallet.get_spendable_coins(["tb1q6n99dl96mx8mfh90m3tn5awk5mllkzdh25dw7z"])})
# test freezing an address
wallet.set_frozen_state_of_addresses(["tb1q6n99dl96mx8mfh90m3tn5awk5mllkzdh25dw7z"], freeze=True)
self.assertEqual(
{'c36a6e1cd54df108e69574f70bc9b88dc13beddc70cfad9feb7f8f6593255d4a:1'},
{txi.prevout.to_str() for txi in wallet.get_spendable_coins()})
wallet.set_frozen_state_of_addresses(["tb1q6n99dl96mx8mfh90m3tn5awk5mllkzdh25dw7z"], freeze=False)
self.assertEqual(
{'c36a6e1cd54df108e69574f70bc9b88dc13beddc70cfad9feb7f8f6593255d4a:1',
'52e669a20a26c8b3df5b41e5e6309b18bcde8e1ad7ea17a18f63b6dc6c8becc0:1'},
{txi.prevout.to_str() for txi in wallet.get_spendable_coins()})
class TestWalletOfflineSigning(TestCaseForTestnet): class TestWalletOfflineSigning(TestCaseForTestnet):

28
electrum/wallet.py

@ -40,7 +40,7 @@ from functools import partial
from collections import defaultdict from collections import defaultdict
from numbers import Number from numbers import Number
from decimal import Decimal 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, Iterable
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
import itertools import itertools
import threading import threading
@ -830,19 +830,31 @@ class Abstract_Wallet(ABC, Logger, EventListener):
def get_addr_balance(self, address): def get_addr_balance(self, address):
return self.adb.get_balance([address]) return self.adb.get_balance([address])
def get_utxos(self, **kwargs): def get_utxos(
domain = self.get_addresses() self,
domain: Optional[Iterable[str]] = None,
**kwargs,
):
if domain is None:
domain = self.get_addresses()
return self.adb.get_utxos(domain=domain, **kwargs) return self.adb.get_utxos(domain=domain, **kwargs)
def get_spendable_coins(self, domain, *, nonlocal_only=False) -> Sequence[PartialTxInput]: def get_spendable_coins(
self,
domain: Optional[Iterable[str]] = None,
*,
nonlocal_only: bool = False,
) -> Sequence[PartialTxInput]:
confirmed_only = self.config.get('confirmed_only', False) confirmed_only = self.config.get('confirmed_only', False)
with self._freeze_lock: with self._freeze_lock:
frozen_addresses = self._frozen_addresses.copy() frozen_addresses = self._frozen_addresses.copy()
utxos = self.get_utxos( utxos = self.get_utxos(
excluded_addresses=frozen_addresses, domain=domain,
mature_only=True, excluded_addresses=frozen_addresses,
confirmed_funding_only=confirmed_only, mature_only=True,
nonlocal_only=nonlocal_only) confirmed_funding_only=confirmed_only,
nonlocal_only=nonlocal_only,
)
utxos = [utxo for utxo in utxos if not self.is_frozen_coin(utxo)] utxos = [utxo for utxo in utxos if not self.is_frozen_coin(utxo)]
return utxos return utxos

Loading…
Cancel
Save