aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/spend.cpp
diff options
context:
space:
mode:
authorRyan Ofsky <ryan@ofsky.org>2022-07-21 08:30:39 -0400
committerRyan Ofsky <ryan@ofsky.org>2022-08-03 07:33:01 -0400
commita23cca56c0a7f4a267915b4beba3af3454c51603 (patch)
tree5d85193889f5a4552a568cfd2b472670c2c6d513 /src/wallet/spend.cpp
parent4a4289e2c98cfbc51b05716f21065838afed80f6 (diff)
downloadbitcoin-a23cca56c0a7f4a267915b4beba3af3454c51603.tar.xz
refactor: Replace BResult with util::Result
Rename `BResult` class to `util::Result` and update the class interface to be more compatible with `std::optional` and with a full-featured result class implemented in https://github.com/bitcoin/bitcoin/pull/25665. Motivation for this change is to update existing `BResult` usages now so they don't have to change later when more features are added in #25665. This change makes the following improvements originally implemented in #25665: - More explicit API. Drops potentially misleading `BResult` constructor that treats any bilingual string argument as an error. Adds `util::Error` constructor so it is never ambiguous when a result is being assigned an error or non-error value. - Better type compatibility. Supports `util::Result<bilingual_str>` return values to hold translated messages which are not errors. - More standard and consistent API. `util::Result` supports most of the same operators and methods as `std::optional`. `BResult` had a less familiar interface with `HasRes`/`GetObj`/`ReleaseObj` methods. The Result/Res/Obj naming was also not internally consistent. - Better code organization. Puts `src/util/` code in the `util::` namespace so naming reflects code organization and it is obvious where the class is coming from. Drops "B" from name because it is undocumented what it stands for (bilingual?) - Has unit tests.
Diffstat (limited to 'src/wallet/spend.cpp')
-rw-r--r--src/wallet/spend.cpp50
1 files changed, 24 insertions, 26 deletions
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index c00a2cd023..5d320feff0 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -758,7 +758,7 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng
}
}
-static BResult<CreatedTransactionResult> CreateTransactionInternal(
+static util::Result<CreatedTransactionResult> CreateTransactionInternal(
CWallet& wallet,
const std::vector<CRecipient>& vecSend,
int change_pos,
@@ -844,11 +844,11 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Do not, ever, assume that it's fine to change the fee rate if the user has explicitly
// provided one
if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate) {
- return 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 util::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))};
}
if (feeCalc.reason == FeeReason::FALLBACK && !wallet.m_allow_fallback_fee) {
// eventually allow a fallback fee
- return _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.");
+ return util::Error{_("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.")};
}
// Calculate the cost of change
@@ -874,7 +874,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
}
if (IsDust(txout, wallet.chain().relayDustFee())) {
- return _("Transaction amount too small");
+ return util::Error{_("Transaction amount too small")};
}
txNew.vout.push_back(txout);
}
@@ -895,7 +895,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Choose coins to use
std::optional<SelectionResult> result = SelectCoins(wallet, available_coins, /*nTargetValue=*/selection_target, coin_control, coin_selection_params);
if (!result) {
- return _("Insufficient funds");
+ return util::Error{_("Insufficient funds")};
}
TRACE5(coin_selection, selected_coins, wallet.GetName().c_str(), GetAlgorithmName(result->m_algo).c_str(), result->m_target, result->GetWaste(), result->GetSelectedValue());
@@ -910,7 +910,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
nChangePosInOut = rng_fast.randrange(txNew.vout.size() + 1);
}
else if ((unsigned int)nChangePosInOut > txNew.vout.size()) {
- return _("Transaction change output index out of range");
+ return util::Error{_("Transaction change output index out of range")};
}
assert(nChangePosInOut != -1);
@@ -937,7 +937,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
TxSize tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), &wallet, &coin_control);
int nBytes = tx_sizes.vsize;
if (nBytes == -1) {
- return _("Missing solving data for estimating transaction size");
+ return util::Error{_("Missing solving data for estimating transaction size")};
}
nFeeRet = coin_selection_params.m_effective_feerate.GetFee(nBytes);
@@ -997,9 +997,9 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Error if this output is reduced to be below dust
if (IsDust(txout, wallet.chain().relayDustFee())) {
if (txout.nValue < 0) {
- return _("The transaction amount is too small to pay the fee");
+ return util::Error{_("The transaction amount is too small to pay the fee")};
} else {
- return _("The transaction amount is too small to send after the fee has been deducted");
+ return util::Error{_("The transaction amount is too small to send after the fee has been deducted")};
}
}
}
@@ -1010,11 +1010,11 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Give up if change keypool ran out and change is required
if (scriptChange.empty() && nChangePosInOut != -1) {
- return error;
+ return util::Error{error};
}
if (sign && !wallet.SignTransaction(txNew)) {
- return _("Signing transaction failed");
+ return util::Error{_("Signing transaction failed")};
}
// Return the constructed transaction data.
@@ -1024,17 +1024,17 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
if ((sign && GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT) ||
(!sign && tx_sizes.weight > MAX_STANDARD_TX_WEIGHT))
{
- return _("Transaction too large");
+ return util::Error{_("Transaction too large")};
}
if (nFeeRet > wallet.m_default_max_tx_fee) {
- return TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
+ return util::Error{TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED)};
}
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)) {
- return _("Transaction has too long of a mempool chain");
+ return util::Error{_("Transaction has too long of a mempool chain")};
}
}
@@ -1053,7 +1053,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
return CreatedTransactionResult(tx, nFeeRet, nChangePosInOut, feeCalc);
}
-BResult<CreatedTransactionResult> CreateTransaction(
+util::Result<CreatedTransactionResult> CreateTransaction(
CWallet& wallet,
const std::vector<CRecipient>& vecSend,
int change_pos,
@@ -1061,28 +1061,26 @@ BResult<CreatedTransactionResult> CreateTransaction(
bool sign)
{
if (vecSend.empty()) {
- return _("Transaction must have at least one recipient");
+ return util::Error{_("Transaction must have at least one recipient")};
}
if (std::any_of(vecSend.cbegin(), vecSend.cend(), [](const auto& recipient){ return recipient.nAmount < 0; })) {
- return _("Transaction amounts must not be negative");
+ return util::Error{_("Transaction amounts must not be negative")};
}
LOCK(wallet.cs_wallet);
auto res = CreateTransactionInternal(wallet, vecSend, change_pos, coin_control, sign);
- TRACE4(coin_selection, normal_create_tx_internal, wallet.GetName().c_str(), res.HasRes(),
- res ? res.GetObj().fee : 0, res ? res.GetObj().change_pos : 0);
+ TRACE4(coin_selection, normal_create_tx_internal, wallet.GetName().c_str(), bool(res),
+ res ? res->fee : 0, res ? res->change_pos : 0);
if (!res) return res;
- const auto& txr_ungrouped = res.GetObj();
+ const auto& txr_ungrouped = *res;
// try with avoidpartialspends unless it's enabled already
if (txr_ungrouped.fee > 0 /* 0 means non-functional fee rate estimation */ && wallet.m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends) {
TRACE1(coin_selection, attempting_aps_create_tx, wallet.GetName().c_str());
CCoinControl tmp_cc = coin_control;
tmp_cc.m_avoid_partial_spends = true;
- auto res_tx_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign);
- // Helper optional class for now
- std::optional<CreatedTransactionResult> txr_grouped{res_tx_grouped.HasRes() ? std::make_optional(res_tx_grouped.GetObj()) : std::nullopt};
+ auto txr_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign);
// if fee of this alternative one is within the range of the max fee, we use this one
const bool use_aps{txr_grouped.has_value() ? (txr_grouped->fee <= txr_ungrouped.fee + wallet.m_max_aps_fee) : false};
TRACE5(coin_selection, aps_create_tx_internal, wallet.GetName().c_str(), use_aps, txr_grouped.has_value(),
@@ -1090,7 +1088,7 @@ BResult<CreatedTransactionResult> CreateTransaction(
if (txr_grouped) {
wallet.WalletLogPrintf("Fee non-grouped = %lld, grouped = %lld, using %s\n",
txr_ungrouped.fee, txr_grouped->fee, use_aps ? "grouped" : "non-grouped");
- if (use_aps) return res_tx_grouped;
+ if (use_aps) return txr_grouped;
}
}
return res;
@@ -1131,10 +1129,10 @@ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet,
auto res = CreateTransaction(wallet, vecSend, nChangePosInOut, coinControl, false);
if (!res) {
- error = res.GetError();
+ error = util::ErrorString(res);
return false;
}
- const auto& txr = res.GetObj();
+ const auto& txr = *res;
CTransactionRef tx_new = txr.tx;
nFeeRet = txr.fee;
nChangePosInOut = txr.change_pos;