@@ -656,19 +656,22 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng
656
656
}
657
657
}
658
658
659
- static bool CreateTransactionInternal (
659
+ static std::optional<CreatedTransactionResult> CreateTransactionInternal (
660
660
CWallet& wallet,
661
661
const std::vector<CRecipient>& vecSend,
662
- CTransactionRef& tx,
663
- CAmount& nFeeRet,
664
- int & nChangePosInOut,
662
+ int change_pos,
665
663
bilingual_str& error,
666
664
const CCoinControl& coin_control,
667
665
FeeCalculation& fee_calc_out,
668
666
bool sign) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
669
667
{
670
668
AssertLockHeld (wallet.cs_wallet );
671
669
670
+ // out variables, to be packed into returned result structure
671
+ CTransactionRef tx;
672
+ CAmount nFeeRet;
673
+ int nChangePosInOut = change_pos;
674
+
672
675
FastRandomContext rng_fast;
673
676
CMutableTransaction txNew; // The resulting transaction that we make
674
677
@@ -742,12 +745,12 @@ static bool CreateTransactionInternal(
742
745
// provided one
743
746
if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate ) {
744
747
error = strprintf (_ (" Fee rate (%s) is lower than the minimum fee rate setting (%s)" ), coin_control.m_feerate ->ToString (FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate .ToString (FeeEstimateMode::SAT_VB));
745
- return false ;
748
+ return std::nullopt ;
746
749
}
747
750
if (feeCalc.reason == FeeReason::FALLBACK && !wallet.m_allow_fallback_fee ) {
748
751
// eventually allow a fallback fee
749
752
error = _ (" Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee." );
750
- return false ;
753
+ return std::nullopt ;
751
754
}
752
755
753
756
// Calculate the cost of change
@@ -774,7 +777,7 @@ static bool CreateTransactionInternal(
774
777
if (IsDust (txout, wallet.chain ().relayDustFee ()))
775
778
{
776
779
error = _ (" Transaction amount too small" );
777
- return false ;
780
+ return std::nullopt ;
778
781
}
779
782
txNew.vout .push_back (txout);
780
783
}
@@ -791,7 +794,7 @@ static bool CreateTransactionInternal(
791
794
std::optional<SelectionResult> result = SelectCoins (wallet, vAvailableCoins, /* nTargetValue=*/ selection_target, coin_control, coin_selection_params);
792
795
if (!result) {
793
796
error = _ (" Insufficient funds" );
794
- return false ;
797
+ return std::nullopt ;
795
798
}
796
799
TRACE5 (coin_selection, selected_coins, wallet.GetName ().c_str (), GetAlgorithmName (result->m_algo ).c_str (), result->m_target , result->GetWaste (), result->GetSelectedValue ());
797
800
@@ -808,7 +811,7 @@ static bool CreateTransactionInternal(
808
811
else if ((unsigned int )nChangePosInOut > txNew.vout .size ())
809
812
{
810
813
error = _ (" Transaction change output index out of range" );
811
- return false ;
814
+ return std::nullopt ;
812
815
}
813
816
814
817
assert (nChangePosInOut != -1 );
@@ -836,7 +839,7 @@ static bool CreateTransactionInternal(
836
839
int nBytes = tx_sizes.vsize ;
837
840
if (nBytes == -1 ) {
838
841
error = _ (" Missing solving data for estimating transaction size" );
839
- return false ;
842
+ return std::nullopt ;
840
843
}
841
844
nFeeRet = coin_selection_params.m_effective_feerate .GetFee (nBytes);
842
845
@@ -900,7 +903,7 @@ static bool CreateTransactionInternal(
900
903
} else {
901
904
error = _ (" The transaction amount is too small to send after the fee has been deducted" );
902
905
}
903
- return false ;
906
+ return std::nullopt ;
904
907
}
905
908
}
906
909
++i;
@@ -910,12 +913,12 @@ static bool CreateTransactionInternal(
910
913
911
914
// Give up if change keypool ran out and change is required
912
915
if (scriptChange.empty () && nChangePosInOut != -1 ) {
913
- return false ;
916
+ return std::nullopt ;
914
917
}
915
918
916
919
if (sign && !wallet.SignTransaction (txNew)) {
917
920
error = _ (" Signing transaction failed" );
918
- return false ;
921
+ return std::nullopt ;
919
922
}
920
923
921
924
// Return the constructed transaction data.
@@ -926,19 +929,19 @@ static bool CreateTransactionInternal(
926
929
(!sign && tx_sizes.weight > MAX_STANDARD_TX_WEIGHT))
927
930
{
928
931
error = _ (" Transaction too large" );
929
- return false ;
932
+ return std::nullopt ;
930
933
}
931
934
932
935
if (nFeeRet > wallet.m_default_max_tx_fee ) {
933
936
error = TransactionErrorString (TransactionError::MAX_FEE_EXCEEDED);
934
- return false ;
937
+ return std::nullopt ;
935
938
}
936
939
937
940
if (gArgs .GetBoolArg (" -walletrejectlongchains" , DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
938
941
// Lastly, ensure this tx will pass the mempool's chain limits
939
942
if (!wallet.chain ().checkChainLimits (tx)) {
940
943
error = _ (" Transaction has too long of a mempool chain" );
941
- return false ;
944
+ return std::nullopt ;
942
945
}
943
946
}
944
947
@@ -955,9 +958,11 @@ static bool CreateTransactionInternal(
955
958
feeCalc.est .fail .start , feeCalc.est .fail .end ,
956
959
(feeCalc.est .fail .totalConfirmed + feeCalc.est .fail .inMempool + feeCalc.est .fail .leftMempool ) > 0.0 ? 100 * feeCalc.est .fail .withinTarget / (feeCalc.est .fail .totalConfirmed + feeCalc.est .fail .inMempool + feeCalc.est .fail .leftMempool ) : 0.0 ,
957
960
feeCalc.est .fail .withinTarget , feeCalc.est .fail .totalConfirmed , feeCalc.est .fail .inMempool , feeCalc.est .fail .leftMempool );
958
- return true ;
961
+ return CreatedTransactionResult (tx, nFeeRet, nChangePosInOut) ;
959
962
}
960
963
964
+ // TODO: also return std::optional<CreatedTransactionResult> here in order
965
+ // to eliminate the out parameters and to simplify the function
961
966
bool CreateTransaction (
962
967
CWallet& wallet,
963
968
const std::vector<CRecipient>& vecSend,
@@ -983,7 +988,14 @@ bool CreateTransaction(
983
988
984
989
int nChangePosIn = nChangePosInOut;
985
990
Assert (!tx); // tx is an out-param. TODO change the return type from bool to tx (or nullptr)
986
- bool res = CreateTransactionInternal (wallet, vecSend, tx, nFeeRet, nChangePosInOut, error, coin_control, fee_calc_out, sign);
991
+ std::optional<CreatedTransactionResult> txr_ungrouped = CreateTransactionInternal (wallet, vecSend, nChangePosInOut, error, coin_control, fee_calc_out, sign);
992
+ bool res = false ;
993
+ if (txr_ungrouped) {
994
+ tx = txr_ungrouped->tx ;
995
+ nFeeRet = txr_ungrouped->fee ;
996
+ nChangePosInOut = txr_ungrouped->change_pos ;
997
+ res = true ;
998
+ }
987
999
TRACE4 (coin_selection, normal_create_tx_internal, wallet.GetName ().c_str (), res, nFeeRet, nChangePosInOut);
988
1000
// try with avoidpartialspends unless it's enabled already
989
1001
if (res && nFeeRet > 0 /* 0 means non-functional fee rate estimation */ && wallet.m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends ) {
@@ -994,7 +1006,12 @@ bool CreateTransaction(
994
1006
CTransactionRef tx2;
995
1007
int nChangePosInOut2 = nChangePosIn;
996
1008
bilingual_str error2; // fired and forgotten; if an error occurs, we discard the results
997
- if (CreateTransactionInternal (wallet, vecSend, tx2, nFeeRet2, nChangePosInOut2, error2, tmp_cc, fee_calc_out, sign)) {
1009
+ std::optional<CreatedTransactionResult> txr_grouped = CreateTransactionInternal (wallet, vecSend, nChangePosInOut2, error2, tmp_cc, fee_calc_out, sign);
1010
+ if (txr_grouped) {
1011
+ tx2 = txr_grouped->tx ;
1012
+ nFeeRet2 = txr_grouped->fee ;
1013
+ nChangePosInOut2 = txr_grouped->change_pos ;
1014
+
998
1015
// if fee of this alternative one is within the range of the max fee, we use this one
999
1016
const bool use_aps = nFeeRet2 <= nFeeRet + wallet.m_max_aps_fee ;
1000
1017
wallet.WalletLogPrintf (" Fee non-grouped = %lld, grouped = %lld, using %s\n " , nFeeRet, nFeeRet2, use_aps ? " grouped" : " non-grouped" );
0 commit comments