Bitcoin ABC 0.30.5
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
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
16namespace avalanche {
17namespace {
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
37using namespace avalanche;
38
39// TestingSetup is required for buildRandomProof()
40BOOST_FIXTURE_TEST_SUITE(compactproofs_tests, TestingSetup)
41
42BOOST_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
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
148BOOST_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
321BOOST_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:699
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 SchnorrSig & getSignature() const
Definition: proof.h:167
const ProofId & getId() const
Definition: proof.h:169
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
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