Skip to content

Commit 6e4d18f

Browse files
committed
Merge bitcoin/bitcoin#29496: policy: bump TX_MAX_STANDARD_VERSION to 3
30a0113 [doc] update bips.md for 431 (glozow) 9dbe6a0 [test] wallet uses CURRENT_VERSION which is 2 (glozow) 539404f [policy] make v3 transactions standard (glozow) 052ede7 [refactor] use TRUC_VERSION in place of 3 (glozow) Pull request description: Make `nVersion=3` (which is currently nonstandard on mainnet) standard. Note that we will treat these transactions as Topologically Restricted Until Confirmation (TRUC). Spec is in BIP 431 and implementation is in #28948, #29306, and #29873 See #27463 for overall project tracking, and #29319 for information about relevance to cluster mempool. ACKs for top commit: sdaftuar: utACK 30a0113 achow101: ACK 30a0113 instagibbs: utACK 30a0113 murchandamus: ACK 30a0113 ismaelsadeeq: ACK 30a0113 🛰️ Tree-SHA512: 2a4aec0442c860e792a061d83e36483c1f1b426f946efbdf664c8db97a596e498b535707e1d3a900218429486ea69fd4552e3d476526a6883cbd5556c6534b48
2 parents feab351 + 30a0113 commit 6e4d18f

File tree

12 files changed

+58
-35
lines changed

12 files changed

+58
-35
lines changed

