diff options
author | Sebastian Falbesoner <sebastian.falbesoner@gmail.com> | 2020-12-13 01:37:40 +0100 |
---|---|---|
committer | Sebastian Falbesoner <sebastian.falbesoner@gmail.com> | 2022-05-16 17:37:10 +0200 |
commit | c9fdaa5e3ae09b45be6a5c2d4ee6b1e8cef9d8a8 (patch) | |
tree | b62e51a4d4f0ce0135c02643948817d7c7dd7846 /src | |
parent | 6b87fa540c407d167535561ac25e3225bf76d6cc (diff) |
wallet: CreateTransactionInternal(): return out-params as (optional) struct
Diffstat (limited to 'src')
-rw-r--r-- | src/wallet/spend.cpp | 55 | ||||
-rw-r--r-- | src/wallet/spend.h | 10 |
2 files changed, 46 insertions, 19 deletions
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 55c0a2cb7f..7bef67d235 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -656,12 +656,10 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng } } -static bool CreateTransactionInternal( +static std::optional<CreatedTransactionResult> CreateTransactionInternal( CWallet& wallet, const std::vector<CRecipient>& vecSend, - CTransactionRef& tx, - CAmount& nFeeRet, - int& nChangePosInOut, + int change_pos, bilingual_str& error, const CCoinControl& coin_control, FeeCalculation& fee_calc_out, @@ -669,6 +667,11 @@ static bool CreateTransactionInternal( { AssertLockHeld(wallet.cs_wallet); + // out variables, to be packed into returned result structure + CTransactionRef tx; + CAmount nFeeRet; + int nChangePosInOut = change_pos; + FastRandomContext rng_fast; CMutableTransaction txNew; // The resulting transaction that we make @@ -742,12 +745,12 @@ static bool CreateTransactionInternal( // provided one if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate) { 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)); - return false; + return std::nullopt; } if (feeCalc.reason == FeeReason::FALLBACK && !wallet.m_allow_fallback_fee) { // eventually allow a fallback fee error = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee."); - return false; + return std::nullopt; } // Calculate the cost of change @@ -774,7 +777,7 @@ static bool CreateTransactionInternal( if (IsDust(txout, wallet.chain().relayDustFee())) { error = _("Transaction amount too small"); - return false; + return std::nullopt; } txNew.vout.push_back(txout); } @@ -791,7 +794,7 @@ static bool CreateTransactionInternal( std::optional<SelectionResult> result = SelectCoins(wallet, vAvailableCoins, /*nTargetValue=*/selection_target, coin_control, coin_selection_params); if (!result) { error = _("Insufficient funds"); - return false; + return std::nullopt; } TRACE5(coin_selection, selected_coins, wallet.GetName().c_str(), GetAlgorithmName(result->m_algo).c_str(), result->m_target, result->GetWaste(), result->GetSelectedValue()); @@ -808,7 +811,7 @@ static bool CreateTransactionInternal( else if ((unsigned int)nChangePosInOut > txNew.vout.size()) { error = _("Transaction change output index out of range"); - return false; + return std::nullopt; } assert(nChangePosInOut != -1); @@ -836,7 +839,7 @@ static bool CreateTransactionInternal( int nBytes = tx_sizes.vsize; if (nBytes == -1) { error = _("Missing solving data for estimating transaction size"); - return false; + return std::nullopt; } nFeeRet = coin_selection_params.m_effective_feerate.GetFee(nBytes); @@ -900,7 +903,7 @@ static bool CreateTransactionInternal( } else { error = _("The transaction amount is too small to send after the fee has been deducted"); } - return false; + return std::nullopt; } } ++i; @@ -910,12 +913,12 @@ static bool CreateTransactionInternal( // Give up if change keypool ran out and change is required if (scriptChange.empty() && nChangePosInOut != -1) { - return false; + return std::nullopt; } if (sign && !wallet.SignTransaction(txNew)) { error = _("Signing transaction failed"); - return false; + return std::nullopt; } // Return the constructed transaction data. @@ -926,19 +929,19 @@ static bool CreateTransactionInternal( (!sign && tx_sizes.weight > MAX_STANDARD_TX_WEIGHT)) { error = _("Transaction too large"); - return false; + return std::nullopt; } if (nFeeRet > wallet.m_default_max_tx_fee) { error = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED); - return false; + return std::nullopt; } if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) { // Lastly, ensure this tx will pass the mempool's chain limits if (!wallet.chain().checkChainLimits(tx)) { error = _("Transaction has too long of a mempool chain"); - return false; + return std::nullopt; } } @@ -955,9 +958,11 @@ static bool CreateTransactionInternal( feeCalc.est.fail.start, feeCalc.est.fail.end, (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, feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool); - return true; + return CreatedTransactionResult(tx, nFeeRet, nChangePosInOut); } +// TODO: also return std::optional<CreatedTransactionResult> here in order +// to eliminate the out parameters and to simplify the function bool CreateTransaction( CWallet& wallet, const std::vector<CRecipient>& vecSend, @@ -983,7 +988,14 @@ bool CreateTransaction( int nChangePosIn = nChangePosInOut; Assert(!tx); // tx is an out-param. TODO change the return type from bool to tx (or nullptr) - bool res = CreateTransactionInternal(wallet, vecSend, tx, nFeeRet, nChangePosInOut, error, coin_control, fee_calc_out, sign); + std::optional<CreatedTransactionResult> txr_ungrouped = CreateTransactionInternal(wallet, vecSend, nChangePosInOut, error, coin_control, fee_calc_out, sign); + bool res = false; + if (txr_ungrouped) { + tx = txr_ungrouped->tx; + nFeeRet = txr_ungrouped->fee; + nChangePosInOut = txr_ungrouped->change_pos; + res = true; + } TRACE4(coin_selection, normal_create_tx_internal, wallet.GetName().c_str(), res, nFeeRet, nChangePosInOut); // try with avoidpartialspends unless it's enabled already 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( CTransactionRef tx2; int nChangePosInOut2 = nChangePosIn; bilingual_str error2; // fired and forgotten; if an error occurs, we discard the results - if (CreateTransactionInternal(wallet, vecSend, tx2, nFeeRet2, nChangePosInOut2, error2, tmp_cc, fee_calc_out, sign)) { + std::optional<CreatedTransactionResult> txr_grouped = CreateTransactionInternal(wallet, vecSend, nChangePosInOut2, error2, tmp_cc, fee_calc_out, sign); + if (txr_grouped) { + tx2 = txr_grouped->tx; + nFeeRet2 = txr_grouped->fee; + nChangePosInOut2 = txr_grouped->change_pos; + // if fee of this alternative one is within the range of the max fee, we use this one const bool use_aps = nFeeRet2 <= nFeeRet + wallet.m_max_aps_fee; wallet.WalletLogPrintf("Fee non-grouped = %lld, grouped = %lld, using %s\n", nFeeRet, nFeeRet2, use_aps ? "grouped" : "non-grouped"); diff --git a/src/wallet/spend.h b/src/wallet/spend.h index e43aac5273..ca5714245e 100644 --- a/src/wallet/spend.h +++ b/src/wallet/spend.h @@ -82,6 +82,16 @@ std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAm std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); +struct CreatedTransactionResult +{ + CTransactionRef tx; + CAmount fee; + int change_pos; + + CreatedTransactionResult(CTransactionRef tx, CAmount fee, int change_pos) + : tx(tx), fee(fee), change_pos(change_pos) {} +}; + /** * Create a new transaction paying the recipients with a set of coins * selected by SelectCoins(); Also create the change output, when needed |