Skip to content

Commit 91a8e9b

Browse files
committed
Merge bitcoin-core/gui#807: refactor: interfaces, make 'createTransaction' less error-prone
4c0d4f6 refactor: interfaces, make 'createTransaction' less error-prone (furszy) e2c3ec9 refactor: move CreatedTransactionResult to types.h (furszy) 4537217 gui: remove AmountWithFeeExceedsBalance error special case (furszy) Pull request description: Bundle all function's outputs inside the `util::Result` returned object. Removals: - The input-output 'change_pos' ref arg from `createTransaction`, which has been a source of bugs in the past. - The 'fee' ref arg from `createTransaction`, which is currently only set when the transaction creation process succeeds. - The no longer needed `AmountWithFeeExceedsBalance` error (more info about its re-introduction at [bitcoin#25269](bitcoin#25269) and [bitcoin#34299](bitcoin#34299). Additionally, this PR moves the `CreatedTransactionResult` struct into its own file. This change is made to avoid further expanding the GUI dependencies on `wallet.h`. Structurally, the GUI should only access the model/interfaces and never the wallet directly. ACKs for top commit: stratospher: ACK 4c0d4f6. hebasto: ACK 4c0d4f6. Tree-SHA512: 4fc61f08ca2e66e46001defb3a2e852265713e75006c98f0c465bd48afe42e7b0d626d28d578741906fdd26e907d6919f06dc640c55c44efc3dfa766fdbf38a4
2 parents 64294c8 + 4c0d4f6 commit 91a8e9b

7 files changed

Lines changed: 33 additions & 46 deletions

File tree

src/interfaces/wallet.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ namespace node {
4040
enum class TransactionError;
4141
} // namespace node
4242
namespace wallet {
43+
struct CreatedTransactionResult;
4344
class CCoinControl;
4445
class CWallet;
4546
enum class AddressPurpose;
@@ -142,11 +143,10 @@ class Wallet
142143
virtual void listLockedCoins(std::vector<COutPoint>& outputs) = 0;
143144

144145
//! Create transaction.
145-
virtual util::Result<CTransactionRef> createTransaction(const std::vector<wallet::CRecipient>& recipients,
146+
virtual util::Result<wallet::CreatedTransactionResult> createTransaction(const std::vector<wallet::CRecipient>& recipients,
146147
const wallet::CCoinControl& coin_control,
147148
bool sign,
148-
int& change_pos,
149-
CAmount& fee) = 0;
149+
std::optional<unsigned int> change_pos) = 0;
150150

151151
//! Commit transaction.
152152
virtual void commitTransaction(CTransactionRef tx,

src/qt/sendcoinsdialog.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -742,9 +742,6 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
742742
case WalletModel::AmountExceedsBalance:
743743
msgParams.first = tr("The amount exceeds your balance.");
744744
break;
745-
case WalletModel::AmountWithFeeExceedsBalance:
746-
msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);
747-
break;
748745
case WalletModel::DuplicateAddress:
749746
msgParams.first = tr("Duplicate address found: addresses should only be used once each.");
750747
break;

src/qt/walletmodel.cpp

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <psbt.h>
2424
#include <util/translation.h>
2525
#include <wallet/coincontrol.h>
26+
#include <wallet/types.h>
2627
#include <wallet/wallet.h>
2728

2829
#include <cstdint>
@@ -149,6 +150,8 @@ bool WalletModel::validateAddress(const QString& address) const
149150

150151
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
151152
{
153+
transaction.getWtx() = nullptr; // reset tx output
154+
152155
CAmount total = 0;
153156
bool fSubtractFeeFromAmount = false;
154157
QList<SendCoinsRecipient> recipients = transaction.getRecipients();
@@ -199,27 +202,21 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
199202
}
200203

201204
try {
202-
CAmount nFeeRequired = 0;
203-
int nChangePosRet = -1;
204-
205205
auto& newTx = transaction.getWtx();
206-
const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), nChangePosRet, nFeeRequired);
207-
newTx = res ? *res : nullptr;
208-
transaction.setTransactionFee(nFeeRequired);
209-
if (fSubtractFeeFromAmount && newTx)
210-
transaction.reassignAmounts(nChangePosRet);
211-
212-
if(!newTx)
213-
{
214-
if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance)
215-
{
216-
return SendCoinsReturn(AmountWithFeeExceedsBalance);
217-
}
206+
const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), /*change_pos=*/std::nullopt);
207+
if (!res) {
218208
Q_EMIT message(tr("Send Coins"), QString::fromStdString(util::ErrorString(res).translated),
219-
CClientUIInterface::MSG_ERROR);
209+
CClientUIInterface::MSG_ERROR);
220210
return TransactionCreationFailed;
221211
}
222212

