@@ -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,58 +958,51 @@ 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
961
- bool CreateTransaction (
964
+ std::optional<CreatedTransactionResult> CreateTransaction (
962
965
CWallet& wallet,
963
966
const std::vector<CRecipient>& vecSend,
964
- CTransactionRef& tx,
965
- CAmount& nFeeRet,
966
- int & nChangePosInOut,
967
+ int change_pos,
967
968
bilingual_str& error,
968
969
const CCoinControl& coin_control,
969
970
FeeCalculation& fee_calc_out,
970
971
bool sign)
971
972
{
972
973
if (vecSend.empty ()) {
973
974
error = _ (" Transaction must have at least one recipient" );
974
- return false ;
975
+ return std::nullopt ;
975
976
}
976
977
977
978
if (std::any_of (vecSend.cbegin (), vecSend.cend (), [](const auto & recipient){ return recipient.nAmount < 0 ; })) {
978
979
error = _ (" Transaction amounts must not be negative" );
979
- return false ;
980
+ return std::nullopt ;
980
981
}
981
982
982
983
LOCK (wallet.cs_wallet );
983
984
984
- int nChangePosIn = nChangePosInOut ;
985
- 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 );
987
- TRACE4 (coin_selection, normal_create_tx_internal, wallet. GetName (). c_str (), res, nFeeRet, nChangePosInOut) ;
985
+ std::optional<CreatedTransactionResult> txr_ungrouped = CreateTransactionInternal (wallet, vecSend, change_pos, error, coin_control, fee_calc_out, sign) ;
986
+ TRACE4 (coin_selection, normal_create_tx_internal, wallet. GetName (). c_str (), txr_ungrouped. has_value (),
987
+ txr_ungrouped. has_value () ? txr_ungrouped-> fee : 0 , txr_ungrouped. has_value () ? txr_ungrouped-> change_pos : 0 );
988
+ if (!txr_ungrouped) return std::nullopt ;
988
989
// try with avoidpartialspends unless it's enabled already
989
- if (res && nFeeRet > 0 /* 0 means non-functional fee rate estimation */ && wallet.m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends ) {
990
+ if (txr_ungrouped-> fee > 0 /* 0 means non-functional fee rate estimation */ && wallet.m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends ) {
990
991
TRACE1 (coin_selection, attempting_aps_create_tx, wallet.GetName ().c_str ());
991
992
CCoinControl tmp_cc = coin_control;
992
993
tmp_cc.m_avoid_partial_spends = true ;
993
- CAmount nFeeRet2;
994
- CTransactionRef tx2;
995
- int nChangePosInOut2 = nChangePosIn;
996
994
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)) {
995
+ std::optional<CreatedTransactionResult> txr_grouped = CreateTransactionInternal (wallet, vecSend, change_pos, error2, tmp_cc, fee_calc_out, sign);
996
+ if (txr_grouped) {
998
997
// if fee of this alternative one is within the range of the max fee, we use this one
999
- const bool use_aps = nFeeRet2 <= nFeeRet + wallet.m_max_aps_fee ;
1000
- wallet.WalletLogPrintf (" Fee non-grouped = %lld, grouped = %lld, using %s\n " , nFeeRet, nFeeRet2, use_aps ? " grouped" : " non-grouped" );
1001
- TRACE5 (coin_selection, aps_create_tx_internal, wallet.GetName ().c_str (), use_aps, res, nFeeRet2, nChangePosInOut2);
1002
- if (use_aps) {
1003
- tx = tx2;
1004
- nFeeRet = nFeeRet2;
1005
- nChangePosInOut = nChangePosInOut2;
1006
- }
998
+ const bool use_aps = txr_grouped->fee <= txr_ungrouped->fee + wallet.m_max_aps_fee ;
999
+ wallet.WalletLogPrintf (" Fee non-grouped = %lld, grouped = %lld, using %s\n " ,
1000
+ txr_ungrouped->fee , txr_grouped->fee , use_aps ? " grouped" : " non-grouped" );
1001
+ TRACE5 (coin_selection, aps_create_tx_internal, wallet.GetName ().c_str (), use_aps, true , txr_grouped->fee , txr_grouped->change_pos );
1002
+ if (use_aps) return txr_grouped;
1007
1003
}
1008
1004
}
1009
- return res ;
1005
+ return txr_ungrouped ;
1010
1006
}
1011
1007
1012
1008
bool FundTransaction (CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet, int & nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int >& setSubtractFeeFromOutputs, CCoinControl coinControl)
@@ -1030,11 +1026,12 @@ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet,
1030
1026
// CreateTransaction call and LockCoin calls (when lockUnspents is true).
1031
1027
LOCK (wallet.cs_wallet );
1032
1028
1033
- CTransactionRef tx_new;
1034
1029
FeeCalculation fee_calc_out;
1035
- if (!CreateTransaction (wallet, vecSend, tx_new, nFeeRet, nChangePosInOut, error, coinControl, fee_calc_out, false )) {
1036
- return false ;
1037
- }
1030
+ std::optional<CreatedTransactionResult> txr = CreateTransaction (wallet, vecSend, nChangePosInOut, error, coinControl, fee_calc_out, false );
1031
+ if (!txr) return false ;
1032
+ CTransactionRef tx_new = txr->tx ;
1033
+ nFeeRet = txr->fee ;
1034
+ nChangePosInOut = txr->change_pos ;
1038
1035
1039
1036
if (nChangePosInOut != -1 ) {
1040
1037
tx.vout .insert (tx.vout .begin () + nChangePosInOut, tx_new->vout [nChangePosInOut]);
0 commit comments