Skip to content

Commit 4d941b5

Browse files
committed
refactor: interfaces, make 'createTransaction' less error-prone
Bundle all function's outputs inside the util::Result returned object. Reasons for the refactoring: - The 'change_pos' ref argument has been a source of bugs in the past. - The 'fee' ref argument is currently only set when the transaction creation process succeeds.
1 parent 95aaaa4 commit 4d941b5

File tree

3 files changed

+19
-25
lines changed

3 files changed

+19
-25
lines changed

src/interfaces/wallet.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ enum class TransactionError;
3434
struct PartiallySignedTransaction;
3535
struct bilingual_str;
3636
namespace wallet {
37+
struct CreatedTransactionResult;
3738
class CCoinControl;
3839
class CWallet;
3940
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/walletmodel.cpp

+13-11
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <psbt.h>
2323
#include <util/translation.h>
2424
#include <wallet/coincontrol.h>
25+
#include <wallet/types.h>
2526
#include <wallet/wallet.h> // for CRecipient
2627

2728
#include <stdint.h>
@@ -153,6 +154,8 @@ bool WalletModel::validateAddress(const QString& address) const
153154

154155
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
155156
{
157+
transaction.getWtx() = nullptr; // reset tx output
158+
156159
CAmount total = 0;
157160
bool fSubtractFeeFromAmount = false;
158161
QList<SendCoinsRecipient> recipients = transaction.getRecipients();
@@ -204,22 +207,21 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
204207
}
205208

206209
try {
207-
CAmount nFeeRequired = 0;
208-
int nChangePosRet = -1;
209-
210210
auto& newTx = transaction.getWtx();
211-
const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), nChangePosRet, nFeeRequired);
212-
newTx = res ? *res : nullptr;
213-
transaction.setTransactionFee(nFeeRequired);
214-
if (fSubtractFeeFromAmount && newTx)
215-
transaction.reassignAmounts(nChangePosRet);
216-
217-
if (!newTx) {
211+
const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), /*change_pos=*/std::nullopt);
212+
if (!res) {
218213
Q_EMIT message(tr("Send Coins"), QString::fromStdString(util::ErrorString(res).translated),
219-
CClientUIInterface::MSG_ERROR);
214+
CClientUIInterface::MSG_ERROR);
220215
return TransactionCreationFailed;
221216
}
222217

218+
newTx = res->tx;
219+
CAmount nFeeRequired = res->fee;
220+
transaction.setTransactionFee(nFeeRequired);
221+
if (fSubtractFeeFromAmount && newTx) {
222+
transaction.reassignAmounts(res->change_pos ? int(*res->change_pos) : -1);
223+
}
224+
223225
// Reject absurdly high fee. (This can never happen because the
224226
// wallet never creates transactions with fee greater than
225227
// m_default_max_tx_fee. This merely a belt-and-suspenders check).

src/wallet/interfaces.cpp

+3-11
Original file line numberDiff line numberDiff line change
@@ -274,21 +274,13 @@ class WalletImpl : public Wallet
274274
LOCK(m_wallet->cs_wallet);
275275
return m_wallet->ListLockedCoins(outputs);
276276
}
277-
util::Result<CTransactionRef> createTransaction(const std::vector<CRecipient>& recipients,
277+
util::Result<wallet::CreatedTransactionResult> createTransaction(const std::vector<CRecipient>& recipients,
278278
const CCoinControl& coin_control,
279279
bool sign,
280-
int& change_pos,
281-
CAmount& fee) override
280+
std::optional<unsigned int> change_pos) override
282281
{
283282
LOCK(m_wallet->cs_wallet);
284-
auto res = CreateTransaction(*m_wallet, recipients, change_pos == -1 ? std::nullopt : std::make_optional(change_pos),
285-
coin_control, sign);
286-
if (!res) return util::Error{util::ErrorString(res)};
287-
const auto& txr = *res;
288-
fee = txr.fee;
289-
change_pos = txr.change_pos ? int(*txr.change_pos) : -1;
290-
291-
return txr.tx;
283+
return CreateTransaction(*m_wallet, recipients, change_pos, coin_control, sign);
292284
}
293285
void commitTransaction(CTransactionRef tx,
294286
WalletValueMap value_map,

0 commit comments

Comments
 (0)