213+
newTx = res->tx;
214+
CAmount nFeeRequired = res->fee;
215+
transaction.setTransactionFee(nFeeRequired);
216+
if (fSubtractFeeFromAmount && newTx) {
217+
transaction.reassignAmounts(static_cast<int>(res->change_pos.value_or(-1)));
218+
}
219+
223220
// Reject absurdly high fee. (This can never happen because the
224221
// wallet never creates transactions with fee greater than
225222
// m_default_max_tx_fee. This merely a belt-and-suspenders check).

src/qt/walletmodel.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ class WalletModel : public QObject
5959
InvalidAmount,
6060
InvalidAddress,
6161
AmountExceedsBalance,
62-
AmountWithFeeExceedsBalance,
6362
DuplicateAddress,
6463
TransactionCreationFailed, // Error returned when wallet is still locked
6564
AbsurdFee

src/wallet/interfaces.cpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -257,21 +257,13 @@ class WalletImpl : public Wallet
257257
LOCK(m_wallet->cs_wallet);
258258
return m_wallet->ListLockedCoins(outputs);
259259
}
260-
util::Result<CTransactionRef> createTransaction(const std::vector<CRecipient>& recipients,
260+
util::Result<wallet::CreatedTransactionResult> createTransaction(const std::vector<CRecipient>& recipients,
261261
const CCoinControl& coin_control,
262262
bool sign,
263-
int& change_pos,
264-
CAmount& fee) override
263+
std::optional<unsigned int> change_pos) override
265264
{
266265
LOCK(m_wallet->cs_wallet);
267-
auto res = CreateTransaction(*m_wallet, recipients, change_pos == -1 ? std::nullopt : std::make_optional(change_pos),
268-
coin_control, sign);
269-
if (!res) return util::Error{util::ErrorString(res)};
270-
const auto& txr = *res;
271-
fee = txr.fee;
272-
change_pos = txr.change_pos ? int(*txr.change_pos) : -1;
273-
274-
return txr.tx;
266+
return CreateTransaction(*m_wallet, recipients, change_pos, coin_control, sign);
275267
}
276268
void commitTransaction(CTransactionRef tx,
277269
WalletValueMap value_map,

src/wallet/spend.h

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <util/result.h>
1111
#include <wallet/coinselection.h>
1212
#include <wallet/transaction.h>
13+
#include <wallet/types.h>
1314
#include <wallet/wallet.h>
1415

1516
#include <map>
@@ -186,17 +187,6 @@ util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& av
186187
const CAmount& nTargetValue, const CCoinControl& coin_control,
187188
const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
188189

189-
struct CreatedTransactionResult
190-
{
191-
CTransactionRef tx;
192-
CAmount fee;
193-
FeeCalculation fee_calc;
194-
std::optional<unsigned int> change_pos;
195-
196-
CreatedTransactionResult(CTransactionRef _tx, CAmount _fee, std::optional<unsigned int> _change_pos, const FeeCalculation& _fee_calc)
197-
: tx(_tx), fee(_fee), fee_calc(_fee_calc), change_pos(_change_pos) {}
198-
};
199-
200190
/**
201191
* Set a height-based locktime for new transactions (uses the height of the
202192
* current chain tip unless we are not synced with the current chain

src/wallet/types.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#ifndef BITCOIN_WALLET_TYPES_H
1515
#define BITCOIN_WALLET_TYPES_H
1616

17-
#include <type_traits>
17+
#include <policy/fees/block_policy_estimator.h>
1818

1919
namespace wallet {
2020
/**
@@ -30,6 +30,18 @@ enum class AddressPurpose {
3030
SEND,
3131
REFUND, //!< Never set in current code may be present in older wallet databases
3232
};
33+
34+
struct CreatedTransactionResult
35+
{
36+
CTransactionRef tx;
37+
CAmount fee;
38+
FeeCalculation fee_calc;
39+
std::optional<unsigned int> change_pos;
40+
41+
CreatedTransactionResult(CTransactionRef _tx, CAmount _fee, std::optional<unsigned int> _change_pos, const FeeCalculation& _fee_calc)
42+
: tx(_tx), fee(_fee), fee_calc(_fee_calc), change_pos(_change_pos) {}
43+
};
44+
3345
} // namespace wallet
3446

3547
#endif // BITCOIN_WALLET_TYPES_H

0 commit comments

Comments
 (0)