wallet: Drop vOrderForm from CommitTransaction
What changed, and why it matters
This is a routine code cleanup in Bitcoin Core's wallet. It changes how optional 'message' fields from payment URIs are passed through the wallet when committing a transaction, replacing a generic 'order form' container with explicit named parameters. There is no security fix or vulnerability here.
No security action required. Treat as normal maintenance/refactoring commit.
Security signals we found
No security-relevant behavioral change
Refactor only: parameter passing changed, data still stored in same vOrderForm format
No bounds-checking, validation, or cryptographic changes
No bug fix or vulnerability remediation evident in diff
Evidence from the diff
The commit refactors CWallet::CommitTransaction and the interfaces that call it. Previously callers passed a WalletOrderForm (vector of key-value pairs) which was stored directly into wtx.vOrderForm. Now callers pass separate std::vector
Changed components
src/wallet/wallet.cppsrc/wallet/wallet.hsrc/interfaces/wallet.hsrc/qt/walletmodel.cppsrc/wallet/feebumper.cppsrc/wallet/interfaces.cppsrc/wallet/rpc/spend.cppsrc/wallet/test/wallet_tests.cppInspect captured patch +35 / −19
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index 20785a81..3c1f70fb 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -149,8 +149,7 @@ public:
std::optional<unsigned int> change_pos) = 0;
//! Commit transaction.
- virtual void commitTransaction(CTransactionRef tx,
- WalletOrderForm order_form) = 0;
+ virtual void commitTransaction(CTransactionRef tx, const std::vector<std::string>& messages) = 0;
//! Return whether transaction can be abandoned.
virtual bool transactionCanBeAbandoned(const Txid& txid) = 0;
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index add876ae..97f2f426 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -238,15 +238,16 @@ void WalletModel::sendCoins(WalletModelTransaction& transaction)
QByteArray transaction_array; /* store serialized transaction */
{
- std::vector<std::pair<std::string, std::string>> vOrderForm;
+ std::vector<std::string> messages;
for (const SendCoinsRecipient &rcp : transaction.getRecipients())
{
- if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
- vOrderForm.emplace_back("Message", rcp.message.toStdString());
+ if (!rcp.message.isEmpty()) { // Message from normal bitcoin:URI (bitcoin:123...?message=example)
+ messages.emplace_back(rcp.message.toStdString());
+ }
}
auto& newTx = transaction.getWtx();
- wallet().commitTransaction(newTx, std::move(vOrderForm));
+ wallet().commitTransaction(newTx, messages);
DataStream ssTx;
ssTx << TX_WITH_WITNESS(*newTx);
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index bdb70742..9fff706b 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -370,7 +370,13 @@ Result CommitTransaction(CWallet& wallet, const Txid& txid, CMutableTransaction&
// commit/broadcast the tx
CTransactionRef tx = MakeTransactionRef(std::move(mtx));
- wallet.CommitTransaction(tx, oldWtx.vOrderForm, oldWtx.GetHash(), oldWtx.m_comment, oldWtx.m_comment_to);
+ std::vector<std::string> messages;
+ std::vector<std::string> payment_requests;
+ for (const auto& [type, data] : oldWtx.vOrderForm) {
+ if (type == "Message") messages.emplace_back(data);
+ else if (type == "PaymentRequest") payment_requests.emplace_back(data);
+ }
+ wallet.CommitTransaction(tx, oldWtx.GetHash(), oldWtx.m_comment, oldWtx.m_comment_to, messages, payment_requests);
// mark the original tx as bumped
bumped_txid = tx->GetHash();
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index dcdd512b..524abac6 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -267,11 +267,10 @@ public:
LOCK(m_wallet->cs_wallet);
return CreateTransaction(*m_wallet, recipients, change_pos, coin_control, sign);
}
- void commitTransaction(CTransactionRef tx,
- WalletOrderForm order_form) override
+ void commitTransaction(CTransactionRef tx, const std::vector<std::string>& messages) override
{
LOCK(m_wallet->cs_wallet);
- m_wallet->CommitTransaction(std::move(tx), std::move(order_form));
+ m_wallet->CommitTransaction(std::move(tx), /*replaces_txid=*/std::nullopt, /*comment=*/std::nullopt, /*comment_to=*/std::nullopt, messages);
}
bool transactionCanBeAbandoned(const Txid& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); }
bool abandonTransaction(const Txid& txid) override
diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
index 42b7eeb3..7de975d3 100644
--- a/src/wallet/rpc/spend.cpp
+++ b/src/wallet/rpc/spend.cpp
@@ -139,7 +139,7 @@ static UniValue FinishTransaction(const std::shared_ptr<CWallet> pwallet, const
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
result.pushKV("txid", tx->GetHash().GetHex());
if (add_to_wallet && !psbt_opt_in) {
- pwallet->CommitTransaction(tx, /*orderForm=*/{});
+ pwallet->CommitTransaction(tx);
} else {
result.pushKV("hex", hex);
}
@@ -191,7 +191,7 @@ UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vecto
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, util::ErrorString(res).original);
}
const CTransactionRef& tx = res->tx;
- wallet.CommitTransaction(tx, /*orderForm=*/{}, /*replaces_txid=*/std::nullopt, comment, comment_to);
+ wallet.CommitTransaction(tx, /*replaces_txid=*/std::nullopt, comment, comment_to);
if (verbose) {
UniValue entry(UniValue::VOBJ);
entry.pushKV("txid", tx->GetHash().GetHex());
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 41fadb8c..49824c80 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -402,7 +402,7 @@ public:
BOOST_CHECK(res);
tx = res->tx;
}
- wallet->CommitTransaction(tx, {});
+ wallet->CommitTransaction(tx);
CMutableTransaction blocktx;
{
LOCK(wallet->cs_wallet);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 86c40de0..ed224a05 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2331,10 +2331,11 @@ OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& chang
void CWallet::CommitTransaction(
CTransactionRef tx,
- std::vector<std::pair<std::string, std::string>> orderForm,
std::optional<Txid> replaces_txid,
std::optional<std::string> comment,
- std::optional<std::string> comment_to
+ std::optional<std::string> comment_to,
+ const std::vector<std::string>& messages,
+ const std::vector<std::string>& payment_requests
)
{
LOCK(cs_wallet);
@@ -2347,7 +2348,16 @@ void CWallet::CommitTransaction(
if (replaces_txid) wtx.m_replaces_txid = replaces_txid;
if (comment) wtx.m_comment = comment;
if (comment_to) wtx.m_comment_to = comment_to;
- wtx.vOrderForm = std::move(orderForm);
+ if (!messages.empty()) {
+ for (const std::string& msg : messages) {
+ wtx.vOrderForm.emplace_back("Message", msg);
+ }
+ }
+ if (!payment_requests.empty()) {
+ for (const std::string& msg : payment_requests) {
+ wtx.vOrderForm.emplace_back("PaymentRequest", msg);
+ }
+ }
return true;
});
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 080046cd..b43805ca 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -690,17 +690,18 @@ public:
* broadcasting the transaction.
*
* @param[in] tx The transaction to be broadcast.
- * @param[in] orderForm BIP 70 / BIP 21 order form details to be set on the transaction.
* @param[in] replaces_txid The txid of the transaction that this transaction replaces
* @param[in] comment The user's comment for this transaction
* @param[in] comment_to The comment for this transaction indicating where coins are sent to
+ * @param[in] messages The BIP 21 URI messages to attach to this transaction
*/
void CommitTransaction(
CTransactionRef tx,
- std::vector<std::pair<std::string, std::string>> orderForm,
std::optional<Txid> replaces_txid = std::nullopt,
std::optional<std::string> comment = std::nullopt,
- std::optional<std::string> comment_to = std::nullopt
+ std::optional<std::string> comment_to = std::nullopt,
+ const std::vector<std::string>& messages = {},
+ const std::vector<std::string>& payment_requests = {}
);
/** Pass this transaction to node for optional mempool insertion and relay to peers. */
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.