mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 23:03:45 +01:00
Merge bitcoin/bitcoin#32896: wallet, rpc: add v3 transaction creation and wallet support
5c8bf7b39edoc: add release notes for version 3 transactions (ishaanam)4ef8065a5etest: add truc wallet tests (ishaanam)5d932e14dbtest: extract `bulk_vout` from `bulk_tx` so it can be used by wallet tests (ishaanam)2cb473d9f2rpc: Support version 3 transaction creation (Bue-von-hon)4c20343b4drpc: Add transaction min standard version parameter (Bue-von-hon)c5a2d08011wallet: don't return utxos from multiple truc txs in AvailableCoins (ishaanam)da8748ad62wallet: limit v3 tx weight in coin selection (ishaanam)85c5410615wallet: mark unconfirmed v3 siblings as mempool conflicts (ishaanam)0804fc3cb1wallet: throw error at conflicting tx versions in pre-selected inputs (ishaanam)cc155226fewallet: set m_version in coin control to default value (ishaanam)2e9617664ewallet: don't include unconfirmed v3 txs with children in available coins (ishaanam)ec2676becdwallet: unconfirmed ancestors and descendants are always truc (ishaanam) Pull request description: This PR Implements the following: - If creating a v3 transaction, `AvailableCoins` doesn't return unconfirmed v2 utxos (and vice versa) - `AvailableCoins` doesn't return an unconfirmed v3 utxo if its transaction already has a child - If a v3 transaction is kicked out of the mempool by a sibling, mark the sibling as a mempool conflict - Throw an error if pre-selected inputs are of the wrong transaction version - Allow setting version to 3 manually in `createrawtransaction` (uses commits from #31936) - Limits a v3 transaction weight in coin selection Closes #31348 To-Do: - [x] Test a v3 sibling conflict kicking out one of our transactions from the mempool - [x] Implement separate size limit for TRUC children - [x] Test that we can't fund a v2 transaction when everything is v3 unconfirmed - [x] Test a v3 sibling conflict being removed from the mempool - [x] Test limiting v3 transaction weight in coin selection - [x] Simplify tests - [x] Add documentation - [x] Test that user-input max weight is not overwritten by truc max weight - [x] Test v3 in RPCs other than `createrawtransaction` ACKs for top commit: glozow: reACK5c8bf7b39eachow101: ACK5c8bf7b39erkrux: ACK5c8bf7b39eTree-SHA512: da8aea51c113e193dd0b442eff765bd6b8dc0e5066272d3e52190a223c903f48788795f32c554f268af0d2607b5b8c3985c648879cb176c65540837c05d0abb5
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include <node/types.h>
|
||||
#include <outputtype.h>
|
||||
#include <policy/feerate.h>
|
||||
#include <policy/truc_policy.h>
|
||||
#include <primitives/block.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <psbt.h>
|
||||
@@ -1213,6 +1214,23 @@ bool CWallet::TransactionCanBeAbandoned(const Txid& hashTx) const
|
||||
return wtx && !wtx->isAbandoned() && GetTxDepthInMainChain(*wtx) == 0 && !wtx->InMempool();
|
||||
}
|
||||
|
||||
void CWallet::UpdateTrucSiblingConflicts(const CWalletTx& parent_wtx, const Txid& child_txid, bool add_conflict) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
|
||||
{
|
||||
// Find all other txs in our wallet that spend utxos from this parent
|
||||
// so that we can mark them as mempool-conflicted by this new tx.
|
||||
for (long unsigned int i = 0; i < parent_wtx.tx->vout.size(); i++) {
|
||||
for (auto range = mapTxSpends.equal_range(COutPoint(parent_wtx.tx->GetHash(), i)); range.first != range.second; range.first++) {
|
||||
const Txid& sibling_txid = range.first->second;
|
||||
// Skip the child_tx itself
|
||||
if (sibling_txid == child_txid) continue;
|
||||
RecursiveUpdateTxState(/*batch=*/nullptr, sibling_txid, [&child_txid, add_conflict](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
|
||||
return add_conflict ? (wtx.mempool_conflicts.insert(child_txid).second ? TxUpdate::CHANGED : TxUpdate::UNCHANGED)
|
||||
: (wtx.mempool_conflicts.erase(child_txid) ? TxUpdate::CHANGED : TxUpdate::UNCHANGED);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::MarkInputsDirty(const CTransactionRef& tx)
|
||||
{
|
||||
for (const CTxIn& txin : tx->vin) {
|
||||
@@ -1368,6 +1386,25 @@ void CWallet::transactionAddedToMempool(const CTransactionRef& tx) {
|
||||
return wtx.mempool_conflicts.insert(txid).second ? TxUpdate::CHANGED : TxUpdate::UNCHANGED;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (tx->version == TRUC_VERSION) {
|
||||
// Unconfirmed TRUC transactions are only allowed a 1-parent-1-child topology.
|
||||
// For any unconfirmed v3 parents (there should be a maximum of 1 except in reorgs),
|
||||
// record this child so the wallet doesn't try to spend any other outputs
|
||||
for (const CTxIn& tx_in : tx->vin) {
|
||||
auto parent_it = mapWallet.find(tx_in.prevout.hash);
|
||||
if (parent_it != mapWallet.end()) {
|
||||
CWalletTx& parent_wtx = parent_it->second;
|
||||
if (parent_wtx.isUnconfirmed()) {
|
||||
parent_wtx.truc_child_in_mempool = tx->GetHash();
|
||||
// Even though these siblings do not spend the same utxos, they can't
|
||||
// be present in the mempool at the same time because of TRUC policy rules
|
||||
UpdateTrucSiblingConflicts(parent_wtx, txid, /*add_conflict=*/true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1421,6 +1458,23 @@ void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRe
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (tx->version == TRUC_VERSION) {
|
||||
// If this tx has a parent, unset its truc_child_in_mempool to make it possible
|
||||
// to spend from the parent again. If this tx was replaced by another
|
||||
// child of the same parent, transactionAddedToMempool
|
||||
// will update truc_child_in_mempool
|
||||
for (const CTxIn& tx_in : tx->vin) {
|
||||
auto parent_it = mapWallet.find(tx_in.prevout.hash);
|
||||
if (parent_it != mapWallet.end()) {
|
||||
CWalletTx& parent_wtx = parent_it->second;
|
||||
if (parent_wtx.truc_child_in_mempool == tx->GetHash()) {
|
||||
parent_wtx.truc_child_in_mempool = std::nullopt;
|
||||
UpdateTrucSiblingConflicts(parent_wtx, txid, /*add_conflict=*/false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::blockConnected(ChainstateRole role, const interfaces::BlockInfo& block)
|
||||
|
||||
Reference in New Issue
Block a user