Bitcoin ABC  0.26.3
P2P Digital Currency
compactproofs_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2022 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 
6 
7 #include <avalanche/test/util.h>
8 #include <streams.h>
9 
10 #include <test/util/setup_common.h>
11 
12 #include <boost/test/unit_test.hpp>
13 
14 #include <algorithm>
15 
16 namespace avalanche {
17 namespace {
18  struct TestCompactProofs {
19  static std::vector<uint64_t> getShortProofIds(const CompactProofs &cp) {
20  return cp.shortproofids;
21  }
22 
23  static std::vector<PrefilledProof>
24  getPrefilledProofs(const CompactProofs &cp) {
25  return cp.prefilledProofs;
26  }
27 
28  static void addPrefilledProof(CompactProofs &cp, uint32_t index,
29  const ProofRef &proof) {
30  PrefilledProof pp{index, proof};
31  cp.prefilledProofs.push_back(std::move(pp));
32  }
33  };
34 } // namespace
35 } // namespace avalanche
36 
37 using namespace avalanche;
38 
39 // TestingSetup is required for buildRandomProof()
40 BOOST_FIXTURE_TEST_SUITE(compactproofs_tests, TestingSetup)
41 
42 BOOST_AUTO_TEST_CASE(compactproofs_roundtrip) {
43  {
44  CompactProofs cpw;
45  BOOST_CHECK_EQUAL(cpw.size(), 0);
46 
48  BOOST_CHECK_NO_THROW(ss << cpw);
49 
50  CompactProofs cpr;
51  BOOST_CHECK_NO_THROW(ss >> cpr);
52 
53  BOOST_CHECK_EQUAL(cpr.size(), 0);
54  BOOST_CHECK_EQUAL(cpr.getKeys().first, cpw.getKeys().first);
55  BOOST_CHECK_EQUAL(cpr.getKeys().second, cpw.getKeys().second);
56  }
57 
58  Chainstate &active_chainstate = Assert(m_node.chainman)->ActiveChainstate();
59 
60  {
61  // Check index boundaries
62  CompactProofs cp;
63 
64  TestCompactProofs::addPrefilledProof(
65  cp, 0, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
66  TestCompactProofs::addPrefilledProof(
67  cp, std::numeric_limits<uint32_t>::max(),
68  buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
69 
71  BOOST_CHECK_NO_THROW(ss << cp);
72 
73  auto prefilledProofs = TestCompactProofs::getPrefilledProofs(cp);
74  BOOST_CHECK_EQUAL(prefilledProofs.size(), 2);
75 
76  BOOST_CHECK_EQUAL(prefilledProofs[0].index, 0);
77  BOOST_CHECK_EQUAL(prefilledProofs[1].index,
78  std::numeric_limits<uint32_t>::max());
79  }
80 
81  auto checkCompactProof = [&](size_t numofProof,
82  size_t numofPrefilledProof) {
84  for (size_t i = 0; i < numofProof; i++) {
85  BOOST_CHECK(proofs.insert(
86  buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE)));
87  }
88 
89  CompactProofs cpw(proofs);
90  BOOST_CHECK_EQUAL(cpw.size(), numofProof);
91 
92  uint32_t prefilledProofIndex = 0;
93  for (size_t i = 0; i < numofPrefilledProof; i++) {
94  TestCompactProofs::addPrefilledProof(
95  cpw, prefilledProofIndex++,
96  buildRandomProof(active_chainstate, GetRand<uint32_t>()));
97  }
98  auto prefilledProofs = TestCompactProofs::getPrefilledProofs(cpw);
99  BOOST_CHECK_EQUAL(prefilledProofs.size(), numofPrefilledProof);
100 
102  BOOST_CHECK_NO_THROW(ss << cpw);
103 
104  CompactProofs cpr;
105  BOOST_CHECK_NO_THROW(ss >> cpr);
106 
107  BOOST_CHECK_EQUAL(cpr.size(), numofProof + numofPrefilledProof);
108  BOOST_CHECK_EQUAL(cpr.getKeys().first, cpw.getKeys().first);
109  BOOST_CHECK_EQUAL(cpr.getKeys().second, cpw.getKeys().second);
110 
111  auto comparePrefilledProof = [](const PrefilledProof &lhs,
112  const PrefilledProof &rhs) {
113  return lhs.index == rhs.index &&
114  lhs.proof->getId() == rhs.proof->getId() &&
115  lhs.proof->getSignature() == rhs.proof->getSignature();
116  };
117 
118  auto prefilledProofsCpr = TestCompactProofs::getPrefilledProofs(cpr);
119  BOOST_CHECK(std::equal(prefilledProofsCpr.begin(),
120  prefilledProofsCpr.end(),
121  prefilledProofs.begin(), comparePrefilledProof));
122 
123  auto shortIds = TestCompactProofs::getShortProofIds(cpr);
124  size_t index = 0;
125  proofs.forEachLeaf([&](auto pLeaf) {
126  const ProofId &proofid = pLeaf->getId();
127  BOOST_CHECK_EQUAL(cpr.getShortID(proofid), cpw.getShortID(proofid));
128  BOOST_CHECK_EQUAL(cpr.getShortID(proofid), shortIds[index]);
129  ++index;
130 
131  return true;
132  });
133  };
134 
135  // No proof at all
136  checkCompactProof(0, 0);
137 
138  // No prefilled proofs
139  checkCompactProof(1000, 0);
140 
141  // Only prefilled proofs
142  checkCompactProof(0, 1000);
143 
144  // Mixed case
145  checkCompactProof(1000, 1000);
146 }
147 
148 BOOST_AUTO_TEST_CASE(compactproofs_overflow) {
149  Chainstate &active_chainstate = Assert(m_node.chainman)->ActiveChainstate();
150  {
151  CompactProofs cp;
152 
153  TestCompactProofs::addPrefilledProof(
154  cp, 0, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
155  TestCompactProofs::addPrefilledProof(
156  cp, 0, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
157 
159  BOOST_CHECK_EXCEPTION(ss << cp, std::ios_base::failure,
160  HasReason("differential value overflow"));
161  }
162 
163  {
164  CompactProofs cp;
165 
166  TestCompactProofs::addPrefilledProof(
167  cp, 1, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
168  TestCompactProofs::addPrefilledProof(
169  cp, 0, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
170 
172  BOOST_CHECK_EXCEPTION(ss << cp, std::ios_base::failure,
173  HasReason("differential value overflow"));
174  }
175 
176  {
177  CompactProofs cp;
178 
179  TestCompactProofs::addPrefilledProof(
180  cp, std::numeric_limits<uint32_t>::max(),
181  buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
182  TestCompactProofs::addPrefilledProof(
183  cp, 0, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
184 
186  BOOST_CHECK_EXCEPTION(ss << cp, std::ios_base::failure,
187  HasReason("differential value overflow"));
188  }
189 
190  {
192  // shortproofidk0, shortproofidk1
193  ss << uint64_t(0) << uint64_t(0);
194  // shortproofids.size()
195  WriteCompactSize(ss, MAX_SIZE + 1);
196 
197  CompactProofs cp;
198  BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
199  HasReason("ReadCompactSize(): size too large"));
200  }
201 
202  {
204  // shortproofidk0, shortproofidk1
205  ss << uint64_t(0) << uint64_t(0);
206  // shortproofids.size()
207  WriteCompactSize(ss, 0);
208  // prefilledProofs.size()
209  WriteCompactSize(ss, MAX_SIZE + 1);
210 
211  CompactProofs cp;
212  BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
213  HasReason("ReadCompactSize(): size too large"));
214  }
215 
216  {
218  // shortproofidk0, shortproofidk1
219  ss << uint64_t(0) << uint64_t(0);
220  // shortproofids.size()
221  WriteCompactSize(ss, 0);
222  // prefilledProofs.size()
223  WriteCompactSize(ss, 1);
224  // prefilledProofs[0].index
225  WriteCompactSize(ss, MAX_SIZE + 1);
226  // prefilledProofs[0].proof
227  ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
228 
229  CompactProofs cp;
230  BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
231  HasReason("ReadCompactSize(): size too large"));
232  }
233 
234  // Compute the number of MAX_SIZE increment we need to cause an overflow
235  const uint64_t overflow =
236  uint64_t(std::numeric_limits<uint32_t>::max()) + 1;
237  // Due to differential encoding, a value of MAX_SIZE bumps the index by
238  // MAX_SIZE + 1
239  BOOST_CHECK_GE(overflow, MAX_SIZE + 1);
240  const uint64_t overflowIter = overflow / (MAX_SIZE + 1);
241 
242  // Make sure the iteration fits in an uint32_t and is <= MAX_SIZE
243  BOOST_CHECK_LE(overflowIter, std::numeric_limits<uint32_t>::max());
244  BOOST_CHECK_LE(overflowIter, MAX_SIZE);
245  uint32_t remainder = uint32_t(overflow - ((MAX_SIZE + 1) * overflowIter));
246 
247  {
249  // shortproofidk0, shortproofidk1
250  ss << uint64_t(0) << uint64_t(0);
251  // shortproofids.size()
252  WriteCompactSize(ss, 0);
253  // prefilledProofs.size()
254  WriteCompactSize(ss, overflowIter + 1);
255  for (uint32_t i = 0; i < overflowIter; i++) {
256  // prefilledProofs[i].index
258  // prefilledProofs[i].proof
259  ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
260  }
261  // This is the prefilled proof causing the overflow
262  WriteCompactSize(ss, remainder);
263  ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
264 
265  CompactProofs cp;
266  BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
267  HasReason("differential value overflow"));
268  }
269 
270  {
272  // shortproofidk0, shortproofidk1
273  ss << uint64_t(0) << uint64_t(0);
274  // shortproofids.size()
275  WriteCompactSize(ss, 1);
276  // shortproofids[0]
278  // prefilledProofs.size()
279  WriteCompactSize(ss, overflowIter + 1);
280  for (uint32_t i = 0; i < overflowIter; i++) {
281  // prefilledProofs[i].index
283  // prefilledProofs[i].proof
284  ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
285  }
286  // This prefilled proof isn't enough to cause the overflow alone, but it
287  // overflows due to the extra shortid.
288  WriteCompactSize(ss, remainder - 1);
289  ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
290 
291  CompactProofs cp;
292  // ss >> cp;
293  BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
294  HasReason("indexes overflowed 32 bits"));
295  }
296 
297  {
299  // shortproofidk0, shortproofidk1
300  ss << uint64_t(0) << uint64_t(0);
301  // shortproofids.size()
302  WriteCompactSize(ss, 0);
303  // prefilledProofs.size()
304  WriteCompactSize(ss, 2);
305  // prefilledProofs[0].index
306  WriteCompactSize(ss, 0);
307  // prefilledProofs[0].proof
308  ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
309  // prefilledProofs[1].index = 1 is differentially encoded, which means
310  // it has an absolute index of 2. This leaves no proof at index 1.
311  WriteCompactSize(ss, 1);
312  // prefilledProofs[1].proof
313  ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
314 
315  CompactProofs cp;
316  BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
317  HasReason("non contiguous indexes"));
318  }
319 }
320 
321 BOOST_AUTO_TEST_SUITE_END()
#define Assert(val)
Identity function.
Definition: check.h:84
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:695
std::vector< PrefilledProof > prefilledProofs
Definition: compactproofs.h:58
uint64_t getShortID(const ProofId &proofid) const
std::pair< uint64_t, uint64_t > getKeys() const
Definition: compactproofs.h:73
std::vector< uint64_t > shortproofids
Definition: compactproofs.h:57
const ProofId & getId() const
Definition: proof.h:169
const SchnorrSig & getSignature() const
Definition: proof.h:167
BOOST_AUTO_TEST_CASE(compactproofs_roundtrip)
ProofRef buildRandomProof(Chainstate &active_chainstate, uint32_t score, int height, const CKey &masterKey)
Definition: util.cpp:20
constexpr uint32_t MIN_VALID_PROOF_SCORE
Definition: util.h:17
NodeContext & m_node
Definition: interfaces.cpp:785
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK_NO_THROW(stmt)
Definition: object.cpp:29
#define BOOST_CHECK(expr)
Definition: object.cpp:17
static constexpr uint64_t MAX_SIZE
The maximum size of a serialized object in bytes or number of elements (for eg vectors) when the size...
Definition: serialize.h:31
@ SER_DISK
Definition: serialize.h:153
@ SER_NETWORK
Definition: serialize.h:152
void WriteCompactSize(CSizeComputer &os, uint64_t nSize)
Definition: serialize.h:1254
BOOST_FIXTURE_TEST_SUITE(stakingrewards_tests, StakingRewardsActivationTestingSetup) BOOST_AUTO_TEST_CASE(isstakingrewardsactivated)
Serialization wrapper class for custom integers and enums.
Definition: serialize.h:606
void Ser(Stream &s, I v)
Definition: serialize.h:611
bool forEachLeaf(Callable &&func) const
Definition: radix.h:144
bool insert(const RCUPtr< T > &value)
Insert a value into the tree.
Definition: radix.h:112
avalanche::ProofRef proof
Definition: compactproofs.h:33
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11