@@ -656,19 +656,22 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng
656656 }
657657}
658658
659- static bool CreateTransactionInternal (
659+ static std::optional<CreatedTransactionResult> CreateTransactionInternal (
660660 CWallet& wallet,
661661 const std::vector<CRecipient>& vecSend,
662- CTransactionRef& tx,
663- CAmount& nFeeRet,
664- int & nChangePosInOut,
662+ int change_pos,
665663 bilingual_str& error,
666664 const CCoinControl& coin_control,
667665 FeeCalculation& fee_calc_out,
668666 bool sign) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
669667{
670668 AssertLockHeld (wallet.cs_wallet );
671669
670+ // out variables, to be packed into returned result structure
671+ CTransactionRef tx;
672+ CAmount nFeeRet;
673+ int nChangePosInOut = change_pos;
674+
672675 FastRandomContext rng_fast;
673676 CMutableTransaction txNew; // The resulting transaction that we make
674677
@@ -742,12 +745,12 @@ static bool CreateTransactionInternal(
742745 // provided one
743746 if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate ) {
744747 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 ;
746749 }
747750 if (feeCalc.reason == FeeReason::FALLBACK && !wallet.m_allow_fallback_fee ) {
748751 // eventually allow a fallback fee
749752 error = _ (" Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee." );
750- return false ;
753+ return std:: nullopt ;
751754 }
752755
753756 // Calculate the cost of change
@@ -774,7 +777,7 @@ static bool CreateTransactionInternal(
774777 if (IsDust (txout, wallet.chain ().relayDustFee ()))
775778 {
776779 error = _ (" Transaction amount too small" );
777- return false ;
780+ return std:: nullopt ;
778781 }
779782 txNew.vout .push_back (txout);
780783 }
@@ -791,7 +794,7 @@ static bool CreateTransactionInternal(
791794 std::optional<SelectionResult> result = SelectCoins (wallet, vAvailableCoins, /* nTargetValue=*/ selection_target, coin_control, coin_selection_params);
792795 if (!result) {
793796 error = _ (" Insufficient funds" );
794- return false ;
797+ return std:: nullopt ;
795798 }
796799 TRACE5 (coin_selection, selected_coins, wallet.GetName ().c_str (), GetAlgorithmName (result->m_algo ).c_str (), result->m_target , result->GetWaste (), result->GetSelectedValue ());
797800
@@ -808,7 +811,7 @@ static bool CreateTransactionInternal(
808811 else if ((unsigned int )nChangePosInOut > txNew.vout .size ())
809812 {
810813 error = _ (" Transaction change output index out of range" );
811- return false ;
814+ return std:: nullopt ;
812815 }
813816
814817 assert (nChangePosInOut != -1 );
@@ -836,7 +839,7 @@ static bool CreateTransactionInternal(
836839 int nBytes = tx_sizes.vsize ;
837840 if (nBytes == -1 ) {
838841 error = _ (" Missing solving data for estimating transaction size" );
839- return false ;
842+ return std:: nullopt ;
840843 }
841844 nFeeRet = coin_selection_params.m_effective_feerate .GetFee (nBytes);
842845
@@ -900,7 +903,7 @@ static bool CreateTransactionInternal(
900903 } else {
901904 error = _ (" The transaction amount is too small to send after the fee has been deducted" );
902905 }
903- return false ;
906+ return std:: nullopt ;
904907 }
905908 }
906909 ++i;
@@ -910,12 +913,12 @@ static bool CreateTransactionInternal(
910913
911914 // Give up if change keypool ran out and change is required
912915 if (scriptChange.empty () && nChangePosInOut != -1 ) {
913- return false ;
916+ return std:: nullopt ;
914917 }
915918
916919 if (sign && !wallet.SignTransaction (txNew)) {
917920 error = _ (" Signing transaction failed" );
918- return false ;
921+ return std:: nullopt ;
919922 }
920923
921924 // Return the constructed transaction data.
@@ -926,19 +929,19 @@ static bool CreateTransactionInternal(
926929 (!sign && tx_sizes.weight > MAX_STANDARD_TX_WEIGHT))
927930 {
928931 error = _ (" Transaction too large" );
929- return false ;
932+ return std:: nullopt ;
930933 }
931934
932935 if (nFeeRet > wallet.m_default_max_tx_fee ) {
933936 error = TransactionErrorString (TransactionError::MAX_FEE_EXCEEDED);
934- return false ;
937+ return std:: nullopt ;
935938 }
936939
937940 if (gArgs .GetBoolArg (" -walletrejectlongchains" , DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
938941 // Lastly, ensure this tx will pass the mempool's chain limits
939942 if (!wallet.chain ().checkChainLimits (tx)) {
940943 error = _ (" Transaction has too long of a mempool chain" );
941- return false ;
944+ return std:: nullopt ;
942945 }
943946 }
944947
@@ -955,9 +958,11 @@ static bool CreateTransactionInternal(
955958 feeCalc.est .fail .start , feeCalc.est .fail .end ,
956959 (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 ,
957960 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) ;
959962}
960963
964+ // TODO: also return std::optional<CreatedTransactionResult> here in order
965+ // to eliminate the out parameters and to simplify the function
961966bool CreateTransaction (
962967 CWallet& wallet,
963968 const std::vector<CRecipient>& vecSend,
@@ -983,7 +988,14 @@ bool CreateTransaction(
983988
984989 int nChangePosIn = nChangePosInOut;
985990 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+ }
987999 TRACE4 (coin_selection, normal_create_tx_internal, wallet.GetName ().c_str (), res, nFeeRet, nChangePosInOut);
9881000 // try with avoidpartialspends unless it's enabled already
9891001 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(
9941006 CTransactionRef tx2;
9951007 int nChangePosInOut2 = nChangePosIn;
9961008 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+
9981015 // if fee of this alternative one is within the range of the max fee, we use this one
9991016 const bool use_aps = nFeeRet2 <= nFeeRet + wallet.m_max_aps_fee ;
10001017 wallet.WalletLogPrintf (" Fee non-grouped = %lld, grouped = %lld, using %s\n " , nFeeRet, nFeeRet2, use_aps ? " grouped" : " non-grouped" );
0 commit comments