@@ -651,13 +651,12 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng
651651 }
652652}
653653
654- static bool CreateTransactionInternal (
654+ static OperationResult CreateTransactionInternal (
655655 CWallet& wallet,
656656 const std::vector<CRecipient>& vecSend,
657657 CTransactionRef& tx,
658658 CAmount& nFeeRet,
659659 int & nChangePosInOut,
660- bilingual_str& error,
661660 const CCoinControl& coin_control,
662661 FeeCalculation& fee_calc_out,
663662 bool sign) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
@@ -666,6 +665,7 @@ static bool CreateTransactionInternal(
666665
667666 FastRandomContext rng_fast;
668667 CMutableTransaction txNew; // The resulting transaction that we make
668+ bilingual_str error; // possible error str
669669
670670 CoinSelectionParams coin_selection_params{rng_fast}; // Parameters for coin selection, init with dummy
671671 coin_selection_params.m_avoid_partial_spends = coin_control.m_avoid_partial_spends ;
@@ -736,13 +736,11 @@ static bool CreateTransactionInternal(
736736 // Do not, ever, assume that it's fine to change the fee rate if the user has explicitly
737737 // provided one
738738 if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate ) {
739- 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));
740- return false ;
739+ return ErrorOut (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)));
741740 }
742741 if (feeCalc.reason == FeeReason::FALLBACK && !wallet.m_allow_fallback_fee ) {
743742 // eventually allow a fallback fee
744- error = _ (" Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee." );
745- return false ;
743+ return ErrorOut (_ (" Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee." ));
746744 }
747745
748746 // Calculate the cost of change
@@ -766,10 +764,8 @@ static bool CreateTransactionInternal(
766764 coin_selection_params.tx_noinputs_size += ::GetSerializeSize (txout, PROTOCOL_VERSION);
767765 }
768766
769- if (IsDust (txout, wallet.chain ().relayDustFee ()))
770- {
771- error = _ (" Transaction amount too small" );
772- return false ;
767+ if (IsDust (txout, wallet.chain ().relayDustFee ())) {
768+ return ErrorOut (_ (" Transaction amount too small" ));
773769 }
774770 txNew.vout .push_back (txout);
775771 }
@@ -785,8 +781,7 @@ static bool CreateTransactionInternal(
785781 // Choose coins to use
786782 std::optional<SelectionResult> result = SelectCoins (wallet, vAvailableCoins, /* nTargetValue=*/ selection_target, coin_control, coin_selection_params);
787783 if (!result) {
788- error = _ (" Insufficient funds" );
789- return false ;
784+ return ErrorOut (_ (" Insufficient funds" ));
790785 }
791786
792787 // Always make a change output
@@ -799,10 +794,8 @@ static bool CreateTransactionInternal(
799794 // Insert change txn at random position:
800795 nChangePosInOut = rng_fast.randrange (txNew.vout .size () + 1 );
801796 }
802- else if ((unsigned int )nChangePosInOut > txNew.vout .size ())
803- {
804- error = _ (" Transaction change output index out of range" );
805- return false ;
797+ else if ((unsigned int )nChangePosInOut > txNew.vout .size ()) {
798+ return ErrorOut (_ (" Transaction change output index out of range" ));
806799 }
807800
808801 assert (nChangePosInOut != -1 );
@@ -829,8 +822,7 @@ static bool CreateTransactionInternal(
829822 TxSize tx_sizes = CalculateMaximumSignedTxSize (CTransaction (txNew), &wallet, &coin_control);
830823 int nBytes = tx_sizes.vsize ;
831824 if (nBytes == -1 ) {
832- error = _ (" Missing solving data for estimating transaction size" );
833- return false ;
825+ return ErrorOut (_ (" Missing solving data for estimating transaction size" ));
834826 }
835827 nFeeRet = coin_selection_params.m_effective_feerate .GetFee (nBytes);
836828
@@ -894,7 +886,7 @@ static bool CreateTransactionInternal(
894886 } else {
895887 error = _ (" The transaction amount is too small to send after the fee has been deducted" );
896888 }
897- return false ;
889+ return ErrorOut (error) ;
898890 }
899891 }
900892 ++i;
@@ -904,12 +896,11 @@ static bool CreateTransactionInternal(
904896
905897 // Give up if change keypool ran out and change is required
906898 if (scriptChange.empty () && nChangePosInOut != -1 ) {
907- return false ;
899+ return ErrorOut (error) ;
908900 }
909901
910902 if (sign && !wallet.SignTransaction (txNew)) {
911- error = _ (" Signing transaction failed" );
912- return false ;
903+ return ErrorOut (_ (" Signing transaction failed" ));
913904 }
914905
915906 // Return the constructed transaction data.
@@ -919,20 +910,17 @@ static bool CreateTransactionInternal(
919910 if ((sign && GetTransactionWeight (*tx) > MAX_STANDARD_TX_WEIGHT) ||
920911 (!sign && tx_sizes.weight > MAX_STANDARD_TX_WEIGHT))
921912 {
922- error = _ (" Transaction too large" );
923- return false ;
913+ return ErrorOut (_ (" Transaction too large" ));
924914 }
925915
926916 if (nFeeRet > wallet.m_default_max_tx_fee ) {
927- error = TransactionErrorString (TransactionError::MAX_FEE_EXCEEDED);
928- return false ;
917+ return ErrorOut (TransactionErrorString (TransactionError::MAX_FEE_EXCEEDED));
929918 }
930919
931920 if (gArgs .GetBoolArg (" -walletrejectlongchains" , DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
932921 // Lastly, ensure this tx will pass the mempool's chain limits
933922 if (!wallet.chain ().checkChainLimits (tx)) {
934- error = _ (" Transaction has too long of a mempool chain" );
935- return false ;
923+ return ErrorOut (_ (" Transaction has too long of a mempool chain" ));
936924 }
937925 }
938926
@@ -949,44 +937,41 @@ static bool CreateTransactionInternal(
949937 feeCalc.est .fail .start , feeCalc.est .fail .end ,
950938 (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 ,
951939 feeCalc.est .fail .withinTarget , feeCalc.est .fail .totalConfirmed , feeCalc.est .fail .inMempool , feeCalc.est .fail .leftMempool );
952- return true ;
940+ return { true } ;
953941}
954942
955- bool CreateTransaction (
956- CWallet& wallet,
957- const std::vector<CRecipient>& vecSend,
958- CTransactionRef& tx,
959- CAmount& nFeeRet,
960- int & nChangePosInOut,
961- bilingual_str& error,
962- const CCoinControl& coin_control,
963- FeeCalculation& fee_calc_out,
964- bool sign)
943+ OperationResult CreateTransaction (
944+ CWallet& wallet,
945+ const std::vector<CRecipient>& vecSend,
946+ CTransactionRef& tx,
947+ CAmount& nFeeRet,
948+ int & nChangePosInOut,
949+ const CCoinControl& coin_control,
950+ FeeCalculation& fee_calc_out,
951+ bool sign)
965952{
966953 if (vecSend.empty ()) {
967- error = _ (" Transaction must have at least one recipient" );
968- return false ;
954+ return ErrorOut (_ (" Transaction must have at least one recipient" ));
969955 }
970956
971957 if (std::any_of (vecSend.cbegin (), vecSend.cend (), [](const auto & recipient){ return recipient.nAmount < 0 ; })) {
972- error = _ (" Transaction amounts must not be negative" );
973- return false ;
958+ return ErrorOut (_ (" Transaction amounts must not be negative" ));
974959 }
975960
976961 LOCK (wallet.cs_wallet );
977962
978963 int nChangePosIn = nChangePosInOut;
979964 Assert (!tx); // tx is an out-param. TODO change the return type from bool to tx (or nullptr)
980- bool res = CreateTransactionInternal (wallet, vecSend, tx, nFeeRet, nChangePosInOut, error , coin_control, fee_calc_out, sign);
965+ auto res = CreateTransactionInternal (wallet, vecSend, tx, nFeeRet, nChangePosInOut, coin_control, fee_calc_out, sign);
981966 // try with avoidpartialspends unless it's enabled already
982967 if (res && nFeeRet > 0 /* 0 means non-functional fee rate estimation */ && wallet.m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends ) {
983968 CCoinControl tmp_cc = coin_control;
984969 tmp_cc.m_avoid_partial_spends = true ;
985970 CAmount nFeeRet2;
986971 CTransactionRef tx2;
987972 int nChangePosInOut2 = nChangePosIn;
988- bilingual_str error2; // fired and forgotten; if an error occurs, we discard the results
989- if (CreateTransactionInternal (wallet, vecSend, tx2, nFeeRet2, nChangePosInOut2, error2, tmp_cc, fee_calc_out, sign)) {
973+ // if an error occurs, we discard the results
974+ if (CreateTransactionInternal (wallet, vecSend, tx2, nFeeRet2, nChangePosInOut2, tmp_cc, fee_calc_out, sign)) {
990975 // if fee of this alternative one is within the range of the max fee, we use this one
991976 const bool use_aps = nFeeRet2 <= nFeeRet + wallet.m_max_aps_fee ;
992977 wallet.WalletLogPrintf (" Fee non-grouped = %lld, grouped = %lld, using %s\n " , nFeeRet, nFeeRet2, use_aps ? " grouped" : " non-grouped" );
@@ -1023,7 +1008,9 @@ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet,
10231008
10241009 CTransactionRef tx_new;
10251010 FeeCalculation fee_calc_out;
1026- if (!CreateTransaction (wallet, vecSend, tx_new, nFeeRet, nChangePosInOut, error, coinControl, fee_calc_out, false )) {
1011+ auto res = CreateTransaction (wallet, vecSend, tx_new, nFeeRet, nChangePosInOut, coinControl, fee_calc_out, false );
1012+ if (!res) {
1013+ error = res.GetError ();
10271014 return false ;
10281015 }
10291016
0 commit comments