Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
txvalidation_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2017-2021 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
6#include <key_io.h>
7#include <policy/packages.h>
8#include <policy/policy.h>
11#include <random.h>
12#include <script/script.h>
14#include <test/util/txmempool.h>
15#include <validation.h>
16
17#include <boost/test/unit_test.hpp>
18
19
20BOOST_AUTO_TEST_SUITE(txvalidation_tests)
21
22
25BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
26{
27 CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
28 CMutableTransaction coinbaseTx;
29
30 coinbaseTx.version = 1;
31 coinbaseTx.vin.resize(1);
32 coinbaseTx.vout.resize(1);
33 coinbaseTx.vin[0].scriptSig = CScript() << OP_11 << OP_EQUAL;
34 coinbaseTx.vout[0].nValue = 1 * CENT;
35 coinbaseTx.vout[0].scriptPubKey = scriptPubKey;
36
37 BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase());
38
40
41 unsigned int initialPoolSize = m_node.mempool->size();
42 const MempoolAcceptResult result = m_node.chainman->ProcessTransaction(MakeTransactionRef(coinbaseTx));
43
45
46 // Check that the transaction hasn't been added to mempool.
47 BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);
48
49 // Check that the validation state reflects the unsuccessful attempt.
51 BOOST_CHECK_EQUAL(result.m_state.GetRejectReason(), "coinbase");
53}
54
55// Generate a number of random, nonexistent outpoints.
56static inline std::vector<COutPoint> random_outpoints(size_t num_outpoints) {
57 std::vector<COutPoint> outpoints;
58 for (size_t i{0}; i < num_outpoints; ++i) {
59 outpoints.emplace_back(Txid::FromUint256(GetRandHash()), 0);
60 }
61 return outpoints;
62}
63
64static inline std::vector<CPubKey> random_keys(size_t num_keys) {
65 std::vector<CPubKey> keys;
66 keys.reserve(num_keys);
67 for (size_t i{0}; i < num_keys; ++i) {
68 CKey key;
69 key.MakeNewKey(true);
70 keys.emplace_back(key.GetPubKey());
71 }
72 return keys;
73}
74
75// Creates a placeholder tx (not valid) with 25 outputs. Specify the version and the inputs.
76static inline CTransactionRef make_tx(const std::vector<COutPoint>& inputs, int32_t version)
77{
79 mtx.version = version;
80 mtx.vin.resize(inputs.size());
81 mtx.vout.resize(25);
82 for (size_t i{0}; i < inputs.size(); ++i) {
83 mtx.vin[i].prevout = inputs[i];
84 }
85 for (auto i{0}; i < 25; ++i) {
86 mtx.vout[i].scriptPubKey = CScript() << OP_TRUE;
87 mtx.vout[i].nValue = 10000;
88 }
89 return MakeTransactionRef(mtx);
90}
91
93{
94 // Test TRUC policy helper functions
96 LOCK2(cs_main, pool.cs);
98 std::set<Txid> empty_conflicts_set;
99 CTxMemPool::setEntries empty_ancestors;
100
101 auto mempool_tx_v3 = make_tx(random_outpoints(1), /*version=*/3);
102 pool.addUnchecked(entry.FromTx(mempool_tx_v3));
103 auto mempool_tx_v2 = make_tx(random_outpoints(1), /*version=*/2);
104 pool.addUnchecked(entry.FromTx(mempool_tx_v2));
105 // Default values.
106 CTxMemPool::Limits m_limits{};
107
108 // Cannot spend from an unconfirmed TRUC transaction unless this tx is also TRUC.
109 {
110 // mempool_tx_v3
111 // ^
112 // tx_v2_from_v3
113 auto tx_v2_from_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/2);
114 auto ancestors_v2_from_v3{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v3), m_limits)};
115 const auto expected_error_str{strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
116 tx_v2_from_v3->GetHash().ToString(), tx_v2_from_v3->GetWitnessHash().ToString(),
117 mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
118 auto result_v2_from_v3{SingleTRUCChecks(tx_v2_from_v3, *ancestors_v2_from_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v3))};
119 BOOST_CHECK_EQUAL(result_v2_from_v3->first, expected_error_str);
120 BOOST_CHECK_EQUAL(result_v2_from_v3->second, nullptr);
121
122 Package package_v3_v2{mempool_tx_v3, tx_v2_from_v3};
123 BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), package_v3_v2, empty_ancestors), expected_error_str);
124 CTxMemPool::setEntries entries_mempool_v3{pool.GetIter(mempool_tx_v3->GetHash().ToUint256()).value()};
125 BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), {tx_v2_from_v3}, entries_mempool_v3), expected_error_str);
126
127 // mempool_tx_v3 mempool_tx_v2
128 // ^ ^
129 // tx_v2_from_v2_and_v3
130 auto tx_v2_from_v2_and_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}, COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/2);
131 auto ancestors_v2_from_both{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v2_and_v3), m_limits)};
132 const auto expected_error_str_2{strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
133 tx_v2_from_v2_and_v3->GetHash().ToString(), tx_v2_from_v2_and_v3->GetWitnessHash().ToString(),
134 mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
135 auto result_v2_from_both{SingleTRUCChecks(tx_v2_from_v2_and_v3, *ancestors_v2_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3))};
136 BOOST_CHECK_EQUAL(result_v2_from_both->first, expected_error_str_2);
137 BOOST_CHECK_EQUAL(result_v2_from_both->second, nullptr);
138
139 Package package_v3_v2_v2{mempool_tx_v3, mempool_tx_v2, tx_v2_from_v2_and_v3};
140 BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v2_and_v3, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3), package_v3_v2_v2, empty_ancestors), expected_error_str_2);
141 }
142
143 // TRUC cannot spend from an unconfirmed non-TRUC transaction.
144 {
145 // mempool_tx_v2
146 // ^
147 // tx_v3_from_v2
148 auto tx_v3_from_v2 = make_tx({COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/3);
149 auto ancestors_v3_from_v2{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v2), m_limits)};
150 const auto expected_error_str{strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
151 tx_v3_from_v2->GetHash().ToString(), tx_v3_from_v2->GetWitnessHash().ToString(),
152 mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
153 auto result_v3_from_v2{SingleTRUCChecks(tx_v3_from_v2, *ancestors_v3_from_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2))};
154 BOOST_CHECK_EQUAL(result_v3_from_v2->first, expected_error_str);
155 BOOST_CHECK_EQUAL(result_v3_from_v2->second, nullptr);
156
157 Package package_v2_v3{mempool_tx_v2, tx_v3_from_v2};
158 BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), package_v2_v3, empty_ancestors), expected_error_str);
159 CTxMemPool::setEntries entries_mempool_v2{pool.GetIter(mempool_tx_v2->GetHash().ToUint256()).value()};
160 BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), {tx_v3_from_v2}, entries_mempool_v2), expected_error_str);
161
162 // mempool_tx_v3 mempool_tx_v2
163 // ^ ^
164 // tx_v3_from_v2_and_v3
165 auto tx_v3_from_v2_and_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}, COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/3);
166 auto ancestors_v3_from_both{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v2_and_v3), m_limits)};
167 const auto expected_error_str_2{strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
168 tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString(),
169 mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
170 auto result_v3_from_both{SingleTRUCChecks(tx_v3_from_v2_and_v3, *ancestors_v3_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3))};
171 BOOST_CHECK_EQUAL(result_v3_from_both->first, expected_error_str_2);
172 BOOST_CHECK_EQUAL(result_v3_from_both->second, nullptr);
173
174 // tx_v3_from_v2_and_v3 also violates TRUC_ANCESTOR_LIMIT.
175 const auto expected_error_str_3{strprintf("tx %s (wtxid=%s) would have too many ancestors",
176 tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString())};
177 Package package_v3_v2_v3{mempool_tx_v3, mempool_tx_v2, tx_v3_from_v2_and_v3};
178 BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2_and_v3, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3), package_v3_v2_v3, empty_ancestors), expected_error_str_3);
179 }
180 // V3 from V3 is ok, and non-V3 from non-V3 is ok.
181 {
182 // mempool_tx_v3
183 // ^
184 // tx_v3_from_v3
185 auto tx_v3_from_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/3);
186 auto ancestors_v3{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v3), m_limits)};
187 BOOST_CHECK(SingleTRUCChecks(tx_v3_from_v3, *ancestors_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v3))
188 == std::nullopt);
189
190 Package package_v3_v3{mempool_tx_v3, tx_v3_from_v3};
191 BOOST_CHECK(PackageTRUCChecks(tx_v3_from_v3, GetVirtualTransactionSize(*tx_v3_from_v3), package_v3_v3, empty_ancestors) == std::nullopt);
192
193 // mempool_tx_v2
194 // ^
195 // tx_v2_from_v2
196 auto tx_v2_from_v2 = make_tx({COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/2);
197 auto ancestors_v2{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v2), m_limits)};
198 BOOST_CHECK(SingleTRUCChecks(tx_v2_from_v2, *ancestors_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2))
199 == std::nullopt);
200
201 Package package_v2_v2{mempool_tx_v2, tx_v2_from_v2};
202 BOOST_CHECK(PackageTRUCChecks(tx_v2_from_v2, GetVirtualTransactionSize(*tx_v2_from_v2), package_v2_v2, empty_ancestors) == std::nullopt);
203 }
204
205 // Tx spending TRUC cannot have too many mempool ancestors
206 // Configuration where the tx has multiple direct parents.
207 {
208 Package package_multi_parents;
209 std::vector<COutPoint> mempool_outpoints;
210 mempool_outpoints.emplace_back(mempool_tx_v3->GetHash(), 0);
211 package_multi_parents.emplace_back(mempool_tx_v3);
212 for (size_t i{0}; i < 2; ++i) {
213 auto mempool_tx = make_tx(random_outpoints(i + 1), /*version=*/3);
214 pool.addUnchecked(entry.FromTx(mempool_tx));
215 mempool_outpoints.emplace_back(mempool_tx->GetHash(), 0);
216 package_multi_parents.emplace_back(mempool_tx);
217 }
218 auto tx_v3_multi_parent = make_tx(mempool_outpoints, /*version=*/3);
219 package_multi_parents.emplace_back(tx_v3_multi_parent);
220 auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_multi_parent), m_limits)};
221 BOOST_CHECK_EQUAL(ancestors->size(), 3);
222 const auto expected_error_str{strprintf("tx %s (wtxid=%s) would have too many ancestors",
223 tx_v3_multi_parent->GetHash().ToString(), tx_v3_multi_parent->GetWitnessHash().ToString())};
224 auto result{SingleTRUCChecks(tx_v3_multi_parent, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_parent))};
225 BOOST_CHECK_EQUAL(result->first, expected_error_str);
226 BOOST_CHECK_EQUAL(result->second, nullptr);
227
228 BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_multi_parent, GetVirtualTransactionSize(*tx_v3_multi_parent), package_multi_parents, empty_ancestors),
229 expected_error_str);
230 }
231
232 // Configuration where the tx is in a multi-generation chain.
233 {
234 Package package_multi_gen;
235 CTransactionRef middle_tx;
236 auto last_outpoint{random_outpoints(1)[0]};
237 for (size_t i{0}; i < 2; ++i) {
238 auto mempool_tx = make_tx({last_outpoint}, /*version=*/3);
239 pool.addUnchecked(entry.FromTx(mempool_tx));
240 last_outpoint = COutPoint{mempool_tx->GetHash(), 0};
241 package_multi_gen.emplace_back(mempool_tx);
242 if (i == 1) middle_tx = mempool_tx;
243 }
244 auto tx_v3_multi_gen = make_tx({last_outpoint}, /*version=*/3);
245 package_multi_gen.emplace_back(tx_v3_multi_gen);
246 auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_multi_gen), m_limits)};
247 const auto expected_error_str{strprintf("tx %s (wtxid=%s) would have too many ancestors",
248 tx_v3_multi_gen->GetHash().ToString(), tx_v3_multi_gen->GetWitnessHash().ToString())};
249 auto result{SingleTRUCChecks(tx_v3_multi_gen, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_gen))};
250 BOOST_CHECK_EQUAL(result->first, expected_error_str);
251 BOOST_CHECK_EQUAL(result->second, nullptr);
252
253 // Middle tx is what triggers a failure for the grandchild:
254 BOOST_CHECK_EQUAL(*PackageTRUCChecks(middle_tx, GetVirtualTransactionSize(*middle_tx), package_multi_gen, empty_ancestors), expected_error_str);
255 BOOST_CHECK(PackageTRUCChecks(tx_v3_multi_gen, GetVirtualTransactionSize(*tx_v3_multi_gen), package_multi_gen, empty_ancestors) == std::nullopt);
256 }
257
258 // Tx spending TRUC cannot be too large in virtual size.
259 auto many_inputs{random_outpoints(100)};
260 many_inputs.emplace_back(mempool_tx_v3->GetHash(), 0);
261 {
262 auto tx_v3_child_big = make_tx(many_inputs, /*version=*/3);
263 const auto vsize{GetVirtualTransactionSize(*tx_v3_child_big)};
264 auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child_big), m_limits)};
265 const auto expected_error_str{strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
266 tx_v3_child_big->GetHash().ToString(), tx_v3_child_big->GetWitnessHash().ToString(), vsize, TRUC_CHILD_MAX_VSIZE)};
267 auto result{SingleTRUCChecks(tx_v3_child_big, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child_big))};
268 BOOST_CHECK_EQUAL(result->first, expected_error_str);
269 BOOST_CHECK_EQUAL(result->second, nullptr);
270
271 Package package_child_big{mempool_tx_v3, tx_v3_child_big};
272 BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_child_big, GetVirtualTransactionSize(*tx_v3_child_big), package_child_big, empty_ancestors),
273 expected_error_str);
274 }
275
276 // Tx spending TRUC cannot have too many sigops.
277 // This child has 10 P2WSH multisig inputs.
278 auto multisig_outpoints{random_outpoints(10)};
279 multisig_outpoints.emplace_back(mempool_tx_v3->GetHash(), 0);
280 auto keys{random_keys(2)};
281 CScript script_multisig;
282 script_multisig << OP_1;
283 for (const auto& key : keys) {
284 script_multisig << ToByteVector(key);
285 }
286 script_multisig << OP_2 << OP_CHECKMULTISIG;
287 {
288 CMutableTransaction mtx_many_sigops = CMutableTransaction{};
289 mtx_many_sigops.version = TRUC_VERSION;
290 for (const auto& outpoint : multisig_outpoints) {
291 mtx_many_sigops.vin.emplace_back(outpoint);
292 mtx_many_sigops.vin.back().scriptWitness.stack.emplace_back(script_multisig.begin(), script_multisig.end());
293 }
294 mtx_many_sigops.vout.resize(1);
295 mtx_many_sigops.vout.back().scriptPubKey = CScript() << OP_TRUE;
296 mtx_many_sigops.vout.back().nValue = 10000;
297 auto tx_many_sigops{MakeTransactionRef(mtx_many_sigops)};
298
299 auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_many_sigops), m_limits)};
300 // legacy uses fAccurate = false, and the maximum number of multisig keys is used
301 const int64_t total_sigops{static_cast<int64_t>(tx_many_sigops->vin.size()) * static_cast<int64_t>(script_multisig.GetSigOpCount(/*fAccurate=*/false))};
302 BOOST_CHECK_EQUAL(total_sigops, tx_many_sigops->vin.size() * MAX_PUBKEYS_PER_MULTISIG);
303 const int64_t bip141_vsize{GetVirtualTransactionSize(*tx_many_sigops)};
304 // Weight limit is not reached...
305 BOOST_CHECK(SingleTRUCChecks(tx_many_sigops, *ancestors, empty_conflicts_set, bip141_vsize) == std::nullopt);
306 // ...but sigop limit is.
307 const auto expected_error_str{strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
308 tx_many_sigops->GetHash().ToString(), tx_many_sigops->GetWitnessHash().ToString(),
310 auto result{SingleTRUCChecks(tx_many_sigops, *ancestors, empty_conflicts_set,
311 GetVirtualTransactionSize(*tx_many_sigops, /*nSigOpCost=*/total_sigops, /*bytes_per_sigop=*/ DEFAULT_BYTES_PER_SIGOP))};
312 BOOST_CHECK_EQUAL(result->first, expected_error_str);
313 BOOST_CHECK_EQUAL(result->second, nullptr);
314
315 Package package_child_sigops{mempool_tx_v3, tx_many_sigops};
316 BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_many_sigops, total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, package_child_sigops, empty_ancestors),
317 expected_error_str);
318 }
319
320 // Parent + child with TRUC in the mempool. Child is allowed as long as it is under TRUC_CHILD_MAX_VSIZE.
321 auto tx_mempool_v3_child = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/3);
322 {
324 auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_mempool_v3_child), m_limits)};
325 BOOST_CHECK(SingleTRUCChecks(tx_mempool_v3_child, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_mempool_v3_child)) == std::nullopt);
326 pool.addUnchecked(entry.FromTx(tx_mempool_v3_child));
327
328 Package package_v3_1p1c{mempool_tx_v3, tx_mempool_v3_child};
329 BOOST_CHECK(PackageTRUCChecks(tx_mempool_v3_child, GetVirtualTransactionSize(*tx_mempool_v3_child), package_v3_1p1c, empty_ancestors) == std::nullopt);
330 }
331
332 // A TRUC transaction cannot have more than 1 descendant. Sibling is returned when exactly 1 exists.
333 {
334 auto tx_v3_child2 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 1}}, /*version=*/3);
335
336 // Configuration where parent already has 1 other child in mempool
337 auto ancestors_1sibling{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child2), m_limits)};
338 const auto expected_error_str{strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
339 mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
340 auto result_with_sibling_eviction{SingleTRUCChecks(tx_v3_child2, *ancestors_1sibling, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child2))};
341 BOOST_CHECK_EQUAL(result_with_sibling_eviction->first, expected_error_str);
342 // The other mempool child is returned to allow for sibling eviction.
343 BOOST_CHECK_EQUAL(result_with_sibling_eviction->second, tx_mempool_v3_child);
344
345 // If directly replacing the child, make sure there is no double-counting.
346 BOOST_CHECK(SingleTRUCChecks(tx_v3_child2, *ancestors_1sibling, {tx_mempool_v3_child->GetHash()}, GetVirtualTransactionSize(*tx_v3_child2))
347 == std::nullopt);
348
349 Package package_v3_1p2c{mempool_tx_v3, tx_mempool_v3_child, tx_v3_child2};
350 BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_child2, GetVirtualTransactionSize(*tx_v3_child2), package_v3_1p2c, empty_ancestors),
351 expected_error_str);
352
353 // Configuration where parent already has 2 other children in mempool (no sibling eviction allowed). This may happen as the result of a reorg.
354 pool.addUnchecked(entry.FromTx(tx_v3_child2));
355 auto tx_v3_child3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 24}}, /*version=*/3);
356 auto entry_mempool_parent = pool.GetIter(mempool_tx_v3->GetHash().ToUint256()).value();
357 BOOST_CHECK_EQUAL(entry_mempool_parent->GetCountWithDescendants(), 3);
358 auto ancestors_2siblings{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child3), m_limits)};
359
360 auto result_2children{SingleTRUCChecks(tx_v3_child3, *ancestors_2siblings, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child3))};
361 BOOST_CHECK_EQUAL(result_2children->first, expected_error_str);
362 // The other mempool child is not returned because sibling eviction is not allowed.
363 BOOST_CHECK_EQUAL(result_2children->second, nullptr);
364 }
365
366 // Sibling eviction: parent already has 1 other child, which also has its own child (no sibling eviction allowed). This may happen as the result of a reorg.
367 {
368 auto tx_mempool_grandparent = make_tx(random_outpoints(1), /*version=*/3);
369 auto tx_mempool_sibling = make_tx({COutPoint{tx_mempool_grandparent->GetHash(), 0}}, /*version=*/3);
370 auto tx_mempool_nibling = make_tx({COutPoint{tx_mempool_sibling->GetHash(), 0}}, /*version=*/3);
371 auto tx_to_submit = make_tx({COutPoint{tx_mempool_grandparent->GetHash(), 1}}, /*version=*/3);
372
373 pool.addUnchecked(entry.FromTx(tx_mempool_grandparent));
374 pool.addUnchecked(entry.FromTx(tx_mempool_sibling));
375 pool.addUnchecked(entry.FromTx(tx_mempool_nibling));
376
377 auto ancestors_3gen{pool.CalculateMemPoolAncestors(entry.FromTx(tx_to_submit), m_limits)};
378 const auto expected_error_str{strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
379 tx_mempool_grandparent->GetHash().ToString(), tx_mempool_grandparent->GetWitnessHash().ToString())};
380 auto result_3gen{SingleTRUCChecks(tx_to_submit, *ancestors_3gen, empty_conflicts_set, GetVirtualTransactionSize(*tx_to_submit))};
381 BOOST_CHECK_EQUAL(result_3gen->first, expected_error_str);
382 // The other mempool child is not returned because sibling eviction is not allowed.
383 BOOST_CHECK_EQUAL(result_3gen->second, nullptr);
384 }
385
386 // Configuration where tx has multiple generations of descendants is not tested because that is
387 // equivalent to the tx with multiple generations of ancestors.
388}
389
node::NodeContext m_node
#define Assert(val)
Identity function.
Definition check.h:77
An encapsulated private key.
Definition key.h:35
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition key.cpp:161
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition key.cpp:182
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition transaction.h:29
Serialized script, used inside transaction inputs and outputs.
Definition script.h:414
unsigned int GetSigOpCount(bool fAccurate) const
Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs as 20 sigops.
Definition script.cpp:159
The basic transaction that is broadcasted on the network and contained in blocks.
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition txmempool.h:304
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition txmempool.h:390
util::Result< setEntries > CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, const Limits &limits, bool fSearchForParents=true) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Try to calculate all in-mempool ancestors of entry.
std::optional< txiter > GetIter(const uint256 &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Returns an iterator to the given hash, if found.
void check(const CCoinsViewCache &active_coins_tip, int64_t spendheight) const EXCLUSIVE_LOCKS_REQUIRED(voi addUnchecked)(const CTxMemPoolEntry &entry) EXCLUSIVE_LOCKS_REQUIRED(cs
If sanity-checking is turned on, check makes sure the pool is consistent (does not contain two transa...
Definition txmempool.h:463
std::set< txiter, CompareIteratorByHash > setEntries
Definition txmempool.h:396
std::string GetRejectReason() const
Definition validation.h:126
Result GetResult() const
Definition validation.h:125
bool IsInvalid() const
Definition validation.h:123
iterator begin()
Definition prevector.h:304
iterator end()
Definition prevector.h:306
static transaction_identifier FromUint256(const uint256 &id)
static int32_t GetTransactionWeight(const CTransaction &tx)
Definition validation.h:149
@ TX_CONSENSUS
invalid by consensus rules
static const int WITNESS_SCALE_FACTOR
Definition consensus.h:21
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition cs_main.cpp:8
BOOST_AUTO_TEST_SUITE(cuckoocache_tests)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
#define BOOST_CHECK_EQUAL(v1, v2)
Definition object.cpp:18
#define BOOST_CHECK(expr)
Definition object.cpp:17
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
Definition packages.h:50
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop)
Compute the virtual transaction size (weight reinterpreted as bytes).
Definition policy.cpp:300
static constexpr unsigned int DEFAULT_BYTES_PER_SIGOP
Default for -bytespersigop.
Definition policy.h:37
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::shared_ptr< const CTransaction > CTransactionRef
uint256 GetRandHash() noexcept
Generate a random uint256.
Definition random.h:454
@ OP_2
Definition script.h:84
@ OP_CHECKMULTISIG
Definition script.h:191
@ OP_CHECKSIG
Definition script.h:189
@ OP_EQUAL
Definition script.h:145
@ OP_1
Definition script.h:82
@ OP_TRUE
Definition script.h:83
@ OP_11
Definition script.h:93
static const int MAX_PUBKEYS_PER_MULTISIG
Definition script.h:33
std::vector< unsigned char > ToByteVector(const T &in)
Definition script.h:66
static constexpr CAmount CENT
A mutable version of CTransaction.
std::vector< CTxOut > vout
std::vector< CTxIn > vin
Validation result for a transaction evaluated by MemPoolAccept (single or package).
Definition validation.h:128
const ResultType m_result_type
Result type.
Definition validation.h:137
const TxValidationState m_state
Contains information about why the transaction failed.
Definition validation.h:140
Identical to TestingSetup, but chain set to regtest.
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
Definition txmempool.h:19
CTxMemPoolEntry FromTx(const CMutableTransaction &tx) const
Definition txmempool.cpp:33
Options struct containing limit options for a CTxMemPool.
std::unique_ptr< CTxMemPool > mempool
Definition context.h:65
std::unique_ptr< ChainstateManager > chainman
Definition context.h:69
#define LOCK2(cs1, cs2)
Definition sync.h:258
#define LOCK(cs)
Definition sync.h:257
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
std::optional< std::string > PackageTRUCChecks(const CTransactionRef &ptx, int64_t vsize, const Package &package, const CTxMemPool::setEntries &mempool_ancestors)
Must be called for every transaction that is submitted within a package, even if not TRUC.
std::optional< std::pair< std::string, CTransactionRef > > SingleTRUCChecks(const CTransactionRef &ptx, const CTxMemPool::setEntries &mempool_ancestors, const std::set< Txid > &direct_conflicts, int64_t vsize)
Must be called for every transaction, even if not TRUC.
static constexpr int64_t TRUC_CHILD_MAX_VSIZE
Maximum sigop-adjusted virtual size of a tx which spends from an unconfirmed TRUC transaction.
Definition truc_policy.h:32
static constexpr decltype(CTransaction::version) TRUC_VERSION
Definition truc_policy.h:20
static CTransactionRef make_tx(const std::vector< COutPoint > &inputs, int32_t version)
static std::vector< COutPoint > random_outpoints(size_t num_outpoints)
BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
Ensure that the mempool won't accept coinbase transactions.
static std::vector< CPubKey > random_keys(size_t num_keys)