Skip to content

Commit fcd6671

Browse files
Andezionmadelinevibes
authored andcommitted
bitcoin/tx.c: use 330 sat dust limit for P2TR/P2WPKH change outputs Fixes #8395
Fix by checking is_elements: Elements keeps 546 sat, Bitcoin uses 330 sat. Changelog-Fixed: Transactions now correctly create change outputs >= 330 sat for P2TR/P2WPKH instead of absorbing them as fees
1 parent 8a4ffea commit fcd6671

2 files changed

Lines changed: 61 additions & 3 deletions

File tree

bitcoin/tx.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -985,9 +985,13 @@ struct amount_sat change_amount(struct amount_sat excess, u32 feerate_perkw,
985985
if (!amount_sat_sub(&excess, excess, fee))
986986
return AMOUNT_SAT(0);
987987

988-
/* Must be non-dust */
989-
if (!amount_sat_greater_eq(excess, chainparams->dust_limit))
990-
return AMOUNT_SAT(0);
988+
if (chainparams->is_elements) {
989+
if (!amount_sat_greater_eq(excess, AMOUNT_SAT(546)))
990+
return AMOUNT_SAT(0);
991+
} else {
992+
if (!amount_sat_greater_eq(excess, AMOUNT_SAT(330)))
993+
return AMOUNT_SAT(0);
994+
}
991995

992996
return excess;
993997
}

tests/test_p2tr_change_dust.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env python3
2+
"""Test P2TR change outputs with dust limit 330 sat (issue #8395)."""
3+
import unittest
4+
5+
from fixtures import * # noqa: F401,F403
6+
from fixtures import TEST_NETWORK
7+
from utils import wait_for
8+
9+
10+
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', "P2TR not yet supported on Elements")
11+
def test_p2tr_change_dust_limit(node_factory, bitcoind):
12+
13+
l1 = node_factory.get_node(feerates=(253, 253, 253, 253))
14+
15+
addr = l1.rpc.newaddr('p2tr')['p2tr']
16+
bitcoind.rpc.sendtoaddress(addr, 1.0)
17+
bitcoind.generate_block(1)
18+
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 1)
19+
20+
outputs = l1.rpc.listfunds()['outputs']
21+
assert len(outputs) == 1
22+
utxo = outputs[0]
23+
24+
utxo_amount = int(utxo['amount_msat'] / 1000)
25+
26+
target_amount = utxo_amount - 450
27+
28+
result = l1.rpc.fundpsbt(
29+
satoshi=f"{target_amount}sat",
30+
feerate="253perkw",
31+
startweight=0,
32+
excess_as_change=True
33+
)
34+
35+
assert 'change_outnum' in result, "Expected change output to be created"
36+
37+
psbt = bitcoind.rpc.decodepsbt(result['psbt'])
38+
39+
change_outnum = result['change_outnum']
40+
if 'tx' in psbt:
41+
change_output = psbt['tx']['vout'][change_outnum]
42+
change_amount_btc = float(change_output['value'])
43+
else:
44+
change_output = psbt['outputs'][change_outnum]
45+
change_amount_btc = float(change_output['amount'])
46+
47+
change_amount_sat = int(change_amount_btc * 100_000_000)
48+
49+
print(f"Change amount: {change_amount_sat} sat")
50+
51+
assert change_amount_sat >= 330, f"Change {change_amount_sat} sat should be >= 330 sat"
52+
assert change_amount_sat <= 546, f"Change {change_amount_sat} sat should be <= 546 sat (for this test)"
53+
54+
print(f"SUCCESS: P2TR change output of {change_amount_sat} sat created (between 330 and 546 sat)")

0 commit comments

Comments
 (0)