Bitcoin Core 28.99.0
P2P Digital Currency
orphanage_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2022 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
5#include <arith_uint256.h>
7#include <policy/policy.h>
9#include <pubkey.h>
10#include <script/sign.h>
12#include <test/util/random.h>
15#include <txorphanage.h>
16
17#include <array>
18#include <cstdint>
19
20#include <boost/test/unit_test.hpp>
21
23
25{
26public:
27 TxOrphanageTest(FastRandomContext& rng) : m_rng{rng} {}
28
29 inline size_t CountOrphans() const
30 {
31 return m_orphans.size();
32 }
33
35 {
36 std::map<Wtxid, OrphanTx>::iterator it;
37 it = m_orphans.lower_bound(Wtxid::FromUint256(m_rng.rand256()));
38 if (it == m_orphans.end())
39 it = m_orphans.begin();
40 return it->second.tx;
41 }
42
44};
45
47{
48 std::vector<unsigned char> keydata;
49 keydata = rand_ctx.randbytes(32);
50 key.Set(keydata.data(), keydata.data() + keydata.size(), /*fCompressedIn=*/true);
51 assert(key.IsValid());
52}
53
54// Creates a transaction with 2 outputs. Spends all outpoints. If outpoints is empty, spends a random one.
55static CTransactionRef MakeTransactionSpending(const std::vector<COutPoint>& outpoints, FastRandomContext& det_rand)
56{
57 CKey key;
60 // If no outpoints are given, create a random one.
61 if (outpoints.empty()) {
62 tx.vin.emplace_back(Txid::FromUint256(det_rand.rand256()), 0);
63 } else {
64 for (const auto& outpoint : outpoints) {
65 tx.vin.emplace_back(outpoint);
66 }
67 }
68 // Ensure txid != wtxid
69 tx.vin[0].scriptWitness.stack.push_back({1});
70 tx.vout.resize(2);
71 tx.vout[0].nValue = CENT;
72 tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
73 tx.vout[1].nValue = 3 * CENT;
74 tx.vout[1].scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(key.GetPubKey()));
75 return MakeTransactionRef(tx);
76}
77
78// Make another (not necessarily valid) tx with the same txid but different wtxid.
80{
81 CMutableTransaction tx(*ptx);
82 tx.vin[0].scriptWitness.stack.push_back({5});
83 auto mutated_tx = MakeTransactionRef(tx);
84 assert(ptx->GetHash() == mutated_tx->GetHash());
85 return mutated_tx;
86}
87
88static bool EqualTxns(const std::set<CTransactionRef>& set_txns, const std::vector<CTransactionRef>& vec_txns)
89{
90 if (vec_txns.size() != set_txns.size()) return false;
91 for (const auto& tx : vec_txns) {
92 if (!set_txns.contains(tx)) return false;
93 }
94 return true;
95}
96
97BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
98{
99 // This test had non-deterministic coverage due to
100 // randomly selected seeds.
101 // This seed is chosen so that all branches of the function
102 // ecdsa_signature_parse_der_lax are executed during this test.
103 // Specifically branches that run only when an ECDSA
104 // signature's R and S values have leading zeros.
105 m_rng.Reseed(uint256{33});
106
107 TxOrphanageTest orphanage{m_rng};
108 CKey key;
111 BOOST_CHECK(keystore.AddKey(key));
112
113 // Freeze time for length of test
114 auto now{GetTime<std::chrono::seconds>()};
115 SetMockTime(now);
116
117 // 50 orphan transactions:
118 for (int i = 0; i < 50; i++)
119 {
121 tx.vin.resize(1);
122 tx.vin[0].prevout.n = 0;
123 tx.vin[0].prevout.hash = Txid::FromUint256(m_rng.rand256());
124 tx.vin[0].scriptSig << OP_1;
125 tx.vout.resize(1);
126 tx.vout[0].nValue = i*CENT;
127 tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
128
129 orphanage.AddTx(MakeTransactionRef(tx), i);
130 }
131
132 // ... and 50 that depend on other orphans:
133 for (int i = 0; i < 50; i++)
134 {
135 CTransactionRef txPrev = orphanage.RandomOrphan();
136
138 tx.vin.resize(1);
139 tx.vin[0].prevout.n = 0;
140 tx.vin[0].prevout.hash = txPrev->GetHash();
141 tx.vout.resize(1);
142 tx.vout[0].nValue = i*CENT;
143 tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
144 SignatureData empty;
145 BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL, empty));
146
147 orphanage.AddTx(MakeTransactionRef(tx), i);
148 }
149
150 // This really-big orphan should be ignored:
151 for (int i = 0; i < 10; i++)
152 {
153 CTransactionRef txPrev = orphanage.RandomOrphan();
154
156 tx.vout.resize(1);
157 tx.vout[0].nValue = 1*CENT;
158 tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
159 tx.vin.resize(2777);
160 for (unsigned int j = 0; j < tx.vin.size(); j++)
161 {
162 tx.vin[j].prevout.n = j;
163 tx.vin[j].prevout.hash = txPrev->GetHash();
164 }
165 SignatureData empty;
166 BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL, empty));
167 // Reuse same signature for other inputs
168 // (they don't have to be valid for this test)
169 for (unsigned int j = 1; j < tx.vin.size(); j++)
170 tx.vin[j].scriptSig = tx.vin[0].scriptSig;
171
172 BOOST_CHECK(!orphanage.AddTx(MakeTransactionRef(tx), i));
173 }
174
175 size_t expected_num_orphans = orphanage.CountOrphans();
176
177 // Non-existent peer; nothing should be deleted
178 orphanage.EraseForPeer(/*peer=*/-1);
179 BOOST_CHECK_EQUAL(orphanage.CountOrphans(), expected_num_orphans);
180
181 // Each of first three peers stored
182 // two transactions each.
183 for (NodeId i = 0; i < 3; i++)
184 {
185 orphanage.EraseForPeer(i);
186 expected_num_orphans -= 2;
187 BOOST_CHECK(orphanage.CountOrphans() == expected_num_orphans);
188 }
189
190 // Test LimitOrphanTxSize() function, nothing should timeout:
191 FastRandomContext rng{/*fDeterministic=*/true};
192 orphanage.LimitOrphans(/*max_orphans=*/expected_num_orphans, rng);
193 BOOST_CHECK_EQUAL(orphanage.CountOrphans(), expected_num_orphans);
194 expected_num_orphans -= 1;
195 orphanage.LimitOrphans(/*max_orphans=*/expected_num_orphans, rng);
196 BOOST_CHECK_EQUAL(orphanage.CountOrphans(), expected_num_orphans);
197 assert(expected_num_orphans > 40);
198 orphanage.LimitOrphans(40, rng);
199 BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 40);
200 orphanage.LimitOrphans(10, rng);
201 BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 10);
202 orphanage.LimitOrphans(0, rng);
203 BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 0);
204
205 // Add one more orphan, check timeout logic
206 auto timeout_tx = MakeTransactionSpending(/*outpoints=*/{}, rng);
207 orphanage.AddTx(timeout_tx, 0);
208 orphanage.LimitOrphans(1, rng);
209 BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 1);
210
211 // One second shy of expiration
213 orphanage.LimitOrphans(1, rng);
214 BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 1);
215
216 // Jump one more second, orphan should be timed out on limiting
218 BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 1);
219 orphanage.LimitOrphans(1, rng);
220 BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 0);
221}
222
223BOOST_AUTO_TEST_CASE(same_txid_diff_witness)
224{
225 FastRandomContext det_rand{true};
226 TxOrphanage orphanage;
227 NodeId peer{0};
228
229 std::vector<COutPoint> empty_outpoints;
230 auto parent = MakeTransactionSpending(empty_outpoints, det_rand);
231
232 // Create children to go into orphanage.
233 auto child_normal = MakeTransactionSpending({{parent->GetHash(), 0}}, det_rand);
234 auto child_mutated = MakeMutation(child_normal);
235
236 const auto& normal_wtxid = child_normal->GetWitnessHash();
237 const auto& mutated_wtxid = child_mutated->GetWitnessHash();
238 BOOST_CHECK(normal_wtxid != mutated_wtxid);
239
240 BOOST_CHECK(orphanage.AddTx(child_normal, peer));
241 // EraseTx fails as transaction by this wtxid doesn't exist.
242 BOOST_CHECK_EQUAL(orphanage.EraseTx(mutated_wtxid), 0);
243 BOOST_CHECK(orphanage.HaveTx(normal_wtxid));
244 BOOST_CHECK(orphanage.GetTx(normal_wtxid) == child_normal);
245 BOOST_CHECK(!orphanage.HaveTx(mutated_wtxid));
246 BOOST_CHECK(orphanage.GetTx(mutated_wtxid) == nullptr);
247
248 // Must succeed. Both transactions should be present in orphanage.
249 BOOST_CHECK(orphanage.AddTx(child_mutated, peer));
250 BOOST_CHECK(orphanage.HaveTx(normal_wtxid));
251 BOOST_CHECK(orphanage.HaveTx(mutated_wtxid));
252
253 // Outpoints map should track all entries: check that both are returned as children of the parent.
254 std::set<CTransactionRef> expected_children{child_normal, child_mutated};
255 BOOST_CHECK(EqualTxns(expected_children, orphanage.GetChildrenFromSamePeer(parent, peer)));
256
257 // Erase by wtxid: mutated first
258 BOOST_CHECK_EQUAL(orphanage.EraseTx(mutated_wtxid), 1);
259 BOOST_CHECK(orphanage.HaveTx(normal_wtxid));
260 BOOST_CHECK(!orphanage.HaveTx(mutated_wtxid));
261
262 BOOST_CHECK_EQUAL(orphanage.EraseTx(normal_wtxid), 1);
263 BOOST_CHECK(!orphanage.HaveTx(normal_wtxid));
264 BOOST_CHECK(!orphanage.HaveTx(mutated_wtxid));
265}
266
267
269{
270 FastRandomContext det_rand{true};
271 std::vector<COutPoint> empty_outpoints;
272
273 auto parent1 = MakeTransactionSpending(empty_outpoints, det_rand);
274 auto parent2 = MakeTransactionSpending(empty_outpoints, det_rand);
275
276 // Make sure these parents have different txids otherwise this test won't make sense.
277 while (parent1->GetHash() == parent2->GetHash()) {
278 parent2 = MakeTransactionSpending(empty_outpoints, det_rand);
279 }
280
281 // Create children to go into orphanage.
282 auto child_p1n0 = MakeTransactionSpending({{parent1->GetHash(), 0}}, det_rand);
283 auto child_p2n1 = MakeTransactionSpending({{parent2->GetHash(), 1}}, det_rand);
284 // Spends the same tx twice. Should not cause duplicates.
285 auto child_p1n0_p1n1 = MakeTransactionSpending({{parent1->GetHash(), 0}, {parent1->GetHash(), 1}}, det_rand);
286 // Spends the same outpoint as previous tx. Should still be returned; don't assume outpoints are unique.
287 auto child_p1n0_p2n0 = MakeTransactionSpending({{parent1->GetHash(), 0}, {parent2->GetHash(), 0}}, det_rand);
288
289 const NodeId node1{1};
290 const NodeId node2{2};
291
292 // All orphans provided by node1
293 {
294 TxOrphanage orphanage;
295 BOOST_CHECK(orphanage.AddTx(child_p1n0, node1));
296 BOOST_CHECK(orphanage.AddTx(child_p2n1, node1));
297 BOOST_CHECK(orphanage.AddTx(child_p1n0_p1n1, node1));
298 BOOST_CHECK(orphanage.AddTx(child_p1n0_p2n0, node1));
299
300 std::set<CTransactionRef> expected_parent1_children{child_p1n0, child_p1n0_p2n0, child_p1n0_p1n1};
301 std::set<CTransactionRef> expected_parent2_children{child_p2n1, child_p1n0_p2n0};
302
303 BOOST_CHECK(EqualTxns(expected_parent1_children, orphanage.GetChildrenFromSamePeer(parent1, node1)));
304 BOOST_CHECK(EqualTxns(expected_parent2_children, orphanage.GetChildrenFromSamePeer(parent2, node1)));
305
306 // The peer must match
307 BOOST_CHECK(orphanage.GetChildrenFromSamePeer(parent1, node2).empty());
308 BOOST_CHECK(orphanage.GetChildrenFromSamePeer(parent2, node2).empty());
309
310 // There shouldn't be any children of this tx in the orphanage
311 BOOST_CHECK(orphanage.GetChildrenFromSamePeer(child_p1n0_p2n0, node1).empty());
312 BOOST_CHECK(orphanage.GetChildrenFromSamePeer(child_p1n0_p2n0, node2).empty());
313 }
314
315 // Orphans provided by node1 and node2
316 {
317 TxOrphanage orphanage;
318 BOOST_CHECK(orphanage.AddTx(child_p1n0, node1));
319 BOOST_CHECK(orphanage.AddTx(child_p2n1, node1));
320 BOOST_CHECK(orphanage.AddTx(child_p1n0_p1n1, node2));
321 BOOST_CHECK(orphanage.AddTx(child_p1n0_p2n0, node2));
322
323 // +----------------+---------------+----------------------------------+
324 // | | sender=node1 | sender=node2 |
325 // +----------------+---------------+----------------------------------+
326 // | spends parent1 | child_p1n0 | child_p1n0_p1n1, child_p1n0_p2n0 |
327 // | spends parent2 | child_p2n1 | child_p1n0_p2n0 |
328 // +----------------+---------------+----------------------------------+
329
330 // Children of parent1 from node1:
331 {
332 std::set<CTransactionRef> expected_parent1_node1{child_p1n0};
333
334 BOOST_CHECK(EqualTxns(expected_parent1_node1, orphanage.GetChildrenFromSamePeer(parent1, node1)));
335 }
336
337 // Children of parent2 from node1:
338 {
339 std::set<CTransactionRef> expected_parent2_node1{child_p2n1};
340
341 BOOST_CHECK(EqualTxns(expected_parent2_node1, orphanage.GetChildrenFromSamePeer(parent2, node1)));
342 }
343
344 // Children of parent1 from node2:
345 {
346 std::set<CTransactionRef> expected_parent1_node2{child_p1n0_p1n1, child_p1n0_p2n0};
347
348 BOOST_CHECK(EqualTxns(expected_parent1_node2, orphanage.GetChildrenFromSamePeer(parent1, node2)));
349 }
350
351 // Children of parent2 from node2:
352 {
353 std::set<CTransactionRef> expected_parent2_node2{child_p1n0_p2n0};
354
355 BOOST_CHECK(EqualTxns(expected_parent2_node2, orphanage.GetChildrenFromSamePeer(parent2, node2)));
356 }
357 }
358}
359
360BOOST_AUTO_TEST_CASE(too_large_orphan_tx)
361{
362 TxOrphanage orphanage;
364 tx.vin.resize(1);
365
366 // check that txs larger than MAX_STANDARD_TX_WEIGHT are not added to the orphanage
369 BOOST_CHECK(!orphanage.AddTx(MakeTransactionRef(tx), 0));
370
371 tx.vout.clear();
374 BOOST_CHECK(orphanage.AddTx(MakeTransactionRef(tx), 0));
375}
376
378{
379 FastRandomContext det_rand{true};
380 TxOrphanageTest orphanage{det_rand};
381
382 // Create outpoints that will be spent by transactions in the block
383 std::vector<COutPoint> outpoints;
384 const uint32_t num_outpoints{6};
385 outpoints.reserve(num_outpoints);
386 for (uint32_t i{0}; i < num_outpoints; ++i) {
387 // All the hashes should be different, but change the n just in case.
388 outpoints.emplace_back(Txid::FromUint256(det_rand.rand256()), i);
389 }
390
391 CBlock block;
392 const NodeId node{0};
393
394 auto control_tx = MakeTransactionSpending({}, det_rand);
395 BOOST_CHECK(orphanage.AddTx(control_tx, node));
396
397 auto bo_tx_same_txid = MakeTransactionSpending({outpoints.at(0)}, det_rand);
398 BOOST_CHECK(orphanage.AddTx(bo_tx_same_txid, node));
399 block.vtx.emplace_back(bo_tx_same_txid);
400
401 // 2 transactions with the same txid but different witness
402 auto b_tx_same_txid_diff_witness = MakeTransactionSpending({outpoints.at(1)}, det_rand);
403 block.vtx.emplace_back(b_tx_same_txid_diff_witness);
404
405 auto o_tx_same_txid_diff_witness = MakeMutation(b_tx_same_txid_diff_witness);
406 BOOST_CHECK(orphanage.AddTx(o_tx_same_txid_diff_witness, node));
407
408 // 2 different transactions that spend the same input.
409 auto b_tx_conflict = MakeTransactionSpending({outpoints.at(2)}, det_rand);
410 block.vtx.emplace_back(b_tx_conflict);
411
412 auto o_tx_conflict = MakeTransactionSpending({outpoints.at(2)}, det_rand);
413 BOOST_CHECK(orphanage.AddTx(o_tx_conflict, node));
414
415 // 2 different transactions that have 1 overlapping input.
416 auto b_tx_conflict_partial = MakeTransactionSpending({outpoints.at(3), outpoints.at(4)}, det_rand);
417 block.vtx.emplace_back(b_tx_conflict_partial);
418
419 auto o_tx_conflict_partial_2 = MakeTransactionSpending({outpoints.at(4), outpoints.at(5)}, det_rand);
420 BOOST_CHECK(orphanage.AddTx(o_tx_conflict_partial_2, node));
421
422 orphanage.EraseForBlock(block);
423 for (const auto& expected_removed : {bo_tx_same_txid, o_tx_same_txid_diff_witness, o_tx_conflict, o_tx_conflict_partial_2}) {
424 const auto& expected_removed_wtxid = expected_removed->GetWitnessHash();
425 BOOST_CHECK(!orphanage.HaveTx(expected_removed_wtxid));
426 }
427 // Only remaining tx is control_tx
428 BOOST_CHECK_EQUAL(orphanage.Size(), 1);
429 BOOST_CHECK(orphanage.HaveTx(control_tx->GetWitnessHash()));
430}
431
432BOOST_AUTO_TEST_CASE(multiple_announcers)
433{
434 const NodeId node0{0};
435 const NodeId node1{1};
436 const NodeId node2{2};
437 size_t expected_total_count{0};
438 FastRandomContext det_rand{true};
439 TxOrphanageTest orphanage{det_rand};
440
441 // Check accounting per peer.
442 // Check that EraseForPeer works with multiple announcers.
443 {
444 auto ptx = MakeTransactionSpending({}, det_rand);
445 const auto& wtxid = ptx->GetWitnessHash();
446 BOOST_CHECK(orphanage.AddTx(ptx, node0));
447 BOOST_CHECK(orphanage.HaveTx(wtxid));
448 expected_total_count += 1;
449 BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
450
451 // Adding again should do nothing.
452 BOOST_CHECK(!orphanage.AddTx(ptx, node0));
453 BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
454
455 // We can add another tx with the same txid but different witness.
456 auto ptx_mutated{MakeMutation(ptx)};
457 BOOST_CHECK(orphanage.AddTx(ptx_mutated, node0));
458 BOOST_CHECK(orphanage.HaveTx(ptx_mutated->GetWitnessHash()));
459 expected_total_count += 1;
460
461 BOOST_CHECK(!orphanage.AddTx(ptx, node0));
462
463 // Adding a new announcer should not change overall accounting.
464 BOOST_CHECK(orphanage.AddAnnouncer(ptx->GetWitnessHash(), node2));
465 BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
466
467 // If we already have this announcer, AddAnnouncer returns false.
468 BOOST_CHECK(orphanage.HaveTxFromPeer(ptx->GetWitnessHash(), node2));
469 BOOST_CHECK(!orphanage.AddAnnouncer(ptx->GetWitnessHash(), node2));
470
471 // Same with using AddTx for an existing tx, which is equivalent to using AddAnnouncer
472 BOOST_CHECK(!orphanage.AddTx(ptx, node1));
473 BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
474
475 // if EraseForPeer is called for an orphan with multiple announcers, the orphanage should only
476 // erase that peer from the announcers set.
477 orphanage.EraseForPeer(node0);
478 BOOST_CHECK(orphanage.HaveTx(ptx->GetWitnessHash()));
479 BOOST_CHECK(!orphanage.HaveTxFromPeer(ptx->GetWitnessHash(), node0));
480 // node0 is the only one that announced ptx_mutated
481 BOOST_CHECK(!orphanage.HaveTx(ptx_mutated->GetWitnessHash()));
482 expected_total_count -= 1;
483 BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
484
485 // EraseForPeer should delete the orphan if it's the only announcer left.
486 orphanage.EraseForPeer(node1);
487 BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
488 BOOST_CHECK(orphanage.HaveTx(ptx->GetWitnessHash()));
489 orphanage.EraseForPeer(node2);
490 expected_total_count -= 1;
491 BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
492 BOOST_CHECK(!orphanage.HaveTx(ptx->GetWitnessHash()));
493 }
494
495 // Check that erasure for blocks removes for all peers.
496 {
497 CBlock block;
498 auto tx_block = MakeTransactionSpending({}, det_rand);
499 block.vtx.emplace_back(tx_block);
500 BOOST_CHECK(orphanage.AddTx(tx_block, node0));
501 BOOST_CHECK(!orphanage.AddTx(tx_block, node1));
502
503 expected_total_count += 1;
504
505 BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
506
507 orphanage.EraseForBlock(block);
508
509 expected_total_count -= 1;
510
511 BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
512 }
513}
515{
516 const NodeId node0{0};
517 const NodeId node1{1};
518 const NodeId node2{2};
519 FastRandomContext det_rand{true};
520 TxOrphanageTest orphanage{det_rand};
521 // AddChildrenToWorkSet should pick an announcer randomly
522 {
523 auto tx_missing_parent = MakeTransactionSpending({}, det_rand);
524 auto tx_orphan = MakeTransactionSpending({COutPoint{tx_missing_parent->GetHash(), 0}}, det_rand);
525 const auto& orphan_wtxid = tx_orphan->GetWitnessHash();
526
527 // All 3 peers are announcers.
528 BOOST_CHECK(orphanage.AddTx(tx_orphan, node0));
529 BOOST_CHECK(!orphanage.AddTx(tx_orphan, node1));
530 BOOST_CHECK(orphanage.AddAnnouncer(orphan_wtxid, node2));
531 for (NodeId node = node0; node <= node2; ++node) {
532 BOOST_CHECK(orphanage.HaveTxFromPeer(orphan_wtxid, node));
533 }
534
535 // Parent accepted: add child to all 3 worksets.
536 orphanage.AddChildrenToWorkSet(*tx_missing_parent);
537 BOOST_CHECK_EQUAL(orphanage.GetTxToReconsider(node0), tx_orphan);
538 BOOST_CHECK_EQUAL(orphanage.GetTxToReconsider(node1), tx_orphan);
539 // Don't call GetTxToReconsider(node2) yet because it mutates the workset.
540
541 // EraseForPeer also removes that tx from the workset.
542 orphanage.EraseForPeer(node0);
543 BOOST_CHECK_EQUAL(orphanage.GetTxToReconsider(node0), nullptr);
544
545 // However, the other peers' worksets are not touched.
546 BOOST_CHECK_EQUAL(orphanage.GetTxToReconsider(node2), tx_orphan);
547
548 // Delete this tx, clearing the orphanage.
549 BOOST_CHECK_EQUAL(orphanage.EraseTx(orphan_wtxid), 1);
550 BOOST_CHECK_EQUAL(orphanage.Size(), 0);
551 for (NodeId node = node0; node <= node2; ++node) {
552 BOOST_CHECK_EQUAL(orphanage.GetTxToReconsider(node), nullptr);
553 BOOST_CHECK(!orphanage.HaveTxFromPeer(orphan_wtxid, node));
554 }
555 }
556}
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: block.h:69
std::vector< CTransactionRef > vtx
Definition: block.h:72
An encapsulated private key.
Definition: key.h:35
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:123
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:182
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:103
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:296
Fast randomness source.
Definition: random.h:377
Fillable signing provider that keeps keys in an address->secret map.
virtual bool AddKey(const CKey &key)
uint256 rand256() noexcept
generate a random uint256.
Definition: random.h:308
std::vector< B > randbytes(size_t len) noexcept
Generate random bytes.
Definition: random.h:297
A class to track orphan transactions (failed on TX_MISSING_INPUTS) Since we cannot distinguish orphan...
Definition: txorphanage.h:28
bool AddTx(const CTransactionRef &tx, NodeId peer)
Add a new orphan transaction.
Definition: txorphanage.cpp:15
int EraseTx(const Wtxid &wtxid)
Erase an orphan by wtxid.
Definition: txorphanage.cpp:65
CTransactionRef GetTx(const Wtxid &wtxid) const
std::vector< CTransactionRef > GetChildrenFromSamePeer(const CTransactionRef &parent, NodeId nodeid) const
Get all children that spend from this tx and were received from nodeid.
bool HaveTx(const Wtxid &wtxid) const
Check if we already have an orphan transaction (by wtxid only)
FastRandomContext & m_rng
size_t CountOrphans() const
CTransactionRef RandomOrphan()
TxOrphanageTest(FastRandomContext &rng)
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition: uint256.h:201
static int32_t GetTransactionWeight(const CTransaction &tx)
Definition: validation.h:133
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
@ SIGHASH_ALL
Definition: interpreter.h:30
Definition: messages.h:20
int64_t NodeId
Definition: net.h:97
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
static CTransactionRef MakeMutation(const CTransactionRef &ptx)
static void MakeNewKeyWithFastRandomContext(CKey &key, FastRandomContext &rand_ctx)
BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
static CTransactionRef MakeTransactionSpending(const std::vector< COutPoint > &outpoints, FastRandomContext &det_rand)
static bool EqualTxns(const std::set< CTransactionRef > &set_txns, const std::vector< CTransactionRef > &vec_txns)
static constexpr int32_t MAX_STANDARD_TX_WEIGHT
The maximum weight for transactions we're willing to relay/mine.
Definition: policy.h:27
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:424
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:423
@ OP_1
Definition: script.h:83
static constexpr CAmount CENT
Definition: setup_common.h:47
A mutable version of CTransaction.
Definition: transaction.h:378
std::vector< CTxOut > vout
Definition: transaction.h:380
std::vector< CTxIn > vin
Definition: transaction.h:379
Testing setup that configures a complete environment.
Definition: setup_common.h:121
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition: time.cpp:39
void BulkTransaction(CMutableTransaction &tx, int32_t target_weight)
bool SignSignature(const SigningProvider &provider, const CScript &fromPubKey, CMutableTransaction &txTo, unsigned int nIn, const CAmount &amount, int nHashType, SignatureData &sig_data)
Produce a satisfying script (scriptSig or witness).
static constexpr auto ORPHAN_TX_EXPIRE_TIME
Expiration time for orphan transactions.
Definition: txorphanage.h:18
assert(!tx.IsCoinBase())