Bitcoin ABC 0.31.2
P2P Digital Currency
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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#include <validation.h>
10
11#include <test/util/setup_common.h>
12
13#include <boost/test/unit_test.hpp>
14
15#include <algorithm>
16
17namespace avalanche {
18namespace {
19 struct TestCompactProofs {
20 static std::vector<uint64_t> getShortProofIds(const CompactProofs &cp) {
21 return cp.shortproofids;
22 }
23
24 static std::vector<PrefilledProof>
25 getPrefilledProofs(const CompactProofs &cp) {
26 return cp.prefilledProofs;
27 }
28
29 static void addPrefilledProof(CompactProofs &cp, uint32_t index,
30 const ProofRef &proof) {
31 PrefilledProof pp{index, proof};
32 cp.prefilledProofs.push_back(std::move(pp));
33 }
34 };
35} // namespace
36} // namespace avalanche
37
38using namespace avalanche;
39
40// TestingSetup is required for buildRandomProof()
41BOOST_FIXTURE_TEST_SUITE(compactproofs_tests, TestingSetup)
42
43BOOST_AUTO_TEST_CASE(compactproofs_roundtrip) {
44 {
45 CompactProofs cpw;
46 BOOST_CHECK_EQUAL(cpw.size(), 0);
47
49 BOOST_CHECK_NO_THROW(ss << cpw);
50
51 CompactProofs cpr;
52 BOOST_CHECK_NO_THROW(ss >> cpr);
53
54 BOOST_CHECK_EQUAL(cpr.size(), 0);
55 BOOST_CHECK_EQUAL(cpr.getKeys().first, cpw.getKeys().first);
56 BOOST_CHECK_EQUAL(cpr.getKeys().second, cpw.getKeys().second);
57 }
58
59 Chainstate &active_chainstate = Assert(m_node.chainman)->ActiveChainstate();
60
61 {
62 // Check index boundaries
64
65 TestCompactProofs::addPrefilledProof(
66 cp, 0, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
67 TestCompactProofs::addPrefilledProof(
68 cp, std::numeric_limits<uint32_t>::max(),
69 buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
70
72 BOOST_CHECK_NO_THROW(ss << cp);
73
74 auto prefilledProofs = TestCompactProofs::getPrefilledProofs(cp);
75 BOOST_CHECK_EQUAL(prefilledProofs.size(), 2);
76
77 BOOST_CHECK_EQUAL(prefilledProofs[0].index, 0);
78 BOOST_CHECK_EQUAL(prefilledProofs[1].index,
79 std::numeric_limits<uint32_t>::max());
80 }
81
82 auto checkCompactProof = [&](size_t numofProof,
83 size_t numofPrefilledProof) {
85 for (size_t i = 0; i < numofProof; i++) {
86 BOOST_CHECK(proofs.insert(
87 buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE)));
88 }
89
90 CompactProofs cpw(proofs);
91 BOOST_CHECK_EQUAL(cpw.size(), numofProof);
92
93 uint32_t prefilledProofIndex = 0;
94 for (size_t i = 0; i < numofPrefilledProof; i++) {
95 TestCompactProofs::addPrefilledProof(
96 cpw, prefilledProofIndex++,
97 buildRandomProof(active_chainstate, GetRand<uint32_t>()));
98 }
99 auto prefilledProofs = TestCompactProofs::getPrefilledProofs(cpw);
100 BOOST_CHECK_EQUAL(prefilledProofs.size(), numofPrefilledProof);
101
103 BOOST_CHECK_NO_THROW(ss << cpw);
104
105 CompactProofs cpr;
106 BOOST_CHECK_NO_THROW(ss >> cpr);
107
108 BOOST_CHECK_EQUAL(cpr.size(), numofProof + numofPrefilledProof);
109 BOOST_CHECK_EQUAL(cpr.getKeys().first, cpw.getKeys().first);
110 BOOST_CHECK_EQUAL(cpr.getKeys().second, cpw.getKeys().second);
111
112 auto comparePrefilledProof = [](const PrefilledProof &lhs,
113 const PrefilledProof &rhs) {
114 return lhs.index == rhs.index &&
115 lhs.proof->getId() == rhs.proof->getId() &&
116 lhs.proof->getSignature() == rhs.proof->getSignature();
117 };
118
119 auto prefilledProofsCpr = TestCompactProofs::getPrefilledProofs(cpr);
120 BOOST_CHECK(std::equal(prefilledProofsCpr.begin(),
121 prefilledProofsCpr.end(),
122 prefilledProofs.begin(), comparePrefilledProof));
123
124 auto shortIds = TestCompactProofs::getShortProofIds(cpr);
125 size_t index = 0;
126 proofs.forEachLeaf([&](auto pLeaf) {
127 const ProofId &proofid = pLeaf->getId();
128 BOOST_CHECK_EQUAL(cpr.getShortID(proofid), cpw.getShortID(proofid));
129 BOOST_CHECK_EQUAL(cpr.getShortID(proofid), shortIds[index]);
130 ++index;
131
132 return true;
133 });
134 };
135
136 // No proof at all
137 checkCompactProof(0, 0);
138
139 // No prefilled proofs
140 checkCompactProof(1000, 0);
141
142 // Only prefilled proofs
143 checkCompactProof(0, 1000);
144
145 // Mixed case
146 checkCompactProof(1000, 1000);
147}
148
149BOOST_AUTO_TEST_CASE(compactproofs_overflow) {
150 Chainstate &active_chainstate = Assert(m_node.chainman)->ActiveChainstate();
151 {
152 CompactProofs cp;
153
154 TestCompactProofs::addPrefilledProof(
155 cp, 0, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
156 TestCompactProofs::addPrefilledProof(
157 cp, 0, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
158
160 BOOST_CHECK_EXCEPTION(ss << cp, std::ios_base::failure,
161 HasReason("differential value overflow"));
162 }
163
164 {
165 CompactProofs cp;
166
167 TestCompactProofs::addPrefilledProof(
168 cp, 1, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
169 TestCompactProofs::addPrefilledProof(
170 cp, 0, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
171
173 BOOST_CHECK_EXCEPTION(ss << cp, std::ios_base::failure,
174 HasReason("differential value overflow"));
175 }
176
177 {
178 CompactProofs cp;
179
180 TestCompactProofs::addPrefilledProof(
181 cp, std::numeric_limits<uint32_t>::max(),
182 buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
183 TestCompactProofs::addPrefilledProof(
184 cp, 0, buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE));
185
187 BOOST_CHECK_EXCEPTION(ss << cp, std::ios_base::failure,
188 HasReason("differential value overflow"));
189 }
190
191 {
193 // shortproofidk0, shortproofidk1
194 ss << uint64_t(0) << uint64_t(0);
195 // shortproofids.size()
196 WriteCompactSize(ss, MAX_SIZE + 1);
197
198 CompactProofs cp;
199 BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
200 HasReason("ReadCompactSize(): size too large"));
201 }
202
203 {
205 // shortproofidk0, shortproofidk1
206 ss << uint64_t(0) << uint64_t(0);
207 // shortproofids.size()
208 WriteCompactSize(ss, 0);
209 // prefilledProofs.size()
210 WriteCompactSize(ss, MAX_SIZE + 1);
211
212 CompactProofs cp;
213 BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
214 HasReason("ReadCompactSize(): size too large"));
215 }
216
217 {
219 // shortproofidk0, shortproofidk1
220 ss << uint64_t(0) << uint64_t(0);
221 // shortproofids.size()
222 WriteCompactSize(ss, 0);
223 // prefilledProofs.size()
224 WriteCompactSize(ss, 1);
225 // prefilledProofs[0].index
226 WriteCompactSize(ss, MAX_SIZE + 1);
227 // prefilledProofs[0].proof
228 ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
229
230 CompactProofs cp;
231 BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
232 HasReason("ReadCompactSize(): size too large"));
233 }
234
235 // Compute the number of MAX_SIZE increment we need to cause an overflow
236 const uint64_t overflow =
237 uint64_t(std::numeric_limits<uint32_t>::max()) + 1;
238 // Due to differential encoding, a value of MAX_SIZE bumps the index by
239 // MAX_SIZE + 1
240 BOOST_CHECK_GE(overflow, MAX_SIZE + 1);
241 const uint64_t overflowIter = overflow / (MAX_SIZE + 1);
242
243 // Make sure the iteration fits in an uint32_t and is <= MAX_SIZE
244 BOOST_CHECK_LE(overflowIter, std::numeric_limits<uint32_t>::max());
245 BOOST_CHECK_LE(overflowIter, MAX_SIZE);
246 uint32_t remainder = uint32_t(overflow - ((MAX_SIZE + 1) * overflowIter));
247
248 {
250 // shortproofidk0, shortproofidk1
251 ss << uint64_t(0) << uint64_t(0);
252 // shortproofids.size()
253 WriteCompactSize(ss, 0);
254 // prefilledProofs.size()
255 WriteCompactSize(ss, overflowIter + 1);
256 for (uint32_t i = 0; i < overflowIter; i++) {
257 // prefilledProofs[i].index
259 // prefilledProofs[i].proof
260 ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
261 }
262 // This is the prefilled proof causing the overflow
263 WriteCompactSize(ss, remainder);
264 ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
265
266 CompactProofs cp;
267 BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
268 HasReason("differential value overflow"));
269 }
270
271 {
273 // shortproofidk0, shortproofidk1
274 ss << uint64_t(0) << uint64_t(0);
275 // shortproofids.size()
276 WriteCompactSize(ss, 1);
277 // shortproofids[0]
279 // prefilledProofs.size()
280 WriteCompactSize(ss, overflowIter + 1);
281 for (uint32_t i = 0; i < overflowIter; i++) {
282 // prefilledProofs[i].index
284 // prefilledProofs[i].proof
285 ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
286 }
287 // This prefilled proof isn't enough to cause the overflow alone, but it
288 // overflows due to the extra shortid.
289 WriteCompactSize(ss, remainder - 1);
290 ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
291
292 CompactProofs cp;
293 // ss >> cp;
294 BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
295 HasReason("indexes overflowed 32 bits"));
296 }
297
298 {
300 // shortproofidk0, shortproofidk1
301 ss << uint64_t(0) << uint64_t(0);
302 // shortproofids.size()
303 WriteCompactSize(ss, 0);
304 // prefilledProofs.size()
305 WriteCompactSize(ss, 2);
306 // prefilledProofs[0].index
307 WriteCompactSize(ss, 0);
308 // prefilledProofs[0].proof
309 ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
310 // prefilledProofs[1].index = 1 is differentially encoded, which means
311 // it has an absolute index of 2. This leaves no proof at index 1.
312 WriteCompactSize(ss, 1);
313 // prefilledProofs[1].proof
314 ss << buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
315
316 CompactProofs cp;
317 BOOST_CHECK_EXCEPTION(ss >> cp, std::ios_base::failure,
318 HasReason("non contiguous indexes"));
319 }
320}
321
322BOOST_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:705
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:168
const ProofId & getId() const
Definition: proof.h:170
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:20
NodeContext & m_node
Definition: interfaces.cpp:815
#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