Skip to content

Commit c88529a

Browse files
author
MarcoFalke
committed
Merge #13805: [wallet] Correctly limit output group size
a13647b [qa] Add test for too-large wallet output groups (Suhas Daftuar) 57ec1c9 [wallet] correctly limit output group size (Suhas Daftuar) Pull request description: Also add a test to ensure that output groups are being limited, even if a wallet has many outputs corresponding to the same scriptPubKey (the test fails without the first commit). Tree-SHA512: 2aaa82005b0910488f5cbf40690d4c5e2f46949e299ef70b4cb6e440713811443d411dcbc6d71b1701fd82423073125e21747787d70830cd021c841afb732d51
2 parents e83d82a + a13647b commit c88529a

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

src/wallet/wallet.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4424,7 +4424,10 @@ std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outpu
44244424
size_t ancestors, descendants;
44254425
mempool.GetTransactionAncestry(output.tx->GetHash(), ancestors, descendants);
44264426
if (!single_coin && ExtractDestination(output.tx->tx->vout[output.i].scriptPubKey, dst)) {
4427-
if (gmap.count(dst) == 10) {
4427+
// Limit output groups to no more than 10 entries, to protect
4428+
// against inadvertently creating a too-large transaction
4429+
// when using -avoidpartialspends
4430+
if (gmap[dst].m_outputs.size() >= 10) {
44284431
groups.push_back(gmap[dst]);
44294432
gmap.erase(dst);
44304433
}

test/functional/wallet_groups.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
"""Test wallet group functionality."""
66

77
from test_framework.test_framework import BitcoinTestFramework
8+
from test_framework.mininode import FromHex, ToHex
9+
from test_framework.messages import CTransaction
810
from test_framework.util import (
911
assert_equal,
1012
)
@@ -63,5 +65,29 @@ def run_test (self):
6365
assert_approx(v[0], 0.2)
6466
assert_approx(v[1], 1.3, 0.0001)
6567

68+
# Empty out node2's wallet
69+
self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=self.nodes[2].getbalance(), subtractfeefromamount=True)
70+
self.sync_all()
71+
self.nodes[0].generate(1)
72+
73+
# Fill node2's wallet with 10000 outputs corresponding to the same
74+
# scriptPubKey
75+
for i in range(5):
76+
raw_tx = self.nodes[0].createrawtransaction([{"txid":"0"*64, "vout":0}], [{addr2[0]: 0.05}])
77+
tx = FromHex(CTransaction(), raw_tx)
78+
tx.vin = []
79+
tx.vout = [tx.vout[0]] * 2000
80+
funded_tx = self.nodes[0].fundrawtransaction(ToHex(tx))
81+
signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx['hex'])
82+
self.nodes[0].sendrawtransaction(signed_tx['hex'])
83+
self.nodes[0].generate(1)
84+
85+
self.sync_all()
86+
87+
# Check that we can create a transaction that only requires ~100 of our
88+
# utxos, without pulling in all outputs and creating a transaction that
89+
# is way too big.
90+
assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)
91+
6692
if __name__ == '__main__':
6793
WalletGroupTest().main ()

0 commit comments

Comments
 (0)