Skip to content

Commit c9fdaa5

Browse files
committed
wallet: CreateTransactionInternal(): return out-params as (optional) struct
1 parent 6b87fa5 commit c9fdaa5

File tree

2 files changed

+46
-19
lines changed

2 files changed

+46
-19
lines changed

src/wallet/spend.cpp

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -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
961966
bool 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");

src/wallet/spend.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAm
8282
std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, const CCoinControl& coin_control,
8383
const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
8484

85+
struct CreatedTransactionResult
86+
{
87+
CTransactionRef tx;
88+
CAmount fee;
89+
int change_pos;
90+
91+
CreatedTransactionResult(CTransactionRef tx, CAmount fee, int change_pos)
92+
: tx(tx), fee(fee), change_pos(change_pos) {}
93+
};
94+
8595
/**
8696
* Create a new transaction paying the recipients with a set of coins
8797
* selected by SelectCoins(); Also create the change output, when needed

0 commit comments

Comments
 (0)