Bitcoin ABC  0.24.10
P2P Digital Currency
proofpool_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2021 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 
5 #include <avalanche/proofpool.h>
6 
8 #include <key.h>
10 #include <primitives/txid.h>
11 #include <random.h>
12 
13 #include <avalanche/test/util.h>
14 #include <test/util/setup_common.h>
15 
16 #include <boost/test/unit_test.hpp>
17 
18 using namespace avalanche;
19 
20 BOOST_FIXTURE_TEST_SUITE(proofpool_tests, TestingSetup)
21 
22 BOOST_AUTO_TEST_CASE(add_remove_proof_no_conflict) {
23  ProofPool testPool;
24 
25  std::vector<ProofRef> proofs;
26  for (size_t i = 0; i < 10; i++) {
27  // Add a bunch of random proofs
30  ProofPool::AddProofStatus::SUCCEED);
31 
32  // Trying to add them again will return a duplicated status
33  for (size_t j = 0; j < 10; j++) {
35  ProofPool::AddProofStatus::DUPLICATED);
36  }
37  proofs.push_back(std::move(proof));
38  }
39 
40  const CKey key = CKey::MakeCompressedKey();
41  const COutPoint conflictingOutpoint{TxId(GetRandHash()), 0};
42 
43  auto buildProofWithSequence = [&](uint64_t sequence) {
44  ProofBuilder pb(sequence, 0, key);
46  pb.addUTXO(conflictingOutpoint, 10 * COIN, 123456, false, key));
47  return pb.build();
48  };
49 
50  auto proof_seq10 = buildProofWithSequence(10);
51  BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof_seq10),
52  ProofPool::AddProofStatus::SUCCEED);
53  proofs.push_back(std::move(proof_seq10));
54 
55  auto proof_seq20 = buildProofWithSequence(20);
56  BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof_seq20),
57  ProofPool::AddProofStatus::REJECTED);
58 
59  // Removing proofs which are not in the pool will fail
60  for (size_t i = 0; i < 10; i++) {
62  }
63 
64  for (auto proof : proofs) {
65  BOOST_CHECK(testPool.removeProof(proof->getId()));
66  }
67  BOOST_CHECK_EQUAL(testPool.size(), 0);
68 }
69 
71  ProofPool testPool;
73 
74  testPool.rescan(pm);
75  BOOST_CHECK_EQUAL(testPool.size(), 0);
76 
77  // No peer should be created
78  bool hasPeer = false;
79  pm.forEachPeer([&](const Peer &p) { hasPeer = true; });
80  BOOST_CHECK(!hasPeer);
81 
82  std::set<ProofRef> poolProofs;
83  for (size_t i = 0; i < 10; i++) {
86  ProofPool::AddProofStatus::SUCCEED);
87  poolProofs.insert(std::move(proof));
88  }
89 
90  testPool.rescan(pm);
91 
92  // All the proofs should be registered as peer
93  std::set<ProofRef> pmProofs;
94  pm.forEachPeer([&](const Peer &p) { pmProofs.insert(p.proof); });
95  BOOST_CHECK_EQUAL_COLLECTIONS(poolProofs.begin(), poolProofs.end(),
96  pmProofs.begin(), pmProofs.end());
97  BOOST_CHECK_EQUAL(testPool.size(), 0);
98 }
99 
100 BOOST_AUTO_TEST_CASE(proof_override) {
101  ProofPool testPool;
102 
103  const CKey key = CKey::MakeCompressedKey();
104 
105  auto buildProofWithSequenceAndOutpoints =
106  [&](uint64_t sequence, const std::vector<COutPoint> &outpoints) {
107  ProofBuilder pb(sequence, 0, key);
108  for (const COutPoint &outpoint : outpoints) {
109  BOOST_CHECK(
110  pb.addUTXO(outpoint, 10 * COIN, 123456, false, key));
111  }
112  return pb.build();
113  };
114 
115  const COutPoint outpoint1{TxId(GetRandHash()), 0};
116  const COutPoint outpoint2{TxId(GetRandHash()), 0};
117  const COutPoint outpoint3{TxId(GetRandHash()), 0};
118 
119  // Build and register 3 proofs with a single utxo
120  auto proof_seq10 = buildProofWithSequenceAndOutpoints(10, {outpoint1});
121  auto proof_seq20 = buildProofWithSequenceAndOutpoints(20, {outpoint2});
122  auto proof_seq30 = buildProofWithSequenceAndOutpoints(30, {outpoint3});
123 
124  BOOST_CHECK_EQUAL(testPool.addProofIfPreferred(proof_seq10),
125  ProofPool::AddProofStatus::SUCCEED);
126  BOOST_CHECK(testPool.getProof(proof_seq10->getId()));
127 
128  BOOST_CHECK_EQUAL(testPool.addProofIfPreferred(proof_seq20),
129  ProofPool::AddProofStatus::SUCCEED);
130  BOOST_CHECK(testPool.getProof(proof_seq20->getId()));
131 
132  BOOST_CHECK_EQUAL(testPool.addProofIfPreferred(proof_seq30),
133  ProofPool::AddProofStatus::SUCCEED);
134  BOOST_CHECK(testPool.getProof(proof_seq30->getId()));
135 
136  // Build a proof that conflicts with the above 3, but has a higher sequence
137  auto proof_seq123 = buildProofWithSequenceAndOutpoints(
138  123, {outpoint1, outpoint2, outpoint3});
139  ProofPool::ConflictingProofSet expectedConflictingProofs = {
140  proof_seq10, proof_seq20, proof_seq30};
141 
142  // The no conflict call should reject our candidate and not alter the 3
143  // conflicting proofs
144  ProofPool::ConflictingProofSet conflictingProofs;
146  testPool.addProofIfNoConflict(proof_seq123, conflictingProofs),
147  ProofPool::AddProofStatus::REJECTED);
148  BOOST_CHECK_EQUAL_COLLECTIONS(
149  conflictingProofs.begin(), conflictingProofs.end(),
150  expectedConflictingProofs.begin(), expectedConflictingProofs.end());
151  BOOST_CHECK(!testPool.getProof(proof_seq123->getId()));
152  BOOST_CHECK(testPool.getProof(proof_seq10->getId()));
153  BOOST_CHECK(testPool.getProof(proof_seq20->getId()));
154  BOOST_CHECK(testPool.getProof(proof_seq30->getId()));
155 
156  // The conflict handling call will override the 3 conflicting proofs
157  conflictingProofs.clear();
159  testPool.addProofIfPreferred(proof_seq123, conflictingProofs),
160  ProofPool::AddProofStatus::SUCCEED);
161  BOOST_CHECK_EQUAL_COLLECTIONS(
162  conflictingProofs.begin(), conflictingProofs.end(),
163  expectedConflictingProofs.begin(), expectedConflictingProofs.end());
164  BOOST_CHECK(testPool.getProof(proof_seq123->getId()));
165  BOOST_CHECK(!testPool.getProof(proof_seq10->getId()));
166  BOOST_CHECK(!testPool.getProof(proof_seq20->getId()));
167  BOOST_CHECK(!testPool.getProof(proof_seq30->getId()));
168 }
169 
170 BOOST_AUTO_TEST_CASE(conflicting_proofs_set) {
171  ProofPool testPool;
172 
173  const CKey key = CKey::MakeCompressedKey();
174  const COutPoint conflictingOutpoint{TxId(GetRandHash()), 0};
175 
176  auto buildProofWithSequence = [&](uint64_t sequence) {
177  ProofBuilder pb(sequence, 0, key);
178  BOOST_CHECK(
179  pb.addUTXO(conflictingOutpoint, 10 * COIN, 123456, false, key));
180  return pb.build();
181  };
182 
183  auto proofSeq10 = buildProofWithSequence(10);
184  auto proofSeq20 = buildProofWithSequence(20);
185  auto proofSeq30 = buildProofWithSequence(30);
186 
187  BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proofSeq20),
188  ProofPool::AddProofStatus::SUCCEED);
189 
190  auto getRandomConflictingProofSet = []() {
195  };
196  };
197 
198  auto checkConflictingProofs =
199  [&](const ProofPool::ConflictingProofSet &conflictingProofs,
200  const ProofPool::ConflictingProofSet &expectedConflictingProofs) {
201  BOOST_CHECK_EQUAL_COLLECTIONS(conflictingProofs.begin(),
202  conflictingProofs.end(),
203  expectedConflictingProofs.begin(),
204  expectedConflictingProofs.end());
205  };
206 
207  {
208  // Without override, duplicated proof
209  auto conflictingProofs = getRandomConflictingProofSet();
211  testPool.addProofIfNoConflict(proofSeq20, conflictingProofs),
212  ProofPool::AddProofStatus::DUPLICATED);
213  checkConflictingProofs(conflictingProofs, {});
214  }
215 
216  {
217  // With override, duplicated proof
218  auto conflictingProofs = getRandomConflictingProofSet();
220  testPool.addProofIfPreferred(proofSeq20, conflictingProofs),
221  ProofPool::AddProofStatus::DUPLICATED);
222  checkConflictingProofs(conflictingProofs, {});
223  }
224 
225  {
226  // Without override, worst proof
227  auto conflictingProofs = getRandomConflictingProofSet();
229  testPool.addProofIfNoConflict(proofSeq10, conflictingProofs),
230  ProofPool::AddProofStatus::REJECTED);
231  checkConflictingProofs(conflictingProofs, {proofSeq20});
232  }
233 
234  {
235  // Without override, better proof
236  auto conflictingProofs = getRandomConflictingProofSet();
238  testPool.addProofIfNoConflict(proofSeq30, conflictingProofs),
239  ProofPool::AddProofStatus::REJECTED);
240  checkConflictingProofs(conflictingProofs, {proofSeq20});
241  }
242 
243  {
244  // With override, worst proof
245  auto conflictingProofs = getRandomConflictingProofSet();
247  testPool.addProofIfPreferred(proofSeq10, conflictingProofs),
248  ProofPool::AddProofStatus::REJECTED);
249  checkConflictingProofs(conflictingProofs, {proofSeq20});
250  }
251 
252  {
253  // With override, better proof
254  auto conflictingProofs = getRandomConflictingProofSet();
256  testPool.addProofIfPreferred(proofSeq30, conflictingProofs),
257  ProofPool::AddProofStatus::SUCCEED);
258  checkConflictingProofs(conflictingProofs, {proofSeq20});
259  }
260 }
261 
263  ProofPool testPool;
264 
265  for (size_t i = 0; i < 10; i++) {
266  BOOST_CHECK(!testPool.getProof(ProofId(GetRandHash())));
267  }
268 
269  for (size_t i = 0; i < 10; i++) {
271  BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof),
272  ProofPool::AddProofStatus::SUCCEED);
273 
274  auto retrievedProof = testPool.getProof(proof->getId());
275  BOOST_CHECK_NE(retrievedProof, nullptr);
276  BOOST_CHECK_EQUAL(retrievedProof->getId(), proof->getId());
277  }
278 }
279 
avalanche::ProofBuilder
Definition: proofbuilder.h:17
avalanche::MIN_VALID_PROOF_SCORE
constexpr uint32_t MIN_VALID_PROOF_SCORE
Definition: util.h:16
avalanche
Definition: avalanche.h:11
transaction.h
avalanche::ProofId
Definition: proofid.h:17
avalanche::ProofPool::ConflictingProofSet
std::set< ProofRef, ConflictingProofComparator > ConflictingProofSet
Definition: proofpool.h:74
avalanche::ProofPool::size
size_t size() const
Definition: proofpool.h:106
BOOST_FIXTURE_TEST_SUITE
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
proofpool.h
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
avalanche::ProofPool::removeProof
bool removeProof(ProofId proofid)
Definition: proofpool.cpp:77
avalanche::ProofBuilder::build
ProofRef build()
Definition: proofbuilder.cpp:36
random.h
avalanche::ProofPool::addProofIfPreferred
AddProofStatus addProofIfPreferred(const ProofRef &proof, ConflictingProofSet &conflictingProofs)
Attempt to add a proof to the pool.
Definition: proofpool.cpp:53
avalanche::PeerManager
Definition: peermanager.h:109
GetRandHash
uint256 GetRandHash() noexcept
Definition: random.cpp:658
avalanche::Peer::proof
ProofRef proof
Definition: peermanager.h:74
TxId
A TxId is the identifier of a transaction.
Definition: txid.h:14
avalanche::ProofPool::rescan
void rescan(PeerManager &peerManager)
Definition: proofpool.cpp:82
util.h
peermanager.h
key.h
avalanche::ProofPool
Map a proof to each utxo.
Definition: proofpool.h:51
CKey
An encapsulated secp256k1 private key.
Definition: key.h:28
avalanche::ProofPool::addProofIfNoConflict
AddProofStatus addProofIfNoConflict(const ProofRef &proof, ConflictingProofSet &conflictingProofs)
Attempt to add a proof to the pool, and fail if there is a conflict on any UTXO.
Definition: proofpool.cpp:13
CKey::MakeCompressedKey
static CKey MakeCompressedKey()
Produce a valid compressed key.
Definition: key.cpp:466
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(add_remove_proof_no_conflict)
Definition: proofpool_tests.cpp:22
avalanche::ProofPool::getProof
ProofRef getProof(const ProofId &proofid) const
Definition: proofpool.cpp:91
COutPoint
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:22
txid.h
BOOST_CHECK
#define BOOST_CHECK(expr)
Definition: object.cpp:17
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::forEachPeer
void forEachPeer(Callable &&func) const
Definition: peermanager.h:233