1
1
from electrum .coinchooser import CoinChooserPrivacy
2
2
from electrum .util import NotEnoughFunds
3
- from electrum .transaction import PartialTxInput , TxOutpoint , Transaction
4
- from electrum .fee_policy import FeePolicy
3
+ from electrum .transaction import PartialTxInput , TxOutpoint , Transaction , PartialTxOutput
4
+ from electrum .fee_policy import FeePolicy , FixedFeePolicy
5
5
from functools import partial
6
+ from typing import Optional
6
7
7
8
from . import ElectrumTestCase
8
9
9
10
10
11
class TestCoinChooser (ElectrumTestCase ):
11
12
13
+ @staticmethod
14
+ def get_dummy_txin_1_284_474_sat () -> PartialTxInput :
15
+ # value of 1_284_474 sat
16
+ prevout_txid = bytes .fromhex (
17
+ "b3d9174cb5d3234764a089bb91fdbd1117b7958be4870d1a544136ab017a67dd"
18
+ )
19
+ coin = PartialTxInput (
20
+ prevout = TxOutpoint (txid = prevout_txid , out_idx = 0 ),
21
+ )
22
+ coin .utxo = Transaction (
23
+ "02000000000105a5a00ad10e754a17154446bbe1c557b44b86a7cd53308ad9ab813388a9d6d1520000000000fdffffff2c48659d10a752b0c0a3efa4092ebee5210943a2f41ff0607ba0e03a4cdf7bbd0000000000fdffffff93f4feb485581654caffa523c500dc417a98097fb731045040bb162acb3e14e90000000000fdffffffbf4b69292acaabf8a415db412eedd8a202d4dd2ca12e532628a756276fec00f50000000000fdffffffa96e18c45ecc56608d0be3c1b2cd93e52d569a9c3a68ed51aead570beeef29ff0000000000fdffffff017a991300000000001600142a55fbef3e419e1c862632a826ae89ade0b07e3a0247304402204de416135d26711df2cbd5209e3f79f95a1de5ddea5980215606ebfe639747bd0220286f9de38a96a078c818e97fe6fbbbe3637287461cd7407adf9e85ba6d899005012102c329033555adccaadb6c83fb486f540ba00aad3edba7a4ec3347b5cc0935c4050247304402200132c1c4c41b840f05efeacf96cccedab38d68c9021c79f940738572b049c1a302200d59ba4719d4d4e55ced651cde35cbf79838bf7122cbafd6584dd934a67db0ed01210380194ab3704b5524a0c97f78b4458b80efd365faaedaebe90fa7807eeab041700247304402202c966fbea5db4bb3794e843b59240d678a3c8e97be1d10c18475a467c101b97c02203edb0ca11e7605af2437ddffbbe416317bca8788c23c4816c13698042222d30f0121035edcdcad9affcff41302ad49a19ccbd47ae50b153ba7c2abaaf3bb2d22c859120247304402206890a622513bb9c8b8ca83e5e82532f9753ecd3188c27d8da9452e264f5500cc022012dad8fb872478b7f9d0d9d310859fca6534b8e9f44511eeef5450beaf13c690012103f683aa56e036b1307c1ae75e81553b6730aea312560e36afad487ba2bc6cf98f02473044022006807df115d6bce73e384651fbb9e932ee313133218be7769e52809b758529b6022078b2859f98a62211f130e69982f96d2968e1820c58bb817f9ab31645b6b4ceae0121026402c3c0a2b4dd5703686f8c5b5b3dcecbbf4d772ef83e440bfad22b742753e730a60300"
24
+ )
25
+ coin .block_height = 100
26
+ return coin
27
+
28
+ @staticmethod
29
+ def get_dummy_txout_1 (amount : Optional [int ] = 1000000 ) -> PartialTxOutput :
30
+ output = PartialTxOutput .from_address_and_value (
31
+ address = "bc1q2089yvkkyw7yq7m6a7lxt45n35c587hk4sgj7c" ,
32
+ value = amount ,
33
+ )
34
+ return output
35
+
12
36
def test_bucket_candidates_with_empty_buckets (self ):
13
37
def sufficient_funds (buckets , * , bucket_value_sum ):
14
38
return True
@@ -34,12 +58,7 @@ def test_make_tx_no_outputs_adds_change(self):
34
58
single_txin .utxo = Transaction ("02000000000101956449bdc8059b680a20483e64e139ce63fe64333b92cd7811a1b116d6b967ad0000000000fdffffff024a01000000000000160014a21d1fbcf571153f57b40855e059c134405a89ecd682010000000000160014fd7debf75d6c410bf6ba1c8ba05f90f23ce4646a0247304402207f07ec0c2415b31743527dea2f7bff3868f494dc0a5d45adec5e05031725a0af02202aa0ac7d06dbcad8ac0b9808a829b6bdaa98bc831aef31a5ab4e5d1890f7552101210278a5d9b2796f2743ccf1b36b2bf47695d766d0841c17b00ce83943c8b37dde0ceea60300" )
35
59
36
60
# dummy input to be used as potential additional input of higher value
37
- prevout_txid = bytes .fromhex ("b3d9174cb5d3234764a089bb91fdbd1117b7958be4870d1a544136ab017a67dd" )
38
- coin = PartialTxInput (
39
- prevout = TxOutpoint (txid = prevout_txid , out_idx = 0 ),
40
- )
41
- coin .utxo = Transaction ("02000000000105a5a00ad10e754a17154446bbe1c557b44b86a7cd53308ad9ab813388a9d6d1520000000000fdffffff2c48659d10a752b0c0a3efa4092ebee5210943a2f41ff0607ba0e03a4cdf7bbd0000000000fdffffff93f4feb485581654caffa523c500dc417a98097fb731045040bb162acb3e14e90000000000fdffffffbf4b69292acaabf8a415db412eedd8a202d4dd2ca12e532628a756276fec00f50000000000fdffffffa96e18c45ecc56608d0be3c1b2cd93e52d569a9c3a68ed51aead570beeef29ff0000000000fdffffff017a991300000000001600142a55fbef3e419e1c862632a826ae89ade0b07e3a0247304402204de416135d26711df2cbd5209e3f79f95a1de5ddea5980215606ebfe639747bd0220286f9de38a96a078c818e97fe6fbbbe3637287461cd7407adf9e85ba6d899005012102c329033555adccaadb6c83fb486f540ba00aad3edba7a4ec3347b5cc0935c4050247304402200132c1c4c41b840f05efeacf96cccedab38d68c9021c79f940738572b049c1a302200d59ba4719d4d4e55ced651cde35cbf79838bf7122cbafd6584dd934a67db0ed01210380194ab3704b5524a0c97f78b4458b80efd365faaedaebe90fa7807eeab041700247304402202c966fbea5db4bb3794e843b59240d678a3c8e97be1d10c18475a467c101b97c02203edb0ca11e7605af2437ddffbbe416317bca8788c23c4816c13698042222d30f0121035edcdcad9affcff41302ad49a19ccbd47ae50b153ba7c2abaaf3bb2d22c859120247304402206890a622513bb9c8b8ca83e5e82532f9753ecd3188c27d8da9452e264f5500cc022012dad8fb872478b7f9d0d9d310859fca6534b8e9f44511eeef5450beaf13c690012103f683aa56e036b1307c1ae75e81553b6730aea312560e36afad487ba2bc6cf98f02473044022006807df115d6bce73e384651fbb9e932ee313133218be7769e52809b758529b6022078b2859f98a62211f130e69982f96d2968e1820c58bb817f9ab31645b6b4ceae0121026402c3c0a2b4dd5703686f8c5b5b3dcecbbf4d772ef83e440bfad22b742753e730a60300" )
42
- coin .block_height = 100
61
+ coin = self .get_dummy_txin_1_284_474_sat ()
43
62
44
63
tx = coin_chooser .make_tx (
45
64
coins = [coin ],
@@ -72,3 +91,21 @@ def test_make_tx_no_outputs_adds_change(self):
72
91
assert len (tx .outputs ()) == 1 , f"expected 1 output got { len (tx .outputs ())} "
73
92
assert len (tx .inputs ()) == 1 , f"expected 1 input got { len (tx .inputs ())} "
74
93
94
+ def test_doesnt_round_output_value_with_zerofee_estimator (self ):
95
+ # output value rounding is enabled (as by default)
96
+ coin_chooser = CoinChooserPrivacy (enable_output_value_rounding = True )
97
+
98
+ # fixed fee estimator always returns 0
99
+ fee_estimator = FixedFeePolicy (0 ).estimate_fee
100
+
101
+ tx = coin_chooser .make_tx (
102
+ coins = [],
103
+ inputs = [self .get_dummy_txin_1_284_474_sat ()] ,
104
+ outputs = [self .get_dummy_txout_1 (1_000_000 )],
105
+ change_addrs = [],
106
+ fee_estimator_vb = fee_estimator ,
107
+ dust_threshold = 500 ,
108
+ )
109
+ assert tx .get_fee () == 0 , f"fee should be 0, is { tx .get_fee ()} "
110
+ assert len (tx .outputs ()) == 2 , f"expected 2 output got { len (tx .outputs ())} "
111
+ assert len (tx .inputs ()) == 1 , f"expected 1 input got { len (tx .inputs ())} "
0 commit comments