Skip to content

Commit 9f6449a

Browse files
committed
Merge bitcoin#518: [Wallet] Combine fees when possible and fix autocombine insufficient funds
eb603b4 [Wallet] Fix autocombine (warrows) 3f9e746 [Wallet] Combine change to output when possible & provide it in autocombine (warrows) 10426c7 [Wallet] Increase fee margin to up to 10% of autocombine send (warrows) Tree-SHA512: e3452b0862b30c5c7f21697d12485e7b009dda3b4225e9685209425cb4a16baf35dd9d591b39ece077c3314f7c344f23b3810e5d0d840a8003c7d7d09f5c7ae4
2 parents fd8aa89 + eb603b4 commit 9f6449a

File tree

1 file changed

+42
-18
lines changed

1 file changed

+42
-18
lines changed

src/wallet.cpp

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,11 +2713,25 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
27132713
// TODO: pass in scriptChange instead of reservekey so
27142714
// change transaction isn't always pay-to-pivx-address
27152715
CScript scriptChange;
2716+
bool combineChange = false;
27162717

27172718
// coin control: send change to custom address
2718-
if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange))
2719+
if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange)) {
27192720
scriptChange = GetScriptForDestination(coinControl->destChange);
27202721

2722+
vector<CTxOut>::iterator it = txNew.vout.begin();
2723+
while (it != txNew.vout.end()) {
2724+
if (scriptChange == it->scriptPubKey) {
2725+
it->nValue += nChange;
2726+
nChange = 0;
2727+
reservekey.ReturnKey();
2728+
combineChange = true;
2729+
break;
2730+
}
2731+
++it;
2732+
}
2733+
}
2734+
27212735
// no coin control: send change to newly generated address
27222736
else {
27232737
// Note: We use a new key here to keep it from being obvious which side is the change.
@@ -2736,18 +2750,20 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
27362750
scriptChange = GetScriptForDestination(vchPubKey.GetID());
27372751
}
27382752

2739-
CTxOut newTxOut(nChange, scriptChange);
2740-
2741-
// Never create dust outputs; if we would, just
2742-
// add the dust to the fee.
2743-
if (newTxOut.IsDust(::minRelayTxFee)) {
2744-
nFeeRet += nChange;
2745-
nChange = 0;
2746-
reservekey.ReturnKey();
2747-
} else {
2748-
// Insert change txn at random position:
2749-
vector<CTxOut>::iterator position = txNew.vout.begin() + GetRandInt(txNew.vout.size() + 1);
2750-
txNew.vout.insert(position, newTxOut);
2753+
if (!combineChange) {
2754+
CTxOut newTxOut(nChange, scriptChange);
2755+
2756+
// Never create dust outputs; if we would, just
2757+
// add the dust to the fee.
2758+
if (newTxOut.IsDust(::minRelayTxFee)) {
2759+
nFeeRet += nChange;
2760+
nChange = 0;
2761+
reservekey.ReturnKey();
2762+
} else {
2763+
// Insert change txn at random position:
2764+
vector<CTxOut>::iterator position = txNew.vout.begin() + GetRandInt(txNew.vout.size() + 1);
2765+
txNew.vout.insert(position, newTxOut);
2766+
}
27512767
}
27522768
} else
27532769
reservekey.ReturnKey();
@@ -4003,6 +4019,8 @@ void CWallet::AutoCombineDust()
40034019
CCoinControl* coinControl = new CCoinControl();
40044020
CAmount nTotalRewardsValue = 0;
40054021
BOOST_FOREACH (const COutput& out, vCoins) {
4022+
if (!out.fSpendable)
4023+
continue;
40064024
//no coins should get this far if they dont have proper maturity, this is double checking
40074025
if (out.tx->IsCoinStake() && out.tx->GetDepthInMainChain() < COINBASE_MATURITY + 1)
40084026
continue;
@@ -4034,24 +4052,30 @@ void CWallet::AutoCombineDust()
40344052
CScript scriptPubKey = GetScriptForDestination(it->first.Get());
40354053
vecSend.push_back(make_pair(scriptPubKey, nTotalRewardsValue));
40364054

4055+
//Send change to same address
4056+
CTxDestination destMyAddress;
4057+
if (!ExtractDestination(scriptPubKey, destMyAddress)) {
4058+
LogPrintf("AutoCombineDust: failed to extract destination\n");
4059+
continue;
4060+
}
4061+
coinControl->destChange = destMyAddress;
4062+
40374063
// Create the transaction and commit it to the network
40384064
CWalletTx wtx;
40394065
CReserveKey keyChange(this); // this change address does not end up being used, because change is returned with coin control switch
40404066
string strErr;
40414067
CAmount nFeeRet = 0;
40424068

4043-
//get the fee amount
4044-
CWalletTx wtxdummy;
4045-
CreateTransaction(vecSend, wtxdummy, keyChange, nFeeRet, strErr, coinControl, ALL_COINS, false, CAmount(0));
4046-
vecSend[0].second = nTotalRewardsValue - nFeeRet - 500;
4069+
// 10% safety margin to avoid "Insufficient funds" errors
4070+
vecSend[0].second = nTotalRewardsValue - (nTotalRewardsValue / 10);
40474071

40484072
if (!CreateTransaction(vecSend, wtx, keyChange, nFeeRet, strErr, coinControl, ALL_COINS, false, CAmount(0))) {
40494073
LogPrintf("AutoCombineDust createtransaction failed, reason: %s\n", strErr);
40504074
continue;
40514075
}
40524076

40534077
//we don't combine below the threshold unless the fees are 0 to avoid paying fees over fees over fees
4054-
if (vecSend[0].second < nAutoCombineThreshold * COIN && nFeeRet > 0)
4078+
if (nTotalRewardsValue < nAutoCombineThreshold * COIN && nFeeRet > 0)
40554079
continue;
40564080

40574081
if (!CommitTransaction(wtx, keyChange)) {

0 commit comments

Comments
 (0)