Bitcoin ABC  0.24.11
P2P Digital Currency
peermanager_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020 The Bitcoin developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
9 #include <avalanche/test/util.h>
10 #include <script/standard.h>
11 #include <util/translation.h>
12 #include <validation.h>
13 
14 #include <test/util/setup_common.h>
15 
16 #include <boost/test/unit_test.hpp>
17 
18 using namespace avalanche;
19 
20 namespace avalanche {
21 namespace {
22  struct TestPeerManager {
23  static bool nodeBelongToPeer(const PeerManager &pm, NodeId nodeid,
24  PeerId peerid) {
25  return pm.forNode(nodeid, [&](const Node &node) {
26  return node.peerid == peerid;
27  });
28  }
29 
30  static bool isNodePending(const PeerManager &pm, NodeId nodeid) {
31  auto &pendingNodesView = pm.pendingNodes.get<by_nodeid>();
32  return pendingNodesView.find(nodeid) != pendingNodesView.end();
33  }
34 
35  static PeerId registerAndGetPeerId(PeerManager &pm,
36  const ProofRef &proof) {
37  pm.registerProof(proof);
38 
39  auto &pview = pm.peers.get<by_proofid>();
40  auto it = pview.find(proof->getId());
41  return it == pview.end() ? NO_PEER : it->peerid;
42  }
43  };
44 } // namespace
45 } // namespace avalanche
46 
47 BOOST_FIXTURE_TEST_SUITE(peermanager_tests, TestingSetup)
48 
49 BOOST_AUTO_TEST_CASE(select_peer_linear) {
50  // No peers.
53 
54  // One peer
55  const std::vector<Slot> oneslot = {{100, 100, 23}};
56 
57  // Undershoot
58  BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 0, 300), NO_PEER);
59  BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 42, 300), NO_PEER);
60  BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 99, 300), NO_PEER);
61 
62  // Nailed it
63  BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 100, 300), 23);
64  BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 142, 300), 23);
65  BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 199, 300), 23);
66 
67  // Overshoot
68  BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 200, 300), NO_PEER);
69  BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 242, 300), NO_PEER);
70  BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 299, 300), NO_PEER);
71 
72  // Two peers
73  const std::vector<Slot> twoslots = {{100, 100, 69}, {300, 100, 42}};
74 
75  // Undershoot
76  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 0, 500), NO_PEER);
77  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 42, 500), NO_PEER);
78  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 99, 500), NO_PEER);
79 
80  // First entry
81  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 100, 500), 69);
82  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 142, 500), 69);
83  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 199, 500), 69);
84 
85  // In between
86  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 200, 500), NO_PEER);
87  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 242, 500), NO_PEER);
88  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 299, 500), NO_PEER);
89 
90  // Second entry
91  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 300, 500), 42);
92  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 342, 500), 42);
93  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 399, 500), 42);
94 
95  // Overshoot
96  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 400, 500), NO_PEER);
97  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 442, 500), NO_PEER);
98  BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 499, 500), NO_PEER);
99 }
100 
101 BOOST_AUTO_TEST_CASE(select_peer_dichotomic) {
102  std::vector<Slot> slots;
103 
104  // 100 peers of size 1 with 1 empty element apart.
105  uint64_t max = 1;
106  for (int i = 0; i < 100; i++) {
107  slots.emplace_back(max, 1, i);
108  max += 2;
109  }
110 
111  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 4, max), NO_PEER);
112 
113  // Check that we get what we expect.
114  for (int i = 0; i < 100; i++) {
115  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 2 * i, max), NO_PEER);
116  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 2 * i + 1, max), i);
117  }
118 
119  BOOST_CHECK_EQUAL(selectPeerImpl(slots, max, max), NO_PEER);
120 
121  // Update the slots to be heavily skewed toward the last element.
122  slots[99] = slots[99].withScore(101);
123  max = slots[99].getStop();
124  BOOST_CHECK_EQUAL(max, 300);
125 
126  for (int i = 0; i < 100; i++) {
127  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 2 * i, max), NO_PEER);
128  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 2 * i + 1, max), i);
129  }
130 
131  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 200, max), 99);
132  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 256, max), 99);
133  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 299, max), 99);
134  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 300, max), NO_PEER);
135 
136  // Update the slots to be heavily skewed toward the first element.
137  for (int i = 0; i < 100; i++) {
138  slots[i] = slots[i].withStart(slots[i].getStart() + 100);
139  }
140 
141  slots[0] = Slot(1, slots[0].getStop() - 1, slots[0].getPeerId());
142  slots[99] = slots[99].withScore(1);
143  max = slots[99].getStop();
144  BOOST_CHECK_EQUAL(max, 300);
145 
146  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 0, max), NO_PEER);
147  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 1, max), 0);
148  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 42, max), 0);
149 
150  for (int i = 0; i < 100; i++) {
151  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 100 + 2 * i + 1, max), i);
152  BOOST_CHECK_EQUAL(selectPeerImpl(slots, 100 + 2 * i + 2, max), NO_PEER);
153  }
154 }
155 
156 BOOST_AUTO_TEST_CASE(select_peer_random) {
157  for (int c = 0; c < 1000; c++) {
158  size_t size = InsecureRandBits(10) + 1;
159  std::vector<Slot> slots;
160  slots.reserve(size);
161 
162  uint64_t max = InsecureRandBits(3);
163  auto next = [&]() {
164  uint64_t r = max;
165  max += InsecureRandBits(3);
166  return r;
167  };
168 
169  for (size_t i = 0; i < size; i++) {
170  const uint64_t start = next();
171  const uint32_t score = InsecureRandBits(3);
172  max += score;
173  slots.emplace_back(start, score, i);
174  }
175 
176  for (int k = 0; k < 100; k++) {
177  uint64_t s = max > 0 ? InsecureRandRange(max) : 0;
178  auto i = selectPeerImpl(slots, s, max);
179  // /!\ Because of the way we construct the vector, the peer id is
180  // always the index. This might not be the case in practice.
181  BOOST_CHECK(i == NO_PEER || slots[i].contains(s));
182  }
183  }
184 }
185 
187  uint32_t score) {
188  auto proof = buildRandomProof(score);
189  BOOST_CHECK(pm.registerProof(proof));
190  BOOST_CHECK(pm.addNode(node, proof->getId()));
191 };
192 
193 BOOST_AUTO_TEST_CASE(peer_probabilities) {
194  // No peers.
197 
198  const NodeId node0 = 42, node1 = 69, node2 = 37;
199 
200  // One peer, we always return it.
202  BOOST_CHECK_EQUAL(pm.selectNode(), node0);
203 
204  // Two peers, verify ratio.
205  addNodeWithScore(pm, node1, 2 * MIN_VALID_PROOF_SCORE);
206 
207  std::unordered_map<PeerId, int> results = {};
208  for (int i = 0; i < 10000; i++) {
209  size_t n = pm.selectNode();
210  BOOST_CHECK(n == node0 || n == node1);
211  results[n]++;
212  }
213 
214  BOOST_CHECK(abs(2 * results[0] - results[1]) < 500);
215 
216  // Three peers, verify ratio.
218 
219  results.clear();
220  for (int i = 0; i < 10000; i++) {
221  size_t n = pm.selectNode();
222  BOOST_CHECK(n == node0 || n == node1 || n == node2);
223  results[n]++;
224  }
225 
226  BOOST_CHECK(abs(results[0] - results[1] + results[2]) < 500);
227 }
228 
229 BOOST_AUTO_TEST_CASE(remove_peer) {
230  // No peers.
233 
234  // Add 4 peers.
235  std::array<PeerId, 8> peerids;
236  for (int i = 0; i < 4; i++) {
237  auto p = buildRandomProof(100);
238  peerids[i] = TestPeerManager::registerAndGetPeerId(pm, p);
239  BOOST_CHECK(pm.addNode(InsecureRand32(), p->getId()));
240  }
241 
242  BOOST_CHECK_EQUAL(pm.getSlotCount(), 400);
244 
245  for (int i = 0; i < 100; i++) {
246  PeerId p = pm.selectPeer();
247  BOOST_CHECK(p == peerids[0] || p == peerids[1] || p == peerids[2] ||
248  p == peerids[3]);
249  }
250 
251  // Remove one peer, it nevers show up now.
252  BOOST_CHECK(pm.removePeer(peerids[2]));
253  BOOST_CHECK_EQUAL(pm.getSlotCount(), 400);
255 
256  // Make sure we compact to never get NO_PEER.
257  BOOST_CHECK_EQUAL(pm.compact(), 100);
258  BOOST_CHECK(pm.verify());
259  BOOST_CHECK_EQUAL(pm.getSlotCount(), 300);
261 
262  for (int i = 0; i < 100; i++) {
263  PeerId p = pm.selectPeer();
264  BOOST_CHECK(p == peerids[0] || p == peerids[1] || p == peerids[3]);
265  }
266 
267  // Add 4 more peers.
268  for (int i = 0; i < 4; i++) {
269  auto p = buildRandomProof(100);
270  peerids[i + 4] = TestPeerManager::registerAndGetPeerId(pm, p);
271  BOOST_CHECK(pm.addNode(InsecureRand32(), p->getId()));
272  }
273 
274  BOOST_CHECK_EQUAL(pm.getSlotCount(), 700);
276 
277  BOOST_CHECK(pm.removePeer(peerids[0]));
278  BOOST_CHECK_EQUAL(pm.getSlotCount(), 700);
280 
281  // Removing the last entry do not increase fragmentation.
282  BOOST_CHECK(pm.removePeer(peerids[7]));
283  BOOST_CHECK_EQUAL(pm.getSlotCount(), 600);
285 
286  // Make sure we compact to never get NO_PEER.
287  BOOST_CHECK_EQUAL(pm.compact(), 100);
288  BOOST_CHECK(pm.verify());
289  BOOST_CHECK_EQUAL(pm.getSlotCount(), 500);
291 
292  for (int i = 0; i < 100; i++) {
293  PeerId p = pm.selectPeer();
294  BOOST_CHECK(p == peerids[1] || p == peerids[3] || p == peerids[4] ||
295  p == peerids[5] || p == peerids[6]);
296  }
297 
298  // Removing non existent peers fails.
299  BOOST_CHECK(!pm.removePeer(peerids[0]));
300  BOOST_CHECK(!pm.removePeer(peerids[2]));
301  BOOST_CHECK(!pm.removePeer(peerids[7]));
303 }
304 
305 BOOST_AUTO_TEST_CASE(compact_slots) {
307 
308  // Add 4 peers.
309  std::array<PeerId, 4> peerids;
310  for (int i = 0; i < 4; i++) {
311  auto p = buildRandomProof(100);
312  peerids[i] = TestPeerManager::registerAndGetPeerId(pm, p);
313  BOOST_CHECK(pm.addNode(InsecureRand32(), p->getId()));
314  }
315 
316  // Remove all peers.
317  for (auto p : peerids) {
318  pm.removePeer(p);
319  }
320 
321  BOOST_CHECK_EQUAL(pm.getSlotCount(), 300);
323 
324  for (int i = 0; i < 100; i++) {
326  }
327 
328  BOOST_CHECK_EQUAL(pm.compact(), 300);
329  BOOST_CHECK(pm.verify());
332 }
333 
336 
337  // Create one peer.
338  auto proof = buildRandomProof(10000000 * MIN_VALID_PROOF_SCORE);
339  BOOST_CHECK(pm.registerProof(proof));
341 
342  // Add 4 nodes.
343  const ProofId &proofid = proof->getId();
344  for (int i = 0; i < 4; i++) {
345  BOOST_CHECK(pm.addNode(i, proofid));
346  }
347 
348  for (int i = 0; i < 100; i++) {
349  NodeId n = pm.selectNode();
350  BOOST_CHECK(n >= 0 && n < 4);
351  BOOST_CHECK(
352  pm.updateNextRequestTime(n, std::chrono::steady_clock::now()));
353  }
354 
355  // Remove a node, check that it doesn't show up.
356  BOOST_CHECK(pm.removeNode(2));
357 
358  for (int i = 0; i < 100; i++) {
359  NodeId n = pm.selectNode();
360  BOOST_CHECK(n == 0 || n == 1 || n == 3);
361  BOOST_CHECK(
362  pm.updateNextRequestTime(n, std::chrono::steady_clock::now()));
363  }
364 
365  // Push a node's timeout in the future, so that it doesn't show up.
366  BOOST_CHECK(pm.updateNextRequestTime(1, std::chrono::steady_clock::now() +
367  std::chrono::hours(24)));
368 
369  for (int i = 0; i < 100; i++) {
370  NodeId n = pm.selectNode();
371  BOOST_CHECK(n == 0 || n == 3);
372  BOOST_CHECK(
373  pm.updateNextRequestTime(n, std::chrono::steady_clock::now()));
374  }
375 
376  // Move a node from a peer to another. This peer has a very low score such
377  // as chances of being picked are 1 in 10 million.
379 
380  int node3selected = 0;
381  for (int i = 0; i < 100; i++) {
382  NodeId n = pm.selectNode();
383  if (n == 3) {
384  // Selecting this node should be exceedingly unlikely.
385  BOOST_CHECK(node3selected++ < 1);
386  } else {
387  BOOST_CHECK_EQUAL(n, 0);
388  }
389  BOOST_CHECK(
390  pm.updateNextRequestTime(n, std::chrono::steady_clock::now()));
391  }
392 }
393 
394 BOOST_AUTO_TEST_CASE(node_binding) {
396 
398  const ProofId &proofid = proof->getId();
399 
400  // Add a bunch of nodes with no associated peer
401  for (int i = 0; i < 10; i++) {
402  BOOST_CHECK(!pm.addNode(i, proofid));
403  BOOST_CHECK(TestPeerManager::isNodePending(pm, i));
404  }
405 
406  // Now create the peer and check all the nodes are bound
407  const PeerId peerid = TestPeerManager::registerAndGetPeerId(pm, proof);
408  BOOST_CHECK_NE(peerid, NO_PEER);
409  for (int i = 0; i < 10; i++) {
410  BOOST_CHECK(!TestPeerManager::isNodePending(pm, i));
411  BOOST_CHECK(TestPeerManager::nodeBelongToPeer(pm, i, peerid));
412  }
413  BOOST_CHECK(pm.verify());
414 
415  // Disconnect some nodes
416  for (int i = 0; i < 5; i++) {
417  BOOST_CHECK(pm.removeNode(i));
418  BOOST_CHECK(!TestPeerManager::isNodePending(pm, i));
419  BOOST_CHECK(!TestPeerManager::nodeBelongToPeer(pm, i, peerid));
420  }
421 
422  // Add nodes when the peer already exists
423  for (int i = 0; i < 5; i++) {
424  BOOST_CHECK(pm.addNode(i, proofid));
425  BOOST_CHECK(!TestPeerManager::isNodePending(pm, i));
426  BOOST_CHECK(TestPeerManager::nodeBelongToPeer(pm, i, peerid));
427  }
428 
429  auto alt_proof = buildRandomProof(MIN_VALID_PROOF_SCORE);
430  const ProofId &alt_proofid = alt_proof->getId();
431 
432  // Update some nodes from a known proof to an unknown proof
433  for (int i = 0; i < 5; i++) {
434  BOOST_CHECK(!pm.addNode(i, alt_proofid));
435  BOOST_CHECK(TestPeerManager::isNodePending(pm, i));
436  BOOST_CHECK(!TestPeerManager::nodeBelongToPeer(pm, i, peerid));
437  }
438 
439  auto alt2_proof = buildRandomProof(MIN_VALID_PROOF_SCORE);
440  const ProofId &alt2_proofid = alt2_proof->getId();
441 
442  // Update some nodes from an unknown proof to another unknown proof
443  for (int i = 0; i < 5; i++) {
444  BOOST_CHECK(!pm.addNode(i, alt2_proofid));
445  BOOST_CHECK(TestPeerManager::isNodePending(pm, i));
446  }
447 
448  // Update some nodes from an unknown proof to a known proof
449  for (int i = 0; i < 5; i++) {
450  BOOST_CHECK(pm.addNode(i, proofid));
451  BOOST_CHECK(!TestPeerManager::isNodePending(pm, i));
452  BOOST_CHECK(TestPeerManager::nodeBelongToPeer(pm, i, peerid));
453  }
454 
455  // Remove the peer, the nodes should be pending again
456  BOOST_CHECK(pm.removePeer(peerid));
457  BOOST_CHECK(!pm.exists(proof->getId()));
458  for (int i = 0; i < 10; i++) {
459  BOOST_CHECK(TestPeerManager::isNodePending(pm, i));
460  BOOST_CHECK(!TestPeerManager::nodeBelongToPeer(pm, i, peerid));
461  }
462  BOOST_CHECK(pm.verify());
463 }
464 
465 BOOST_AUTO_TEST_CASE(node_binding_reorg) {
467 
469  auto key = CKey::MakeCompressedKey();
470  const CScript script = GetScriptForDestination(PKHash(key.GetPubKey()));
471  COutPoint utxo(TxId(GetRandHash()), 0);
472  Amount amount = 1 * COIN;
473  const int height = 1234;
474  BOOST_CHECK(pb.addUTXO(utxo, amount, height, false, key));
475  auto proof = pb.build();
476  const ProofId &proofid = proof->getId();
477 
478  {
479  LOCK(cs_main);
481  coins.AddCoin(utxo, Coin(CTxOut(amount, script), height, false), false);
482  }
483 
484  PeerId peerid = TestPeerManager::registerAndGetPeerId(pm, proof);
485  BOOST_CHECK_NE(peerid, NO_PEER);
486  BOOST_CHECK(pm.verify());
487 
488  // Add nodes to our peer
489  for (int i = 0; i < 10; i++) {
490  BOOST_CHECK(pm.addNode(i, proofid));
491  BOOST_CHECK(!TestPeerManager::isNodePending(pm, i));
492  BOOST_CHECK(TestPeerManager::nodeBelongToPeer(pm, i, peerid));
493  }
494 
495  // Orphan the proof
496  {
497  LOCK(cs_main);
499  coins.SpendCoin(utxo);
500  }
501 
502  pm.updatedBlockTip();
503  BOOST_CHECK(pm.isOrphan(proofid));
504  BOOST_CHECK(!pm.isBoundToPeer(proofid));
505  for (int i = 0; i < 10; i++) {
506  BOOST_CHECK(TestPeerManager::isNodePending(pm, i));
507  BOOST_CHECK(!TestPeerManager::nodeBelongToPeer(pm, i, peerid));
508  }
509  BOOST_CHECK(pm.verify());
510 
511  // Make the proof great again
512  {
513  LOCK(cs_main);
515  coins.AddCoin(utxo, Coin(CTxOut(amount, script), height, false), false);
516  }
517 
518  pm.updatedBlockTip();
519  BOOST_CHECK(!pm.isOrphan(proofid));
520  BOOST_CHECK(pm.isBoundToPeer(proofid));
521  // The peerid has certainly been updated
522  peerid = TestPeerManager::registerAndGetPeerId(pm, proof);
523  BOOST_CHECK_NE(peerid, NO_PEER);
524  for (int i = 0; i < 10; i++) {
525  BOOST_CHECK(!TestPeerManager::isNodePending(pm, i));
526  BOOST_CHECK(TestPeerManager::nodeBelongToPeer(pm, i, peerid));
527  }
528  BOOST_CHECK(pm.verify());
529 }
530 
531 BOOST_AUTO_TEST_CASE(proof_conflict) {
532  auto key = CKey::MakeCompressedKey();
533  const CScript script = GetScriptForDestination(PKHash(key.GetPubKey()));
534 
535  TxId txid1(GetRandHash());
536  TxId txid2(GetRandHash());
537  BOOST_CHECK(txid1 != txid2);
538 
539  const Amount v = 5 * COIN;
540  const int height = 1234;
541 
542  {
543  LOCK(cs_main);
545 
546  for (int i = 0; i < 10; i++) {
547  coins.AddCoin(COutPoint(txid1, i),
548  Coin(CTxOut(v, script), height, false), false);
549  coins.AddCoin(COutPoint(txid2, i),
550  Coin(CTxOut(v, script), height, false), false);
551  }
552  }
553 
555  CKey masterKey = CKey::MakeCompressedKey();
556  const auto getPeerId = [&](const std::vector<COutPoint> &outpoints) {
557  ProofBuilder pb(0, 0, masterKey);
558  for (const auto &o : outpoints) {
559  BOOST_CHECK(pb.addUTXO(o, v, height, false, key));
560  }
561 
562  return TestPeerManager::registerAndGetPeerId(pm, pb.build());
563  };
564 
565  // Add one peer.
566  const PeerId peer1 = getPeerId({COutPoint(txid1, 0)});
567  BOOST_CHECK(peer1 != NO_PEER);
568 
569  // Same proof, same peer.
570  BOOST_CHECK_EQUAL(getPeerId({COutPoint(txid1, 0)}), peer1);
571 
572  // Different txid, different proof.
573  const PeerId peer2 = getPeerId({COutPoint(txid2, 0)});
574  BOOST_CHECK(peer2 != NO_PEER && peer2 != peer1);
575 
576  // Different index, different proof.
577  const PeerId peer3 = getPeerId({COutPoint(txid1, 1)});
578  BOOST_CHECK(peer3 != NO_PEER && peer3 != peer1);
579 
580  // Empty proof, no peer.
581  BOOST_CHECK_EQUAL(getPeerId({}), NO_PEER);
582 
583  // Multiple inputs.
584  const PeerId peer4 = getPeerId({COutPoint(txid1, 2), COutPoint(txid2, 2)});
585  BOOST_CHECK(peer4 != NO_PEER && peer4 != peer1);
586 
587  // Duplicated input.
588  {
590  COutPoint o(txid1, 3);
591  BOOST_CHECK(pb.addUTXO(o, v, height, false, key));
592  BOOST_CHECK(
594  }
595 
596  // Multiple inputs, collision on first input.
597  BOOST_CHECK_EQUAL(getPeerId({COutPoint(txid1, 0), COutPoint(txid2, 4)}),
598  NO_PEER);
599 
600  // Mutliple inputs, collision on second input.
601  BOOST_CHECK_EQUAL(getPeerId({COutPoint(txid1, 4), COutPoint(txid2, 0)}),
602  NO_PEER);
603 
604  // Mutliple inputs, collision on both inputs.
605  BOOST_CHECK_EQUAL(getPeerId({COutPoint(txid1, 0), COutPoint(txid2, 2)}),
606  NO_PEER);
607 }
608 
609 BOOST_AUTO_TEST_CASE(orphan_proofs) {
611 
612  auto key = CKey::MakeCompressedKey();
613  const CScript script = GetScriptForDestination(PKHash(key.GetPubKey()));
614 
615  COutPoint outpoint1 = COutPoint(TxId(GetRandHash()), 0);
616  COutPoint outpoint2 = COutPoint(TxId(GetRandHash()), 0);
617  COutPoint outpoint3 = COutPoint(TxId(GetRandHash()), 0);
618 
619  const Amount v = 5 * COIN;
620  const int height = 1234;
621  const int wrongHeight = 12345;
622 
623  const auto makeProof = [&](const COutPoint &outpoint, const int h) {
625  BOOST_CHECK(pb.addUTXO(outpoint, v, h, false, key));
626  return pb.build();
627  };
628 
629  auto proof1 = makeProof(outpoint1, height);
630  auto proof2 = makeProof(outpoint2, height);
631  auto proof3 = makeProof(outpoint3, wrongHeight);
632 
633  const Coin coin = Coin(CTxOut(v, script), height, false);
634 
635  // Add outpoints 1 and 3, not 2
636  {
637  LOCK(cs_main);
639  coins.AddCoin(outpoint1, coin, false);
640  coins.AddCoin(outpoint3, coin, false);
641  }
642 
643  // Add the proofs
644  BOOST_CHECK(pm.registerProof(proof1));
645  BOOST_CHECK(!pm.registerProof(proof2));
646  BOOST_CHECK(!pm.registerProof(proof3));
647 
648  auto checkOrphan = [&](const ProofRef &proof, bool expectedOrphan) {
649  const ProofId &proofid = proof->getId();
650  BOOST_CHECK(pm.exists(proofid));
651 
652  BOOST_CHECK_EQUAL(pm.isOrphan(proofid), expectedOrphan);
653  BOOST_CHECK_EQUAL(pm.isBoundToPeer(proofid), !expectedOrphan);
654 
655  bool ret = false;
656  pm.forEachPeer([&](const Peer &peer) {
657  if (proof->getId() == peer.proof->getId()) {
658  ret = true;
659  }
660  });
661  BOOST_CHECK_EQUAL(ret, !expectedOrphan);
662  };
663 
664  // Good
665  checkOrphan(proof1, false);
666  // MISSING_UTXO
667  checkOrphan(proof2, true);
668  // HEIGHT_MISMATCH
669  checkOrphan(proof3, true);
670 
671  // Add outpoint2, proof2 is no longer considered orphan
672  {
673  LOCK(cs_main);
675  coins.AddCoin(outpoint2, coin, false);
676  }
677 
678  pm.updatedBlockTip();
679  checkOrphan(proof2, false);
680 
681  // The status of proof1 and proof3 are unchanged
682  checkOrphan(proof1, false);
683  checkOrphan(proof3, true);
684 
685  // Spend outpoint1, proof1 becomes orphan
686  {
687  LOCK(cs_main);
689  coins.SpendCoin(outpoint1);
690  }
691 
692  pm.updatedBlockTip();
693  checkOrphan(proof1, true);
694 
695  // The status of proof2 and proof3 are unchanged
696  checkOrphan(proof2, false);
697  checkOrphan(proof3, true);
698 
699  // A reorg could make a previous HEIGHT_MISMATCH become valid
700  {
701  LOCK(cs_main);
703  coins.SpendCoin(outpoint3);
704  coins.AddCoin(outpoint3, Coin(CTxOut(v, script), wrongHeight, false),
705  false);
706  }
707 
708  pm.updatedBlockTip();
709  checkOrphan(proof3, false);
710 
711  // The status of proof 1 and proof2 are unchanged
712  checkOrphan(proof1, true);
713  checkOrphan(proof2, false);
714 }
715 
716 BOOST_AUTO_TEST_CASE(dangling_node) {
718 
720  PeerId peerid = TestPeerManager::registerAndGetPeerId(pm, proof);
721  BOOST_CHECK_NE(peerid, NO_PEER);
722 
723  const TimePoint theFuture(std::chrono::steady_clock::now() +
724  std::chrono::hours(24));
725 
726  // Add nodes to this peer and update their request time far in the future
727  for (int i = 0; i < 10; i++) {
728  BOOST_CHECK(pm.addNode(i, proof->getId()));
729  BOOST_CHECK(pm.updateNextRequestTime(i, theFuture));
730  }
731 
732  // Remove the peer
733  BOOST_CHECK(pm.removePeer(peerid));
734 
735  // Check the nodes are still there
736  for (int i = 0; i < 10; i++) {
737  BOOST_CHECK(pm.forNode(i, [](const Node &n) { return true; }));
738  }
739 
740  // Build a new one
742  peerid = TestPeerManager::registerAndGetPeerId(pm, proof);
743  BOOST_CHECK_NE(peerid, NO_PEER);
744 
745  // Update the nodes with the new proof
746  for (int i = 0; i < 10; i++) {
747  BOOST_CHECK(pm.addNode(i, proof->getId()));
748  BOOST_CHECK(pm.forNode(
749  i, [&](const Node &n) { return n.nextRequestTime == theFuture; }));
750  }
751 
752  // Remove the peer
753  BOOST_CHECK(pm.removePeer(peerid));
754 
755  // Disconnect the nodes
756  for (int i = 0; i < 10; i++) {
757  BOOST_CHECK(pm.removeNode(i));
758  }
759 }
760 
761 BOOST_AUTO_TEST_CASE(proof_accessors) {
763 
764  constexpr int numProofs = 10;
765 
766  std::vector<ProofRef> proofs;
767  proofs.reserve(numProofs);
768  for (int i = 0; i < numProofs; i++) {
769  proofs.push_back(buildRandomProof(MIN_VALID_PROOF_SCORE));
770  }
771 
772  for (int i = 0; i < numProofs; i++) {
773  BOOST_CHECK(pm.registerProof(proofs[i]));
774  // Fail to add an existing proof
775  BOOST_CHECK(!pm.registerProof(proofs[i]));
776 
777  for (int added = 0; added <= i; added++) {
778  auto proof = pm.getProof(proofs[added]->getId());
779  BOOST_CHECK(proof != nullptr);
780 
781  const ProofId &proofid = proof->getId();
782  BOOST_CHECK_EQUAL(proofid, proofs[added]->getId());
783  }
784  }
785 
786  // No stake, copied from proof_tests.cpp
787  const std::string badProofHex(
788  "96527eae083f1f24625f049d9e54bb9a2102a93d98bf42ab90cfc0bf9e7c634ed76a7"
789  "3e95b02cacfd357b64e4fb6c92e92dd00");
791  Proof badProof;
792  BOOST_CHECK(Proof::FromHex(badProof, badProofHex, error));
793  BOOST_CHECK(
794  !pm.registerProof(std::make_shared<Proof>(std::move(badProof))));
795 }
796 
797 BOOST_AUTO_TEST_CASE(conflicting_proof_rescan) {
799 
800  const CKey key = CKey::MakeCompressedKey();
801 
802  const Amount amount = 10 * COIN;
803  const uint32_t height = 100;
804  const bool is_coinbase = false;
805 
807 
808  auto addCoin = [&]() {
809  LOCK(cs_main);
810  COutPoint outpoint(TxId(GetRandHash()), 0);
812  coins.AddCoin(outpoint,
813  Coin(CTxOut(amount, script), height, is_coinbase), false);
814 
815  return outpoint;
816  };
817 
818  const COutPoint conflictingOutpoint = addCoin();
819  const COutPoint outpointToSend = addCoin();
820 
821  ProofRef proofToInvalidate;
822  {
823  ProofBuilder pb(0, 0, key);
824  BOOST_CHECK(
825  pb.addUTXO(conflictingOutpoint, amount, height, is_coinbase, key));
826  BOOST_CHECK(
827  pb.addUTXO(outpointToSend, amount, height, is_coinbase, key));
828  proofToInvalidate = pb.build();
829  }
830 
831  BOOST_CHECK(pm.registerProof(proofToInvalidate));
832 
833  ProofRef conflictingProof;
834  {
835  ProofBuilder pb(0, 0, key);
836  BOOST_CHECK(
837  pb.addUTXO(conflictingOutpoint, amount, height, is_coinbase, key));
838  BOOST_CHECK(pb.addUTXO(addCoin(), amount, height, is_coinbase, key));
839  conflictingProof = pb.build();
840  }
841 
842  BOOST_CHECK(!pm.registerProof(conflictingProof));
843  BOOST_CHECK(pm.isInConflictingPool(conflictingProof->getId()));
844 
845  {
846  LOCK(cs_main);
848  // Make proofToInvalidate invalid
849  coins.SpendCoin(outpointToSend);
850  }
851 
852  pm.updatedBlockTip();
853 
854  BOOST_CHECK(pm.isOrphan(proofToInvalidate->getId()));
855 
856  BOOST_CHECK(!pm.isInConflictingPool(conflictingProof->getId()));
857  BOOST_CHECK(pm.isBoundToPeer(conflictingProof->getId()));
858 }
859 
860 BOOST_AUTO_TEST_CASE(conflicting_proof_selection) {
862 
863  const CKey key = CKey::MakeCompressedKey();
864 
865  const Amount amount(10 * COIN);
866  const uint32_t height = 100;
867  const bool is_coinbase = false;
868 
870 
871  auto addCoin = [&](const Amount &amount) {
872  LOCK(cs_main);
873  const COutPoint outpoint(TxId(GetRandHash()), 0);
875  coins.AddCoin(outpoint,
876  Coin(CTxOut(amount, script), height, is_coinbase), false);
877  return outpoint;
878  };
879 
880  // This will be the conflicting UTXO for all the following proofs
881  auto conflictingOutpoint = addCoin(amount);
882 
883  auto buildProofWithSequence = [&](uint64_t sequence) {
884  ProofBuilder pb(sequence, GetRandInt(std::numeric_limits<int>::max()),
885  key);
886  BOOST_CHECK(
887  pb.addUTXO(conflictingOutpoint, amount, height, is_coinbase, key));
888 
889  return pb.build();
890  };
891 
892  auto proof_base = buildProofWithSequence(10);
893 
894  ConflictingProofComparator comparator;
895  auto checkPreferred = [&](const ProofRef &candidate,
896  const ProofRef &reference, bool expectAccepted) {
897  BOOST_CHECK_EQUAL(comparator(candidate, reference), expectAccepted);
898  BOOST_CHECK_EQUAL(comparator(reference, candidate), !expectAccepted);
899  };
900 
901  // Same master key, lower sequence number
902  checkPreferred(buildProofWithSequence(9), proof_base, false);
903  // Same master key, higher sequence number
904  checkPreferred(buildProofWithSequence(11), proof_base, true);
905 
906  auto buildProofFromAmounts = [&](const CKey &master,
907  std::vector<Amount> &&amounts) {
908  ProofBuilder pb(0, 0, master);
909  BOOST_CHECK(
910  pb.addUTXO(conflictingOutpoint, amount, height, is_coinbase, key));
911  for (const Amount &v : amounts) {
912  auto outpoint = addCoin(v);
913  BOOST_CHECK(
914  pb.addUTXO(std::move(outpoint), v, height, is_coinbase, key));
915  }
916  return pb.build();
917  };
918 
919  auto proof_multiUtxo = buildProofFromAmounts(key, {10 * COIN, 10 * COIN});
920 
921  // Test for both the same master and a different one. The sequence number
922  // is the same for all these tests.
923  for (const CKey &k : {key, CKey::MakeCompressedKey()}) {
924  // Low amount
925  checkPreferred(buildProofFromAmounts(k, {10 * COIN, 5 * COIN}),
926  proof_multiUtxo, false);
927  // High amount
928  checkPreferred(buildProofFromAmounts(k, {10 * COIN, 15 * COIN}),
929  proof_multiUtxo, true);
930  // Same amount, low stake count
931  checkPreferred(buildProofFromAmounts(k, {20 * COIN}), proof_multiUtxo,
932  true);
933  // Same amount, high stake count
934  checkPreferred(
935  buildProofFromAmounts(k, {10 * COIN, 5 * COIN, 5 * COIN}),
936  proof_multiUtxo, false);
937  // Same amount, same stake count, selection is done on proof id
938  auto proofSimilar = buildProofFromAmounts(k, {10 * COIN, 10 * COIN});
939  checkPreferred(proofSimilar, proof_multiUtxo,
940  proofSimilar->getId() < proof_multiUtxo->getId());
941  }
942 }
943 
944 BOOST_AUTO_TEST_CASE(conflicting_orphans) {
946 
947  const CKey key = CKey::MakeCompressedKey();
948 
949  const Amount amount(10 * COIN);
950  const uint32_t height = 100;
951  const bool is_coinbase = false;
953 
954  auto buildProofWithSequence = [&](uint64_t sequence,
955  const std::vector<COutPoint> &outpoints) {
956  ProofBuilder pb(sequence, 0, key);
957 
958  for (const COutPoint &outpoint : outpoints) {
959  BOOST_CHECK(pb.addUTXO(outpoint, amount, height, is_coinbase, key));
960  }
961 
962  return pb.build();
963  };
964 
965  const COutPoint conflictingOutpoint(TxId(GetRandHash()), 0);
966  const COutPoint randomOutpoint1(TxId(GetRandHash()), 0);
967 
968  auto orphan10 = buildProofWithSequence(10, {conflictingOutpoint});
969  auto orphan20 =
970  buildProofWithSequence(20, {conflictingOutpoint, randomOutpoint1});
971 
972  BOOST_CHECK(!pm.registerProof(orphan10));
973  BOOST_CHECK(pm.isOrphan(orphan10->getId()));
974 
975  BOOST_CHECK(!pm.registerProof(orphan20));
976  BOOST_CHECK(pm.isOrphan(orphan20->getId()));
977  BOOST_CHECK(!pm.exists(orphan10->getId()));
978 
979  auto addCoin = [&](const COutPoint &outpoint) {
980  LOCK(cs_main);
982  coins.AddCoin(outpoint,
983  Coin(CTxOut(amount, script), height, is_coinbase), false);
984  };
985 
986  const COutPoint outpointToSend(TxId(GetRandHash()), 0);
987  // Add both randomOutpoint1 and outpointToSend to the UTXO set. The orphan20
988  // proof is still an orphan because the conflictingOutpoint is unknown.
989  addCoin(randomOutpoint1);
990  addCoin(outpointToSend);
991 
992  // Build and register proof valid proof that will conflict with the orphan
993  auto proof30 =
994  buildProofWithSequence(30, {randomOutpoint1, outpointToSend});
995  BOOST_CHECK(pm.registerProof(proof30));
996  BOOST_CHECK(pm.isBoundToPeer(proof30->getId()));
997 
998  // Spend the outpointToSend to orphan proof30
999  {
1000  LOCK(cs_main);
1002  coins.SpendCoin(outpointToSend);
1003  }
1004 
1005  // Check that a rescan will also select the preferred orphan, in this case
1006  // proof30 will replace orphan20.
1007  pm.updatedBlockTip();
1008 
1009  BOOST_CHECK(!pm.isBoundToPeer(proof30->getId()));
1010  BOOST_CHECK(pm.isOrphan(proof30->getId()));
1011  BOOST_CHECK(!pm.exists(orphan20->getId()));
1012 }
1013 
1014 BOOST_AUTO_TEST_CASE(preferred_conflicting_proof) {
1016 
1017  const CKey key = CKey::MakeCompressedKey();
1018 
1019  const Amount amount(10 * COIN);
1020  const uint32_t height = 100;
1021  const bool is_coinbase = false;
1023 
1024  const COutPoint conflictingOutpoint(TxId(GetRandHash()), 0);
1025  {
1026  LOCK(cs_main);
1028  coins.AddCoin(conflictingOutpoint,
1029  Coin(CTxOut(amount, script), height, is_coinbase), false);
1030  }
1031 
1032  auto buildProofWithSequence = [&](uint64_t sequence) {
1033  ProofBuilder pb(sequence, 0, key);
1034  BOOST_CHECK(
1035  pb.addUTXO(conflictingOutpoint, amount, height, is_coinbase, key));
1036 
1037  return pb.build();
1038  };
1039 
1040  auto proofSeq10 = buildProofWithSequence(10);
1041  auto proofSeq20 = buildProofWithSequence(20);
1042  auto proofSeq30 = buildProofWithSequence(30);
1043 
1044  BOOST_CHECK(pm.registerProof(proofSeq30));
1045  BOOST_CHECK(pm.isBoundToPeer(proofSeq30->getId()));
1046  BOOST_CHECK(!pm.isInConflictingPool(proofSeq30->getId()));
1047 
1048  // proofSeq10 is a worst candidate than proofSeq30, so it goes to the
1049  // conflicting pool.
1050  BOOST_CHECK(!pm.registerProof(proofSeq10));
1051  BOOST_CHECK(pm.isBoundToPeer(proofSeq30->getId()));
1052  BOOST_CHECK(!pm.isBoundToPeer(proofSeq10->getId()));
1053  BOOST_CHECK(pm.isInConflictingPool(proofSeq10->getId()));
1054 
1055  // proofSeq20 is a worst candidate than proofSeq30 but a better one than
1056  // proogSeq10, so it replaces it in the conflicting pool and proofSeq10 is
1057  // evicted.
1058  BOOST_CHECK(!pm.registerProof(proofSeq20));
1059  BOOST_CHECK(pm.isBoundToPeer(proofSeq30->getId()));
1060  BOOST_CHECK(!pm.isBoundToPeer(proofSeq20->getId()));
1061  BOOST_CHECK(pm.isInConflictingPool(proofSeq20->getId()));
1062  BOOST_CHECK(!pm.exists(proofSeq10->getId()));
1063 }
1064 
1065 BOOST_AUTO_TEST_CASE(update_next_conflict_time) {
1067 
1068  auto now = GetTime<std::chrono::seconds>();
1069  SetMockTime(now.count());
1070 
1071  // Updating the time of an unknown peer should fail
1072  for (size_t i = 0; i < 10; i++) {
1073  BOOST_CHECK(
1075  }
1076 
1078  PeerId peerid = TestPeerManager::registerAndGetPeerId(pm, proof);
1079 
1080  auto checkNextPossibleConflictTime = [&](std::chrono::seconds expected) {
1081  BOOST_CHECK(pm.forPeer(proof->getId(), [&](const Peer &p) {
1082  return p.nextPossibleConflictTime == expected;
1083  }));
1084  };
1085 
1086  checkNextPossibleConflictTime(now);
1087 
1088  // Move the time in the past is not possible
1090  peerid, now - std::chrono::seconds{1}));
1091  checkNextPossibleConflictTime(now);
1092 
1094  peerid, now + std::chrono::seconds{1}));
1095  checkNextPossibleConflictTime(now + std::chrono::seconds{1});
1096 }
1097 
1098 BOOST_AUTO_TEST_CASE(register_force_accept) {
1100 
1101  const CKey key = CKey::MakeCompressedKey();
1102 
1103  const Amount amount(10 * COIN);
1104  const uint32_t height = 100;
1105  const bool is_coinbase = false;
1107 
1108  const COutPoint conflictingOutpoint(TxId(GetRandHash()), 0);
1109  {
1110  LOCK(cs_main);
1112  coins.AddCoin(conflictingOutpoint,
1113  Coin(CTxOut(amount, script), height, is_coinbase), false);
1114  }
1115 
1116  auto buildProofWithSequence = [&](uint64_t sequence) {
1117  ProofBuilder pb(sequence, 0, key);
1118  BOOST_CHECK(
1119  pb.addUTXO(conflictingOutpoint, amount, height, is_coinbase, key));
1120 
1121  return pb.build();
1122  };
1123 
1124  auto proofSeq10 = buildProofWithSequence(10);
1125  auto proofSeq20 = buildProofWithSequence(20);
1126  auto proofSeq30 = buildProofWithSequence(30);
1127 
1128  BOOST_CHECK(pm.registerProof(proofSeq30));
1129  BOOST_CHECK(pm.isBoundToPeer(proofSeq30->getId()));
1130  BOOST_CHECK(!pm.isInConflictingPool(proofSeq30->getId()));
1131 
1132  // proofSeq20 is a worst candidate than proofSeq30, so it goes to the
1133  // conflicting pool.
1134  BOOST_CHECK(!pm.registerProof(proofSeq20));
1135  BOOST_CHECK(pm.isBoundToPeer(proofSeq30->getId()));
1136  BOOST_CHECK(pm.isInConflictingPool(proofSeq20->getId()));
1137 
1138  // We can force the acceptance of proofSeq20
1139  using RegistrationMode = avalanche::PeerManager::RegistrationMode;
1140  BOOST_CHECK(pm.registerProof(proofSeq20, RegistrationMode::FORCE_ACCEPT));
1141  BOOST_CHECK(pm.isBoundToPeer(proofSeq20->getId()));
1142  BOOST_CHECK(pm.isInConflictingPool(proofSeq30->getId()));
1143 
1144  // We can also force the acceptance of a proof which is not already in the
1145  // conflicting pool.
1146  BOOST_CHECK(!pm.registerProof(proofSeq10));
1147  BOOST_CHECK(!pm.exists(proofSeq10->getId()));
1148 
1149  BOOST_CHECK(pm.registerProof(proofSeq10, RegistrationMode::FORCE_ACCEPT));
1150  BOOST_CHECK(pm.isBoundToPeer(proofSeq10->getId()));
1151  BOOST_CHECK(!pm.exists(proofSeq20->getId()));
1152  BOOST_CHECK(pm.isInConflictingPool(proofSeq30->getId()));
1153 
1154  // Attempting to register again fails, and has no impact on the pools
1155  for (size_t i = 0; i < 10; i++) {
1156  BOOST_CHECK(!pm.registerProof(proofSeq10));
1157  BOOST_CHECK(
1158  !pm.registerProof(proofSeq10, RegistrationMode::FORCE_ACCEPT));
1159 
1160  BOOST_CHECK(pm.isBoundToPeer(proofSeq10->getId()));
1161  BOOST_CHECK(!pm.exists(proofSeq20->getId()));
1162  BOOST_CHECK(pm.isInConflictingPool(proofSeq30->getId()));
1163  }
1164 
1165  // Revert between proofSeq10 and proofSeq30 a few times
1166  for (size_t i = 0; i < 10; i++) {
1167  BOOST_CHECK(
1168  pm.registerProof(proofSeq30, RegistrationMode::FORCE_ACCEPT));
1169 
1170  BOOST_CHECK(pm.isBoundToPeer(proofSeq30->getId()));
1171  BOOST_CHECK(pm.isInConflictingPool(proofSeq10->getId()));
1172 
1173  BOOST_CHECK(
1174  pm.registerProof(proofSeq10, RegistrationMode::FORCE_ACCEPT));
1175 
1176  BOOST_CHECK(pm.isBoundToPeer(proofSeq10->getId()));
1177  BOOST_CHECK(pm.isInConflictingPool(proofSeq30->getId()));
1178  }
1179 }
1180 
avalanche::PeerManager::verify
bool verify() const
Perform consistency check on internal data structures.
Definition: peermanager.cpp:451
avalanche::Slot
Definition: peermanager.h:37
avalanche::ProofBuilder
Definition: proofbuilder.h:17
avalanche::PeerManager::forNode
bool forNode(NodeId nodeid, Callable &&func) const
Definition: peermanager.h:183
avalanche::MIN_VALID_PROOF_SCORE
constexpr uint32_t MIN_VALID_PROOF_SCORE
Definition: util.h:16
avalanche::PeerManager::updateNextRequestTime
bool updateNextRequestTime(NodeId nodeid, TimePoint timeout)
Definition: peermanager.cpp:136
avalanche::PeerManager::compact
uint64_t compact()
Trigger maintenance of internal data structures.
Definition: peermanager.cpp:419
avalanche
Definition: avalanche.h:11
CCoinsViewCache::AddCoin
void AddCoin(const COutPoint &outpoint, Coin coin, bool possible_overwrite)
Add a coin.
Definition: coins.cpp:103
GetScriptForDestination
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:243
avalanche::PeerManager::addNode
bool addNode(NodeId nodeid, const ProofId &proofid)
Node API.
Definition: peermanager.cpp:17
bilingual_str
Bilingual messages:
Definition: translation.h:17
avalanche::PeerManager::peers
PeerSet peers
Definition: peermanager.h:127
delegationbuilder.h
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(select_peer_linear)
Definition: peermanager_tests.cpp:49
avalanche::ProofId
Definition: proofid.h:17
avalanche::TestProofBuilder::buildDuplicatedStakes
static ProofRef buildDuplicatedStakes(ProofBuilder &pb)
Definition: util.cpp:104
ChainstateActive
CChainState & ChainstateActive()
Please prefer the identical ChainstateManager::ActiveChainstate.
Definition: validation.cpp:80
BOOST_FIXTURE_TEST_SUITE
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
avalanche::Node::peerid
PeerId peerid
Definition: node.h:23
avalanche::buildRandomProof
ProofRef buildRandomProof(uint32_t score, const CKey &masterKey)
Definition: util.cpp:20
avalanche::Peer
Definition: peermanager.h:69
COIN
static constexpr Amount COIN
Definition: amount.h:154
avalanche::ProofBuilder::addUTXO
bool addUTXO(COutPoint utxo, Amount amount, uint32_t height, bool is_coinbase, CKey key)
Definition: proofbuilder.cpp:23
proofbuilder.h
avalanche::ProofBuilder::build
ProofRef build()
Definition: proofbuilder.cpp:36
avalanche::PeerManager::isOrphan
bool isOrphan(const ProofId &proofid) const
Definition: peermanager.cpp:362
TimePoint
std::chrono::time_point< std::chrono::steady_clock > TimePoint
Definition: node.h:17
avalanche::PeerManager::updatedBlockTip
void updatedBlockTip()
Update the peer set when a new block is connected.
Definition: peermanager.cpp:288
GetRandInt
int GetRandInt(int nMax) noexcept
Definition: random.cpp:654
avalanche::PeerManager::exists
bool exists(const ProofId &proofid) const
Definition: peermanager.h:222
avalanche::selectPeerImpl
PeerId selectPeerImpl(const std::vector< Slot > &slots, const uint64_t slot, const uint64_t max)
Internal methods that are exposed for testing purposes.
Definition: peermanager.cpp:547
CCoinsViewCache::SpendCoin
bool SpendCoin(const COutPoint &outpoint, Coin *moveto=nullptr)
Spend a coin.
Definition: coins.cpp:160
CTxOut
An output of a transaction.
Definition: transaction.h:130
cs_main
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:103
Coin
A UTXO entry.
Definition: coins.h:27
avalanche::PeerManager::removePeer
bool removePeer(const PeerId peerid)
Remove an existing peer.
Definition: peermanager.cpp:370
avalanche::Node
Definition: node.h:21
SetMockTime
void SetMockTime(int64_t nMockTimeIn)
For testing.
Definition: time.cpp:50
avalanche::PeerManager
Definition: peermanager.h:109
GetRandHash
uint256 GetRandHash() noexcept
Definition: random.cpp:658
avalanche::PeerManager::RegistrationMode
RegistrationMode
Registration mode.
Definition: peermanager.h:215
standard.h
avalanche::Peer::proof
ProofRef proof
Definition: peermanager.h:74
avalanche::PeerManager::removeNode
bool removeNode(NodeId nodeid)
Definition: peermanager.cpp:79
TxId
A TxId is the identifier of a transaction.
Definition: txid.h:14
CKey::GetPubKey
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:210
Amount
Definition: amount.h:19
CScript
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:430
NO_NODE
static constexpr NodeId NO_NODE
Special NodeId that represent no node.
Definition: nodeid.h:15
avalanche::Proof
Definition: proof.h:102
avalanche::PeerManager::getProof
ProofRef getProof(const ProofId &proofid) const
Definition: peermanager.cpp:338
avalanche::Proof::FromHex
static bool FromHex(Proof &proof, const std::string &hexProof, bilingual_str &errorOut)
Definition: proof.cpp:62
avalanche::ConflictingProofComparator
Compare conflicting proofs.
Definition: proofcomparator.h:35
avalanche::PeerManager::updateNextPossibleConflictTime
bool updateNextPossibleConflictTime(PeerId peerid, const std::chrono::seconds &nextTime)
Proof and Peer related API.
Definition: peermanager.cpp:150
util.h
PKHash
Definition: standard.h:106
peermanager.h
avalanche::PeerManager::selectPeer
PeerId selectPeer() const
Randomly select a peer to poll.
Definition: peermanager.cpp:403
avalanche::PeerManager::getSlotCount
uint64_t getSlotCount() const
Definition: peermanager.h:277
avalanche::PeerManager::forPeer
bool forPeer(const ProofId &proofid, Callable &&func) const
Definition: peermanager.h:227
CKey
An encapsulated secp256k1 private key.
Definition: key.h:28
CCoinsViewCache
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:231
translation.h
LOCK
#define LOCK(cs)
Definition: sync.h:241
CKey::MakeCompressedKey
static CKey MakeCompressedKey()
Produce a valid compressed key.
Definition: key.cpp:466
avalanche::PeerManager::isBoundToPeer
bool isBoundToPeer(const ProofId &proofid) const
Definition: peermanager.cpp:357
avalanche::PeerManager::registerProof
bool registerProof(const ProofRef &proof, RegistrationMode mode=RegistrationMode::DEFAULT)
Definition: peermanager.cpp:167
proofcomparator.h
NodeId
int64_t NodeId
Definition: nodeid.h:10
NO_PEER
static constexpr PeerId NO_PEER
Definition: node.h:15
COutPoint
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:22
error
bool error(const char *fmt, const Args &... args)
Definition: system.h:48
avalanche::ProofRef
std::shared_ptr< const Proof > ProofRef
Definition: proof.h:163
addNodeWithScore
static void addNodeWithScore(avalanche::PeerManager &pm, NodeId node, uint32_t score)
Definition: peermanager_tests.cpp:186
avalanche::PeerManager::isInConflictingPool
bool isInConflictingPool(const ProofId &proofid) const
Definition: peermanager.cpp:366
addCoin
static void addCoin(const Amount nValue, const CWallet &wallet, std::vector< std::unique_ptr< CWalletTx >> &wtxs)
Definition: coin_selection.cpp:15
CChainState::CoinsTip
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Definition: validation.h:837
avalanche::PeerManager::pendingNodes
PendingNodeSet pendingNodes
Definition: peermanager.h:159
BOOST_CHECK
#define BOOST_CHECK(expr)
Definition: object.cpp:17
PeerId
uint32_t PeerId
Definition: node.h:14
avalanche::PeerManager::getFragmentation
uint64_t getFragmentation() const
Definition: peermanager.h:278
BOOST_AUTO_TEST_SUITE_END
#define BOOST_AUTO_TEST_SUITE_END()
Definition: object.cpp:16
BOOST_CHECK_EQUAL
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
avalanche::PeerManager::selectNode
NodeId selectNode()
Definition: peermanager.cpp:265
avalanche::PeerManager::forEachPeer
void forEachPeer(Callable &&func) const
Definition: peermanager.h:233