@@ -2569,7 +2569,43 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
2569
2569
std::vector<COutput> vAvailableCoins;
2570
2570
AvailableCoins (vAvailableCoins, true , coinControl);
2571
2571
2572
+ // Create change script that will be used if we need change
2573
+ // TODO: pass in scriptChange instead of reservekey so
2574
+ // change transaction isn't always pay-to-bitcoin-address
2575
+ CScript scriptChange;
2576
+
2577
+ // coin control: send change to custom address
2578
+ if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange ))
2579
+ scriptChange = GetScriptForDestination (coinControl->destChange );
2580
+
2581
+ // no coin control: send change to newly generated address
2582
+ else
2583
+ {
2584
+ // Note: We use a new key here to keep it from being obvious which side is the change.
2585
+ // The drawback is that by not reusing a previous key, the change may be lost if a
2586
+ // backup is restored, if the backup doesn't have the new private key for the change.
2587
+ // If we reused the old key, it would be possible to add code to look for and
2588
+ // rediscover unknown transactions that were written with keys of ours to recover
2589
+ // post-backup change.
2590
+
2591
+ // Reserve a new key pair from key pool
2592
+ CPubKey vchPubKey;
2593
+ bool ret;
2594
+ ret = reservekey.GetReservedKey (vchPubKey, true );
2595
+ if (!ret)
2596
+ {
2597
+ strFailReason = _ (" Keypool ran out, please call keypoolrefill first" );
2598
+ return false ;
2599
+ }
2600
+
2601
+ scriptChange = GetScriptForDestination (vchPubKey.GetID ());
2602
+ }
2603
+ CTxOut change_prototype_txout (0 , scriptChange);
2604
+ size_t change_prototype_size = GetSerializeSize (change_prototype_txout, SER_DISK, 0 );
2605
+
2572
2606
nFeeRet = 0 ;
2607
+ bool pick_new_inputs = true ;
2608
+ CAmount nValueIn = 0 ;
2573
2609
// Start with no fee and loop until there is enough fee
2574
2610
while (true )
2575
2611
{
@@ -2615,49 +2651,21 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
2615
2651
}
2616
2652
2617
2653
// Choose coins to use
2618
- CAmount nValueIn = 0 ;
2619
- setCoins.clear ();
2620
- if (!SelectCoins (vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
2621
- {
2622
- strFailReason = _ (" Insufficient funds" );
2623
- return false ;
2654
+ if (pick_new_inputs) {
2655
+ nValueIn = 0 ;
2656
+ setCoins.clear ();
2657
+ if (!SelectCoins (vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
2658
+ {
2659
+ strFailReason = _ (" Insufficient funds" );
2660
+ return false ;
2661
+ }
2624
2662
}
2625
2663
2626
2664
const CAmount nChange = nValueIn - nValueToSelect;
2665
+
2627
2666
if (nChange > 0 )
2628
2667
{
2629
2668
// Fill a vout to ourself
2630
- // TODO: pass in scriptChange instead of reservekey so
2631
- // change transaction isn't always pay-to-bitcoin-address
2632
- CScript scriptChange;
2633
-
2634
- // coin control: send change to custom address
2635
- if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange ))
2636
- scriptChange = GetScriptForDestination (coinControl->destChange );
2637
-
2638
- // no coin control: send change to newly generated address
2639
- else
2640
- {
2641
- // Note: We use a new key here to keep it from being obvious which side is the change.
2642
- // The drawback is that by not reusing a previous key, the change may be lost if a
2643
- // backup is restored, if the backup doesn't have the new private key for the change.
2644
- // If we reused the old key, it would be possible to add code to look for and
2645
- // rediscover unknown transactions that were written with keys of ours to recover
2646
- // post-backup change.
2647
-
2648
- // Reserve a new key pair from key pool
2649
- CPubKey vchPubKey;
2650
- bool ret;
2651
- ret = reservekey.GetReservedKey (vchPubKey, true );
2652
- if (!ret)
2653
- {
2654
- strFailReason = _ (" Keypool ran out, please call keypoolrefill first" );
2655
- return false ;
2656
- }
2657
-
2658
- scriptChange = GetScriptForDestination (vchPubKey.GetID ());
2659
- }
2660
-
2661
2669
CTxOut newTxOut (nChange, scriptChange);
2662
2670
2663
2671
// Never create dust outputs; if we would, just
@@ -2666,7 +2674,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
2666
2674
{
2667
2675
nChangePosInOut = -1 ;
2668
2676
nFeeRet += nChange;
2669
- reservekey.ReturnKey ();
2670
2677
}
2671
2678
else
2672
2679
{
@@ -2685,7 +2692,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
2685
2692
txNew.vout .insert (position, newTxOut);
2686
2693
}
2687
2694
} else {
2688
- reservekey.ReturnKey ();
2689
2695
nChangePosInOut = -1 ;
2690
2696
}
2691
2697
@@ -2740,16 +2746,30 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
2740
2746
}
2741
2747
2742
2748
if (nFeeRet >= nFeeNeeded) {
2743
- // Reduce fee to only the needed amount if we have change
2744
- // output to increase. This prevents potential overpayment
2745
- // in fees if the coins selected to meet nFeeNeeded result
2746
- // in a transaction that requires less fee than the prior
2747
- // iteration.
2749
+ // Reduce fee to only the needed amount if possible. This
2750
+ // prevents potential overpayment in fees if the coins
2751
+ // selected to meet nFeeNeeded result in a transaction that
2752
+ // requires less fee than the prior iteration.
2753
+
2748
2754
// TODO: The case where nSubtractFeeFromAmount > 0 remains
2749
2755
// to be addressed because it requires returning the fee to
2750
2756
// the payees and not the change output.
2751
- // TODO: The case where there is no change output remains
2752
- // to be addressed so we avoid creating too small an output.
2757
+
2758
+ // If we have no change and a big enough excess fee, then
2759
+ // try to construct transaction again only without picking
2760
+ // new inputs. We now know we only need the smaller fee
2761
+ // (because of reduced tx size) and so we should add a
2762
+ // change output. Only try this once.
2763
+ CAmount fee_needed_for_change = GetMinimumFee (change_prototype_size, currentConfirmationTarget, ::mempool, ::feeEstimator, nullptr , false /* ignoreGlobalPayTxFee */ , conservative_estimate);
2764
+ CAmount minimum_value_for_change = GetDustThreshold (change_prototype_txout, ::dustRelayFee);
2765
+ CAmount max_excess_fee = fee_needed_for_change + minimum_value_for_change;
2766
+ if (nFeeRet > nFeeNeeded + max_excess_fee && nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) {
2767
+ pick_new_inputs = false ;
2768
+ nFeeRet = nFeeNeeded + fee_needed_for_change;
2769
+ continue ;
2770
+ }
2771
+
2772
+ // If we have change output already, just increase it
2753
2773
if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0 ) {
2754
2774
CAmount extraFeePaid = nFeeRet - nFeeNeeded;
2755
2775
std::vector<CTxOut>::iterator change_position = txNew.vout .begin ()+nChangePosInOut;
@@ -2758,6 +2778,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
2758
2778
}
2759
2779
break ; // Done, enough fee included.
2760
2780
}
2781
+ else if (!pick_new_inputs) {
2782
+ // This shouldn't happen, we should have had enough excess
2783
+ // fee to pay for the new output and still meet nFeeNeeded
2784
+ strFailReason = _ (" Transaction fee and change calculation failed" );
2785
+ return false ;
2786
+ }
2761
2787
2762
2788
// Try to reduce change to include necessary fee
2763
2789
if (nChangePosInOut != -1 && nSubtractFeeFromAmount == 0 ) {
@@ -2777,6 +2803,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
2777
2803
}
2778
2804
}
2779
2805
2806
+ if (nChangePosInOut == -1 ) reservekey.ReturnKey (); // Return any reserved key if we don't have change
2807
+
2780
2808
if (sign)
2781
2809
{
2782
2810
CTransaction txNewConst (txNew);
0 commit comments