Branch data Line data Source code
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>
6 : : #include <primitives/transaction.h>
7 : : #include <pubkey.h>
8 : : #include <script/sign.h>
9 : : #include <script/signingprovider.h>
10 : : #include <test/util/random.h>
11 : : #include <test/util/setup_common.h>
12 : : #include <txorphanage.h>
13 : :
14 : : #include <array>
15 : : #include <cstdint>
16 : :
17 : : #include <boost/test/unit_test.hpp>
18 : :
19 : : BOOST_FIXTURE_TEST_SUITE(orphanage_tests, TestingSetup)
20 : :
21 : 0 : class TxOrphanageTest : public TxOrphanage
22 : : {
23 : : public:
24 : 14 : inline size_t CountOrphans() const
25 : : {
26 [ + - ]: 3 : return m_orphans.size();
27 : : }
28 : :
29 : 60 : CTransactionRef RandomOrphan()
30 : : {
31 : 60 : std::map<Wtxid, OrphanTx>::iterator it;
32 : 60 : it = m_orphans.lower_bound(Wtxid::FromUint256(InsecureRand256()));
33 [ - + ]: 60 : if (it == m_orphans.end())
34 : 0 : it = m_orphans.begin();
35 [ + - ]: 60 : return it->second.tx;
36 : : }
37 : : };
38 : :
39 : 10 : static void MakeNewKeyWithFastRandomContext(CKey& key, FastRandomContext& rand_ctx = g_insecure_rand_ctx)
40 : : {
41 : 10 : std::vector<unsigned char> keydata;
42 : 10 : keydata = rand_ctx.randbytes(32);
43 [ + - ]: 10 : key.Set(keydata.data(), keydata.data() + keydata.size(), /*fCompressedIn=*/true);
44 [ - + ]: 10 : assert(key.IsValid());
45 : 10 : }
46 : :
47 : : // Creates a transaction with 2 outputs. Spends all outpoints. If outpoints is empty, spends a random one.
48 : 9 : static CTransactionRef MakeTransactionSpending(const std::vector<COutPoint>& outpoints, FastRandomContext& det_rand)
49 : : {
50 : 9 : CKey key;
51 [ + - ]: 9 : MakeNewKeyWithFastRandomContext(key, det_rand);
52 [ + - ]: 9 : CMutableTransaction tx;
53 : : // If no outpoints are given, create a random one.
54 [ + + ]: 9 : if (outpoints.empty()) {
55 [ + - ]: 4 : tx.vin.emplace_back(Txid::FromUint256(det_rand.rand256()), 0);
56 : : } else {
57 [ + + ]: 12 : for (const auto& outpoint : outpoints) {
58 [ + - ]: 7 : tx.vin.emplace_back(outpoint);
59 : : }
60 : : }
61 : : // Ensure txid != wtxid
62 [ + - + - ]: 18 : tx.vin[0].scriptWitness.stack.push_back({1});
63 [ + - ]: 9 : tx.vout.resize(2);
64 [ + - ]: 9 : tx.vout[0].nValue = CENT;
65 [ + - + - : 9 : tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
+ - ]
66 [ + - ]: 9 : tx.vout[1].nValue = 3 * CENT;
67 [ + - + - : 9 : tx.vout[1].scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(key.GetPubKey()));
+ - ]
68 [ + - ]: 18 : return MakeTransactionRef(tx);
69 : 9 : }
70 : :
71 : : // Make another (not necessarily valid) tx with the same txid but different wtxid.
72 : 1 : static CTransactionRef MakeMutation(const CTransactionRef& ptx)
73 : : {
74 : 1 : CMutableTransaction tx(*ptx);
75 [ + - + - ]: 2 : tx.vin[0].scriptWitness.stack.push_back({5});
76 [ + - ]: 1 : auto mutated_tx = MakeTransactionRef(tx);
77 [ - + ]: 1 : assert(ptx->GetHash() == mutated_tx->GetHash());
78 : 1 : return mutated_tx;
79 : 1 : }
80 : :
81 : 7 : static bool EqualTxns(const std::set<CTransactionRef>& set_txns, const std::vector<CTransactionRef>& vec_txns)
82 : : {
83 [ + - ]: 7 : if (vec_txns.size() != set_txns.size()) return false;
84 [ + + ]: 19 : for (const auto& tx : vec_txns) {
85 [ + - ]: 12 : if (!set_txns.contains(tx)) return false;
86 : : }
87 : : return true;
88 : : }
89 : 6 : static bool EqualTxns(const std::set<CTransactionRef>& set_txns,
90 : : const std::vector<std::pair<CTransactionRef, NodeId>>& vec_txns)
91 : : {
92 [ + - ]: 6 : if (vec_txns.size() != set_txns.size()) return false;
93 [ + + ]: 16 : for (const auto& [tx, nodeid] : vec_txns) {
94 [ + - ]: 10 : if (!set_txns.contains(tx)) return false;
95 : : }
96 : : return true;
97 : : }
98 : :
99 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
100 : : {
101 : : // This test had non-deterministic coverage due to
102 : : // randomly selected seeds.
103 : : // This seed is chosen so that all branches of the function
104 : : // ecdsa_signature_parse_der_lax are executed during this test.
105 : : // Specifically branches that run only when an ECDSA
106 : : // signature's R and S values have leading zeros.
107 : 1 : g_insecure_rand_ctx.Reseed(uint256{33});
108 : :
109 : 1 : TxOrphanageTest orphanage;
110 : 1 : CKey key;
111 [ + - ]: 1 : MakeNewKeyWithFastRandomContext(key);
112 : 1 : FillableSigningProvider keystore;
113 [ + - + - : 2 : BOOST_CHECK(keystore.AddKey(key));
+ - ]
114 : :
115 : : // Freeze time for length of test
116 : 1 : auto now{GetTime<std::chrono::seconds>()};
117 [ + - ]: 1 : SetMockTime(now);
118 : :
119 : : // 50 orphan transactions:
120 [ + + ]: 51 : for (int i = 0; i < 50; i++)
121 : : {
122 [ + - ]: 50 : CMutableTransaction tx;
123 [ + - ]: 50 : tx.vin.resize(1);
124 : 50 : tx.vin[0].prevout.n = 0;
125 [ + - ]: 50 : tx.vin[0].prevout.hash = Txid::FromUint256(InsecureRand256());
126 [ + - ]: 50 : tx.vin[0].scriptSig << OP_1;
127 [ + - ]: 50 : tx.vout.resize(1);
128 [ + - ]: 50 : tx.vout[0].nValue = 1*CENT;
129 [ + - + - : 50 : tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
+ - ]
130 : :
131 [ + - + - ]: 150 : orphanage.AddTx(MakeTransactionRef(tx), i);
132 : 50 : }
133 : :
134 : : // ... and 50 that depend on other orphans:
135 [ + + ]: 51 : for (int i = 0; i < 50; i++)
136 : : {
137 : 50 : CTransactionRef txPrev = orphanage.RandomOrphan();
138 : :
139 [ + - ]: 50 : CMutableTransaction tx;
140 [ + - ]: 50 : tx.vin.resize(1);
141 [ + - ]: 50 : tx.vin[0].prevout.n = 0;
142 [ + - ]: 50 : tx.vin[0].prevout.hash = txPrev->GetHash();
143 [ + - ]: 50 : tx.vout.resize(1);
144 [ + - ]: 50 : tx.vout[0].nValue = 1*CENT;
145 [ + - + - : 50 : tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
+ - ]
146 : 50 : SignatureData empty;
147 [ + - + - : 100 : BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL, empty));
+ - + - ]
148 : :
149 [ + - + - ]: 100 : orphanage.AddTx(MakeTransactionRef(tx), i);
150 [ + - ]: 150 : }
151 : :
152 : : // This really-big orphan should be ignored:
153 [ + + ]: 11 : for (int i = 0; i < 10; i++)
154 : : {
155 : 10 : CTransactionRef txPrev = orphanage.RandomOrphan();
156 : :
157 [ + - ]: 10 : CMutableTransaction tx;
158 [ + - ]: 10 : tx.vout.resize(1);
159 [ + - ]: 10 : tx.vout[0].nValue = 1*CENT;
160 [ + - + - : 10 : tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
+ - ]
161 [ + - ]: 10 : tx.vin.resize(2777);
162 [ + + ]: 27780 : for (unsigned int j = 0; j < tx.vin.size(); j++)
163 : : {
164 : 27770 : tx.vin[j].prevout.n = j;
165 : 27770 : tx.vin[j].prevout.hash = txPrev->GetHash();
166 : : }
167 : 10 : SignatureData empty;
168 [ + - + - : 20 : BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL, empty));
+ - ]
169 : : // Reuse same signature for other inputs
170 : : // (they don't have to be valid for this test)
171 [ + + ]: 27770 : for (unsigned int j = 1; j < tx.vin.size(); j++)
172 : 27760 : tx.vin[j].scriptSig = tx.vin[0].scriptSig;
173 : :
174 [ + - + - : 40 : BOOST_CHECK(!orphanage.AddTx(MakeTransactionRef(tx), i));
+ - + - +
- ]
175 [ + - + - ]: 30 : }
176 : :
177 [ + - ]: 1 : size_t expected_num_orphans = orphanage.CountOrphans();
178 : :
179 : : // Non-existent peer; nothing should be deleted
180 [ + - ]: 1 : orphanage.EraseForPeer(/*peer=*/-1);
181 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(orphanage.CountOrphans(), expected_num_orphans);
182 : :
183 : : // Each of first three peers stored
184 : : // two transactions each.
185 [ + + ]: 4 : for (NodeId i = 0; i < 3; i++)
186 : : {
187 [ + - ]: 3 : orphanage.EraseForPeer(i);
188 : 3 : expected_num_orphans -= 2;
189 [ + - + - ]: 6 : BOOST_CHECK(orphanage.CountOrphans() == expected_num_orphans);
190 : : }
191 : :
192 : : // Test LimitOrphanTxSize() function, nothing should timeout:
193 : 1 : FastRandomContext rng{/*fDeterministic=*/true};
194 [ + - ]: 1 : orphanage.LimitOrphans(/*max_orphans=*/expected_num_orphans, rng);
195 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(orphanage.CountOrphans(), expected_num_orphans);
196 : 1 : expected_num_orphans -= 1;
197 [ + - ]: 1 : orphanage.LimitOrphans(/*max_orphans=*/expected_num_orphans, rng);
198 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(orphanage.CountOrphans(), expected_num_orphans);
199 [ - + ]: 1 : assert(expected_num_orphans > 40);
200 [ + - ]: 1 : orphanage.LimitOrphans(40, rng);
201 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 40);
202 [ + - ]: 1 : orphanage.LimitOrphans(10, rng);
203 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 10);
204 [ + - ]: 1 : orphanage.LimitOrphans(0, rng);
205 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 0);
206 : :
207 : : // Add one more orphan, check timeout logic
208 [ + - ]: 1 : auto timeout_tx = MakeTransactionSpending(/*outpoints=*/{}, rng);
209 [ + - ]: 1 : orphanage.AddTx(timeout_tx, 0);
210 [ + - ]: 1 : orphanage.LimitOrphans(1, rng);
211 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 1);
212 : :
213 : : // One second shy of expiration
214 [ + - ]: 1 : SetMockTime(now + ORPHAN_TX_EXPIRE_TIME - 1s);
215 [ + - ]: 1 : orphanage.LimitOrphans(1, rng);
216 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 1);
217 : :
218 : : // Jump one more second, orphan should be timed out on limiting
219 [ + - ]: 1 : SetMockTime(now + ORPHAN_TX_EXPIRE_TIME);
220 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 1);
221 [ + - ]: 1 : orphanage.LimitOrphans(1, rng);
222 [ + - + - : 1 : BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 0);
+ - ]
223 : 1 : }
224 : :
225 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(same_txid_diff_witness)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
226 : : {
227 : 1 : FastRandomContext det_rand{true};
228 : 1 : TxOrphanage orphanage;
229 : 1 : NodeId peer{0};
230 : :
231 : 1 : std::vector<COutPoint> empty_outpoints;
232 [ + - ]: 1 : auto parent = MakeTransactionSpending(empty_outpoints, det_rand);
233 : :
234 : : // Create children to go into orphanage.
235 [ + - + - : 2 : auto child_normal = MakeTransactionSpending({{parent->GetHash(), 0}}, det_rand);
+ - ]
236 [ + - ]: 1 : auto child_mutated = MakeMutation(child_normal);
237 : :
238 [ + - ]: 1 : const auto& normal_wtxid = child_normal->GetWitnessHash();
239 : 1 : const auto& mutated_wtxid = child_mutated->GetWitnessHash();
240 [ + - + - : 2 : BOOST_CHECK(normal_wtxid != mutated_wtxid);
+ - ]
241 : :
242 [ + - + - : 2 : BOOST_CHECK(orphanage.AddTx(child_normal, peer));
+ - + - ]
243 : : // EraseTx fails as transaction by this wtxid doesn't exist.
244 [ + - + - : 1 : BOOST_CHECK_EQUAL(orphanage.EraseTx(mutated_wtxid), 0);
+ - ]
245 [ + - + - : 2 : BOOST_CHECK(orphanage.HaveTx(normal_wtxid));
+ - + - ]
246 [ + - + - : 2 : BOOST_CHECK(!orphanage.HaveTx(mutated_wtxid));
+ - + - ]
247 : :
248 : : // Must succeed. Both transactions should be present in orphanage.
249 [ + - + - : 2 : BOOST_CHECK(orphanage.AddTx(child_mutated, peer));
+ - + - ]
250 [ + - + - : 2 : BOOST_CHECK(orphanage.HaveTx(normal_wtxid));
+ - + - ]
251 [ + - + - : 2 : 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 [ + + + - : 3 : std::set<CTransactionRef> expected_children{child_normal, child_mutated};
- - - - ]
255 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_children, orphanage.GetChildrenFromSamePeer(parent, peer)));
+ - + - ]
256 : :
257 : : // Erase by wtxid: mutated first
258 [ + - + - : 1 : BOOST_CHECK_EQUAL(orphanage.EraseTx(mutated_wtxid), 1);
+ - ]
259 [ + - + - : 2 : BOOST_CHECK(orphanage.HaveTx(normal_wtxid));
+ - + - ]
260 [ + - + - : 2 : BOOST_CHECK(!orphanage.HaveTx(mutated_wtxid));
+ - + - ]
261 : :
262 [ + - + - : 1 : BOOST_CHECK_EQUAL(orphanage.EraseTx(normal_wtxid), 1);
+ - ]
263 [ + - + - : 2 : BOOST_CHECK(!orphanage.HaveTx(normal_wtxid));
+ - + - ]
264 [ + - + - : 2 : BOOST_CHECK(!orphanage.HaveTx(mutated_wtxid));
+ - ]
265 [ + - + - : 7 : }
- + + - +
- + - ]
266 : :
267 : :
268 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(get_children)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
269 : : {
270 : 1 : FastRandomContext det_rand{true};
271 : 1 : std::vector<COutPoint> empty_outpoints;
272 : :
273 [ + - ]: 1 : auto parent1 = MakeTransactionSpending(empty_outpoints, det_rand);
274 [ + - ]: 1 : auto parent2 = MakeTransactionSpending(empty_outpoints, det_rand);
275 : :
276 : : // Make sure these parents have different txids otherwise this test won't make sense.
277 [ - + ]: 1 : while (parent1->GetHash() == parent2->GetHash()) {
278 [ # # # # ]: 0 : parent2 = MakeTransactionSpending(empty_outpoints, det_rand);
279 : : }
280 : :
281 : : // Create children to go into orphanage.
282 [ + - + - : 2 : auto child_p1n0 = MakeTransactionSpending({{parent1->GetHash(), 0}}, det_rand);
+ - ]
283 [ + - + - : 2 : auto child_p2n1 = MakeTransactionSpending({{parent2->GetHash(), 1}}, det_rand);
+ - ]
284 : : // Spends the same tx twice. Should not cause duplicates.
285 [ + - + - : 2 : 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 [ + - + - ]: 2 : auto child_p1n0_p2n0 = MakeTransactionSpending({{parent1->GetHash(), 0}, {parent2->GetHash(), 0}}, det_rand);
288 : :
289 : 1 : const NodeId node1{1};
290 : 1 : const NodeId node2{2};
291 : :
292 : : // All orphans provided by node1
293 : 1 : {
294 : 1 : TxOrphanage orphanage;
295 [ + - + - : 2 : BOOST_CHECK(orphanage.AddTx(child_p1n0, node1));
+ - + - ]
296 [ + - + - : 2 : BOOST_CHECK(orphanage.AddTx(child_p2n1, node1));
+ - + - ]
297 [ + - + - : 2 : BOOST_CHECK(orphanage.AddTx(child_p1n0_p1n1, node1));
+ - + - ]
298 [ + - + - : 2 : BOOST_CHECK(orphanage.AddTx(child_p1n0_p2n0, node1));
+ - + - ]
299 : :
300 [ + + + - : 4 : std::set<CTransactionRef> expected_parent1_children{child_p1n0, child_p1n0_p2n0, child_p1n0_p1n1};
- - - - ]
301 [ + + + - : 3 : std::set<CTransactionRef> expected_parent2_children{child_p2n1, child_p1n0_p2n0};
- - - - ]
302 : :
303 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent1_children, orphanage.GetChildrenFromSamePeer(parent1, node1)));
+ - + - ]
304 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent2_children, orphanage.GetChildrenFromSamePeer(parent2, node1)));
+ - + - ]
305 : :
306 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent1_children, orphanage.GetChildrenFromDifferentPeer(parent1, node2)));
+ - + - ]
307 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent2_children, orphanage.GetChildrenFromDifferentPeer(parent2, node2)));
+ - + - ]
308 : :
309 : : // The peer must match
310 [ + - + - : 2 : BOOST_CHECK(orphanage.GetChildrenFromSamePeer(parent1, node2).empty());
+ - + - ]
311 [ + - + - : 2 : BOOST_CHECK(orphanage.GetChildrenFromSamePeer(parent2, node2).empty());
+ - + - ]
312 : :
313 : : // There shouldn't be any children of this tx in the orphanage
314 [ + - + - : 2 : BOOST_CHECK(orphanage.GetChildrenFromSamePeer(child_p1n0_p2n0, node1).empty());
+ - + - ]
315 [ + - + - : 2 : BOOST_CHECK(orphanage.GetChildrenFromSamePeer(child_p1n0_p2n0, node2).empty());
+ - + - ]
316 [ + - + - : 2 : BOOST_CHECK(orphanage.GetChildrenFromDifferentPeer(child_p1n0_p2n0, node1).empty());
+ - + - ]
317 [ + - + - : 2 : BOOST_CHECK(orphanage.GetChildrenFromDifferentPeer(child_p1n0_p2n0, node2).empty());
+ - ]
318 : 1 : }
319 : :
320 : : // Orphans provided by node1 and node2
321 : 1 : {
322 : 1 : TxOrphanage orphanage;
323 [ + - + - : 2 : BOOST_CHECK(orphanage.AddTx(child_p1n0, node1));
+ - + - ]
324 [ + - + - : 2 : BOOST_CHECK(orphanage.AddTx(child_p2n1, node1));
+ - + - ]
325 [ + - + - : 2 : BOOST_CHECK(orphanage.AddTx(child_p1n0_p1n1, node2));
+ - + - ]
326 [ + - + - : 2 : BOOST_CHECK(orphanage.AddTx(child_p1n0_p2n0, node2));
+ - + - ]
327 : :
328 : : // +----------------+---------------+----------------------------------+
329 : : // | | sender=node1 | sender=node2 |
330 : : // +----------------+---------------+----------------------------------+
331 : : // | spends parent1 | child_p1n0 | child_p1n0_p1n1, child_p1n0_p2n0 |
332 : : // | spends parent2 | child_p2n1 | child_p1n0_p2n0 |
333 : : // +----------------+---------------+----------------------------------+
334 : :
335 : : // Children of parent1 from node1:
336 : 1 : {
337 [ + + + - : 2 : std::set<CTransactionRef> expected_parent1_node1{child_p1n0};
- - - - ]
338 : :
339 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent1_node1, orphanage.GetChildrenFromSamePeer(parent1, node1)));
+ - + - ]
340 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent1_node1, orphanage.GetChildrenFromDifferentPeer(parent1, node2)));
+ - ]
341 : 0 : }
342 : :
343 : : // Children of parent2 from node1:
344 : 1 : {
345 [ + + + - : 2 : std::set<CTransactionRef> expected_parent2_node1{child_p2n1};
- - - - ]
346 : :
347 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent2_node1, orphanage.GetChildrenFromSamePeer(parent2, node1)));
+ - + - ]
348 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent2_node1, orphanage.GetChildrenFromDifferentPeer(parent2, node2)));
+ - ]
349 : 0 : }
350 : :
351 : : // Children of parent1 from node2:
352 : 1 : {
353 [ + + + - : 3 : std::set<CTransactionRef> expected_parent1_node2{child_p1n0_p1n1, child_p1n0_p2n0};
- - - - ]
354 : :
355 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent1_node2, orphanage.GetChildrenFromSamePeer(parent1, node2)));
+ - + - ]
356 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent1_node2, orphanage.GetChildrenFromDifferentPeer(parent1, node1)));
+ - ]
357 : 0 : }
358 : :
359 : : // Children of parent2 from node2:
360 : 1 : {
361 [ + + + - : 2 : std::set<CTransactionRef> expected_parent2_node2{child_p1n0_p2n0};
- - - - ]
362 : :
363 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent2_node2, orphanage.GetChildrenFromSamePeer(parent2, node2)));
+ - + - ]
364 [ + - + - : 2 : BOOST_CHECK(EqualTxns(expected_parent2_node2, orphanage.GetChildrenFromDifferentPeer(parent2, node1)));
+ - ]
365 : 0 : }
366 [ + - ]: 1 : }
367 [ + - + - : 22 : }
+ - - + +
- + - - +
+ - - + +
- - + + -
+ - - + +
- - + + -
+ - + - +
- + - ]
368 : :
369 : : BOOST_AUTO_TEST_SUITE_END()
|