mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-08 05:39:38 +02:00
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.
This commit is contained in:
@@ -40,6 +40,7 @@ namespace node {
|
|||||||
enum class TransactionError;
|
enum class TransactionError;
|
||||||
} // namespace node
|
} // namespace node
|
||||||
namespace wallet {
|
namespace wallet {
|
||||||
|
struct CreatedTransactionResult;
|
||||||
class CCoinControl;
|
class CCoinControl;
|
||||||
class CWallet;
|
class CWallet;
|
||||||
enum class AddressPurpose;
|
enum class AddressPurpose;
|
||||||
@@ -142,11 +143,10 @@ public:
|
|||||||
virtual void listLockedCoins(std::vector<COutPoint>& outputs) = 0;
|
virtual void listLockedCoins(std::vector<COutPoint>& outputs) = 0;
|
||||||
|
|
||||||
//! Create transaction.
|
//! Create transaction.
|
||||||
virtual util::Result<CTransactionRef> createTransaction(const std::vector<wallet::CRecipient>& recipients,
|
virtual util::Result<wallet::CreatedTransactionResult> createTransaction(const std::vector<wallet::CRecipient>& recipients,
|
||||||
const wallet::CCoinControl& coin_control,
|
const wallet::CCoinControl& coin_control,
|
||||||
bool sign,
|
bool sign,
|
||||||
int& change_pos,
|
std::optional<unsigned int> change_pos) = 0;
|
||||||
CAmount& fee) = 0;
|
|
||||||
|
|
||||||
//! Commit transaction.
|
//! Commit transaction.
|
||||||
virtual void commitTransaction(CTransactionRef tx,
|
virtual void commitTransaction(CTransactionRef tx,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <psbt.h>
|
#include <psbt.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
#include <wallet/coincontrol.h>
|
#include <wallet/coincontrol.h>
|
||||||
|
#include <wallet/types.h>
|
||||||
#include <wallet/wallet.h>
|
#include <wallet/wallet.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -149,6 +150,8 @@ bool WalletModel::validateAddress(const QString& address) const
|
|||||||
|
|
||||||
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
|
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
|
||||||
{
|
{
|
||||||
|
transaction.getWtx() = nullptr; // reset tx output
|
||||||
|
|
||||||
CAmount total = 0;
|
CAmount total = 0;
|
||||||
bool fSubtractFeeFromAmount = false;
|
bool fSubtractFeeFromAmount = false;
|
||||||
QList<SendCoinsRecipient> recipients = transaction.getRecipients();
|
QList<SendCoinsRecipient> recipients = transaction.getRecipients();
|
||||||
@@ -199,22 +202,21 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CAmount nFeeRequired = 0;
|
|
||||||
int nChangePosRet = -1;
|
|
||||||
|
|
||||||
auto& newTx = transaction.getWtx();
|
auto& newTx = transaction.getWtx();
|
||||||
const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), nChangePosRet, nFeeRequired);
|
const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), /*change_pos=*/std::nullopt);
|
||||||
newTx = res ? *res : nullptr;
|
if (!res) {
|
||||||
transaction.setTransactionFee(nFeeRequired);
|
|
||||||
if (fSubtractFeeFromAmount && newTx)
|
|
||||||
transaction.reassignAmounts(nChangePosRet);
|
|
||||||
|
|
||||||
if (!newTx) {
|
|
||||||
Q_EMIT message(tr("Send Coins"), QString::fromStdString(util::ErrorString(res).translated),
|
Q_EMIT message(tr("Send Coins"), QString::fromStdString(util::ErrorString(res).translated),
|
||||||
CClientUIInterface::MSG_ERROR);
|
CClientUIInterface::MSG_ERROR);
|
||||||
return TransactionCreationFailed;
|
return TransactionCreationFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newTx = res->tx;
|
||||||
|
CAmount nFeeRequired = res->fee;
|
||||||
|
transaction.setTransactionFee(nFeeRequired);
|
||||||
|
if (fSubtractFeeFromAmount && newTx) {
|
||||||
|
transaction.reassignAmounts(static_cast<int>(res->change_pos.value_or(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
// Reject absurdly high fee. (This can never happen because the
|
// Reject absurdly high fee. (This can never happen because the
|
||||||
// wallet never creates transactions with fee greater than
|
// wallet never creates transactions with fee greater than
|
||||||
// m_default_max_tx_fee. This merely a belt-and-suspenders check).
|
// m_default_max_tx_fee. This merely a belt-and-suspenders check).
|
||||||
|
|||||||
@@ -257,21 +257,13 @@ public:
|
|||||||
LOCK(m_wallet->cs_wallet);
|
LOCK(m_wallet->cs_wallet);
|
||||||
return m_wallet->ListLockedCoins(outputs);
|
return m_wallet->ListLockedCoins(outputs);
|
||||||
}
|
}
|
||||||
util::Result<CTransactionRef> createTransaction(const std::vector<CRecipient>& recipients,
|
util::Result<wallet::CreatedTransactionResult> createTransaction(const std::vector<CRecipient>& recipients,
|
||||||
const CCoinControl& coin_control,
|
const CCoinControl& coin_control,
|
||||||
bool sign,
|
bool sign,
|
||||||
int& change_pos,
|
std::optional<unsigned int> change_pos) override
|
||||||
CAmount& fee) override
|
|
||||||
{
|
{
|
||||||
LOCK(m_wallet->cs_wallet);
|
LOCK(m_wallet->cs_wallet);
|
||||||
auto res = CreateTransaction(*m_wallet, recipients, change_pos == -1 ? std::nullopt : std::make_optional(change_pos),
|
return CreateTransaction(*m_wallet, recipients, change_pos, coin_control, sign);
|
||||||
coin_control, sign);
|
|
||||||
if (!res) return util::Error{util::ErrorString(res)};
|
|
||||||
const auto& txr = *res;
|
|
||||||
fee = txr.fee;
|
|
||||||
change_pos = txr.change_pos ? int(*txr.change_pos) : -1;
|
|
||||||
|
|
||||||
return txr.tx;
|
|
||||||
}
|
}
|
||||||
void commitTransaction(CTransactionRef tx,
|
void commitTransaction(CTransactionRef tx,
|
||||||
WalletValueMap value_map,
|
WalletValueMap value_map,
|
||||||
|
|||||||
Reference in New Issue
Block a user