doc/bips.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,4 @@ BIPs that are implemented by Bitcoin Core:
6969
[`385`](https://github.com/bitcoin/bips/blob/master/bip-0385.mediawiki):
7070
Output Script Descriptors, and most of Script Expressions are implemented as of **v0.17.0** ([PR 13697](https://github.com/bitcoin/bitcoin/pull/13697)).
7171
* [`BIP 386`](https://github.com/bitcoin/bips/blob/master/bip-0386.mediawiki): tr() Output Script Descriptors are implemented as of **v22.0** ([PR 22051](https://github.com/bitcoin/bitcoin/pull/22051)).
72+
* [`BIP 431`](https://github.com/bitcoin/bips/blob/master/bip-0431.mediawiki): transactions with nVersion=3 are standard and treated as Topologically Restricted Until Confirmation as of **v28.0** ([PR 29496](https://github.com/bitcoin/bitcoin/pull/29496)).

src/policy/policy.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_
131131
// Changing the default transaction version requires a two step process: first
132132
// adapting relay policy by bumping TX_MAX_STANDARD_VERSION, and then later
133133
// allowing the new transaction version in the wallet/RPC.
134-
static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{2};
134+
static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{3};
135135

136136
/**
137137
* Check for standard transaction types

src/policy/v3_policy.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v
6666
const auto in_package_parents{FindInPackageParents(package, ptx)};
6767

6868
// Now we have all ancestors, so we can start checking v3 rules.
69-
if (ptx->nVersion == 3) {
69+
if (ptx->nVersion == TRUC_VERSION) {
7070
// SingleV3Checks should have checked this already.
7171
if (!Assume(vsize <= V3_MAX_VSIZE)) {
7272
return strprintf("v3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
@@ -107,7 +107,7 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v
107107
}();
108108

109109
// If there is a parent, it must have the right version.
110-
if (parent_info.m_version != 3) {
110+
if (parent_info.m_version != TRUC_VERSION) {
111111
return strprintf("v3 tx %s (wtxid=%s) cannot spend from non-v3 tx %s (wtxid=%s)",
112112
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
113113
parent_info.m_txid.ToString(), parent_info.m_wtxid.ToString());
@@ -146,14 +146,14 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v
146146
} else {
147147
// Non-v3 transactions cannot have v3 parents.
148148
for (auto it : mempool_ancestors) {
149-
if (it->GetTx().nVersion == 3) {
149+
if (it->GetTx().nVersion == TRUC_VERSION) {
150150
return strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)",
151151
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
152152
it->GetSharedTx()->GetHash().ToString(), it->GetSharedTx()->GetWitnessHash().ToString());
153153
}
154154
}
155155
for (const auto& index: in_package_parents) {
156-
if (package.at(index)->nVersion == 3) {
156+
if (package.at(index)->nVersion == TRUC_VERSION) {
157157
return strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)",
158158
ptx->GetHash().ToString(),
159159
ptx->GetWitnessHash().ToString(),
@@ -172,12 +172,12 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleV3Checks(const CTra
172172
{
173173
// Check v3 and non-v3 inheritance.
174174
for (const auto& entry : mempool_ancestors) {
175-
if (ptx->nVersion != 3 && entry->GetTx().nVersion == 3) {
175+
if (ptx->nVersion != TRUC_VERSION && entry->GetTx().nVersion == TRUC_VERSION) {
176176
return std::make_pair(strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)",
177177
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
178178
entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString()),
179179
nullptr);
180-
} else if (ptx->nVersion == 3 && entry->GetTx().nVersion != 3) {
180+
} else if (ptx->nVersion == TRUC_VERSION && entry->GetTx().nVersion != TRUC_VERSION) {
181181
return std::make_pair(strprintf("v3 tx %s (wtxid=%s) cannot spend from non-v3 tx %s (wtxid=%s)",
182182
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
183183
entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString()),
@@ -190,7 +190,7 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleV3Checks(const CTra
190190
static_assert(V3_DESCENDANT_LIMIT == 2);
191191

192192
// The rest of the rules only apply to transactions with nVersion=3.
193-
if (ptx->nVersion != 3) return std::nullopt;
193+
if (ptx->nVersion != TRUC_VERSION) return std::nullopt;
194194

195195
if (vsize > V3_MAX_VSIZE) {
196196
return std::make_pair(strprintf("v3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes",

src/policy/v3_policy.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
#include <set>
1616
#include <string>
1717

18-
// This module enforces rules for transactions with nVersion=3 ("v3 transactions") which help make
18+
// This module enforces rules for BIP 431 TRUC transactions (with nVersion=3) which help make
1919
// RBF abilities more robust.
20+
static constexpr decltype(CTransaction::nVersion) TRUC_VERSION{3};
2021

2122
// v3 only allows 1 parent and 1 child when unconfirmed.
2223
/** Maximum number of transactions including an unconfirmed tx and its descendants. */

src/test/fuzz/package_eval.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)
173173
// Create transaction to add to the mempool
174174
const CTransactionRef tx = [&] {
175175
CMutableTransaction tx_mut;
176-
tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ? 3 : CTransaction::CURRENT_VERSION;
176+
tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ? TRUC_VERSION : CTransaction::CURRENT_VERSION;
177177
tx_mut.nLockTime = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<uint32_t>();
178178
// Last tx will sweep all outpoints in package
179179
const auto num_in = last_tx ? package_outpoints.size() : fuzzed_data_provider.ConsumeIntegralInRange<int>(1, mempool_outpoints.size());

src/test/fuzz/tx_pool.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
226226
// Create transaction to add to the mempool
227227
const CTransactionRef tx = [&] {
228228
CMutableTransaction tx_mut;
229-
tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ? 3 : CTransaction::CURRENT_VERSION;
229+
tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ? TRUC_VERSION : CTransaction::CURRENT_VERSION;
230230
tx_mut.nLockTime = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<uint32_t>();
231231
const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size());
232232
const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size() * 2);

src/test/txvalidation_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
286286
script_multisig << OP_2 << OP_CHECKMULTISIG;
287287
{
288288
CMutableTransaction mtx_many_sigops = CMutableTransaction{};
289-
mtx_many_sigops.nVersion = 3;
289+
mtx_many_sigops.nVersion = TRUC_VERSION;
290290
for (const auto& outpoint : multisig_outpoints) {
291291
mtx_many_sigops.vin.emplace_back(outpoint);
292292
mtx_many_sigops.vin.back().scriptWitness.stack.emplace_back(script_multisig.begin(), script_multisig.end());

src/test/util/txmempool.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ void CheckMempoolV3Invariants(const CTxMemPool& tx_pool)
118118
LOCK(tx_pool.cs);
119119
for (const auto& tx_info : tx_pool.infoAll()) {
120120
const auto& entry = *Assert(tx_pool.GetEntry(tx_info.tx->GetHash()));
121-
if (tx_info.tx->nVersion == 3) {
121+
if (tx_info.tx->nVersion == TRUC_VERSION) {
122122
// Check that special maximum virtual size is respected
123123
Assert(entry.GetTxSize() <= V3_MAX_VSIZE);
124124

@@ -133,12 +133,12 @@ void CheckMempoolV3Invariants(const CTxMemPool& tx_pool)
133133
Assert(entry.GetTxSize() <= V3_CHILD_MAX_VSIZE);
134134
// All v3 transactions must only have v3 unconfirmed parents.
135135
const auto& parents = entry.GetMemPoolParentsConst();
136-
Assert(parents.begin()->get().GetSharedTx()->nVersion == 3);
136+
Assert(parents.begin()->get().GetSharedTx()->nVersion == TRUC_VERSION);
137137
}
138138
} else if (entry.GetCountWithAncestors() > 1) {
139139
// All non-v3 transactions must only have non-v3 unconfirmed parents.
140140
for (const auto& parent : entry.GetMemPoolParentsConst()) {
141-
Assert(parent.get().GetSharedTx()->nVersion != 3);
141+
Assert(parent.get().GetSharedTx()->nVersion != TRUC_VERSION);
142142
}
143143
}
144144
}

src/validation.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
831831
//
832832
// Replaceability signaling of the original transactions may be
833833
// ignored due to node setting.
834-
const bool allow_rbf{m_pool.m_opts.full_rbf || SignalsOptInRBF(*ptxConflicting) || ptxConflicting->nVersion == 3};
834+
const bool allow_rbf{m_pool.m_opts.full_rbf || SignalsOptInRBF(*ptxConflicting) || ptxConflicting->nVersion == TRUC_VERSION};
835835
if (!allow_rbf) {
836836
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "txn-mempool-conflict");
837837
}
@@ -935,7 +935,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
935935
// method of ensuring the tx remains bumped. For example, the fee-bumping child could disappear
936936
// due to a replacement.
937937
// The only exception is v3 transactions.
938-
if (!bypass_limits && ws.m_ptx->nVersion != 3 && ws.m_modified_fees < m_pool.m_opts.min_relay_feerate.GetFee(ws.m_vsize)) {
938+
if (!bypass_limits && ws.m_ptx->nVersion != TRUC_VERSION && ws.m_modified_fees < m_pool.m_opts.min_relay_feerate.GetFee(ws.m_vsize)) {
939939
// Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not
940940
// TX_RECONSIDERABLE, because it cannot be bypassed using package validation.
941941
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met",
@@ -1017,7 +1017,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
10171017
.descendant_count = maybe_rbf_limits.descendant_count + 1,
10181018
.descendant_size_vbytes = maybe_rbf_limits.descendant_size_vbytes + EXTRA_DESCENDANT_TX_SIZE_LIMIT,
10191019
};
1020-
if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || ws.m_ptx->nVersion == 3) {
1020+
if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || ws.m_ptx->nVersion == TRUC_VERSION) {
10211021
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
10221022
}
10231023
if (auto ancestors_retry{m_pool.CalculateMemPoolAncestors(*entry, cpfp_carve_out_limits)}) {

test/functional/mempool_accept.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ def run_test(self):
287287

288288
self.log.info('Some nonstandard transactions')
289289
tx = tx_from_hex(raw_tx_reference)
290-
tx.nVersion = 3 # A version currently non-standard
290+
tx.nVersion = 4 # A version currently non-standard
291291
self.check_mempool_result(
292292
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'version'}],
293293
rawtxs=[tx.serialize().hex()],

0 commit comments

Comments
 (0)