Skip to content

Commit 4c0d4f6

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 e2c3ec9 commit 4c0d4f6

3 files changed

Lines changed: 19 additions & 25 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/walletmodel.cpp

Lines changed: 13 additions & 11 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,22 +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) {
206+
const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), /*change_pos=*/std::nullopt);
207+
if (!res) {
213208
Q_EMIT message(tr("Send Coins"), QString::fromStdString(util::ErrorString(res).translated),
214-
CClientUIInterface::MSG_ERROR);
209+
CClientUIInterface::MSG_ERROR);
215210
return TransactionCreationFailed;
216211
}
217212

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+
218220
// Reject absurdly high fee. (This can never happen because the
219221
// wallet never creates transactions with fee greater than
220222
// m_default_max_tx_fee. This merely a belt-and-suspenders check).

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,

0 commit comments

Comments
 (0)