Bitcoin ABC 0.33.11
P2P Digital Currency
voterecord_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2018-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 <test/util/random.h>
8#include <test/util/setup_common.h>
9
10#include <boost/test/unit_test.hpp>
11
12using namespace avalanche;
13
15struct VoteRecordFixture : public BasicTestingSetup {
17
20 if (currentNodeId >= 8) {
21 currentNodeId = 0;
22 }
23 return currentNodeId;
24 }
25};
26} // namespace voterecord_tests
27
28BOOST_FIXTURE_TEST_SUITE(voterecord_tests, VoteRecordFixture)
29
30#define REGISTER_VOTE_AND_CHECK(vr, vote, state, finalized, stale, confidence) \
31 vr.registerVote(nextNodeId(), vote); \
32 BOOST_CHECK_EQUAL(vr.isAccepted(), state); \
33 BOOST_CHECK_EQUAL(vr.hasFinalized(), finalized); \
34 BOOST_CHECK_EQUAL(vr.isStale(), stale); \
35 BOOST_CHECK_EQUAL(vr.getConfidence(), confidence);
36
38 VoteRecord vraccepted(true);
39
40 // Check initial state.
41 BOOST_CHECK_EQUAL(vraccepted.isAccepted(), true);
42 BOOST_CHECK_EQUAL(vraccepted.hasFinalized(), false);
43 BOOST_CHECK_EQUAL(vraccepted.isStale(), false);
44 BOOST_CHECK_EQUAL(vraccepted.getConfidence(), 0);
45
46 VoteRecord vr(false);
47
48 // Check initial state.
49 BOOST_CHECK_EQUAL(vr.isAccepted(), false);
51 BOOST_CHECK_EQUAL(vr.isStale(), false);
53
54 // We need to register 6 positive votes before we start counting.
55 for (int i = 0; i < 6; i++) {
56 REGISTER_VOTE_AND_CHECK(vr, 0, false, false, false, 0);
57 }
58
59 // Next vote will flip state, and confidence will increase as long as we
60 // vote yes.
61 REGISTER_VOTE_AND_CHECK(vr, 0, true, false, false, 0);
62
63 // A single neutral vote do not change anything.
64 REGISTER_VOTE_AND_CHECK(vr, -1, true, false, false, 1);
65 for (int i = 2; i < 8; i++) {
66 REGISTER_VOTE_AND_CHECK(vr, 0, true, false, false, i);
67 }
68
69 // Two neutral votes will stall progress.
70 REGISTER_VOTE_AND_CHECK(vr, -1, true, false, false, 7);
71 REGISTER_VOTE_AND_CHECK(vr, -1, true, false, false, 7);
72 for (int i = 2; i < 8; i++) {
73 REGISTER_VOTE_AND_CHECK(vr, 0, true, false, false, 7);
74 }
75
76 // Now confidence will increase as long as we vote yes.
77 for (int i = 8; i < AVALANCHE_FINALIZATION_SCORE; i++) {
78 REGISTER_VOTE_AND_CHECK(vr, 0, true, false, false, i);
79 }
80
81 // The next vote will finalize the decision.
82 REGISTER_VOTE_AND_CHECK(vr, 1, true, true, false,
84
85 // Now that we have two no votes, confidence stop increasing.
86 for (int i = 0; i < 5; i++) {
87 REGISTER_VOTE_AND_CHECK(vr, 1, true, true, false,
89 }
90
91 // Next vote will flip state, and confidence will increase as long as we
92 // vote no.
93 REGISTER_VOTE_AND_CHECK(vr, 1, false, false, false, 0);
94
95 // A single neutral vote do not change anything.
96 REGISTER_VOTE_AND_CHECK(vr, -1, false, false, false, 1);
97 for (int i = 2; i < 8; i++) {
98 REGISTER_VOTE_AND_CHECK(vr, 1, false, false, false, i);
99 }
100
101 // Two neutral votes will stall progress.
102 REGISTER_VOTE_AND_CHECK(vr, -1, false, false, false, 7);
103 REGISTER_VOTE_AND_CHECK(vr, -1, false, false, false, 7);
104 for (int i = 2; i < 8; i++) {
105 REGISTER_VOTE_AND_CHECK(vr, 1, false, false, false, 7);
106 }
107
108 // Now confidence will increase as long as we vote no.
109 for (int i = 8; i < AVALANCHE_FINALIZATION_SCORE; i++) {
110 REGISTER_VOTE_AND_CHECK(vr, 1, false, false, false, i);
111 }
112
113 // The next vote will finalize the decision.
114 REGISTER_VOTE_AND_CHECK(vr, 0, false, true, false,
116
117 // Check that inflight accounting work as expected.
118 VoteRecord vrinflight(false);
119 for (int i = 0; i < 2 * AVALANCHE_MAX_INFLIGHT_POLL; i++) {
120 bool shouldPoll = vrinflight.shouldPoll();
122 BOOST_CHECK_EQUAL(vrinflight.registerPoll(), shouldPoll);
123 }
124
125 // Clear various number of inflight requests and check everything behaves as
126 // expected.
127 for (int i = 1; i < AVALANCHE_MAX_INFLIGHT_POLL; i++) {
128 vrinflight.clearInflightRequest(i);
129 BOOST_CHECK(vrinflight.shouldPoll());
130
131 for (int j = 1; j < i; j++) {
132 BOOST_CHECK(vrinflight.registerPoll());
133 BOOST_CHECK(vrinflight.shouldPoll());
134 }
135
136 BOOST_CHECK(vrinflight.registerPoll());
137 BOOST_CHECK(!vrinflight.shouldPoll());
138 }
139
140 // Check for inflight underflow
141 VoteRecord vrunderflow(false);
142 BOOST_CHECK(vrunderflow.shouldPoll());
144 // If an underflow occurred, the inflight count would be >
145 // AVALANCHE_MAX_INFLIGHT_POLL
146 BOOST_CHECK(vrunderflow.shouldPoll());
147}
148
149// Test some cases where confidence never advances
150BOOST_AUTO_TEST_CASE(stale_vote_always_inconclusive) {
151 // Setup a record that is inconclusive so far
152 VoteRecord vr(false);
153
154 for (uint32_t i = 0; i < AVALANCHE_VOTE_STALE_THRESHOLD / 8; i++) {
155 // Vote randomly, but such that there's always enough neutral votes to
156 // not gain confidence.
157 for (auto j = 0; j < 6; j++) {
158 REGISTER_VOTE_AND_CHECK(vr, m_rng.rand32(), false, false, false, 0);
159 }
160 REGISTER_VOTE_AND_CHECK(vr, -1, false, false, false, 0);
161 REGISTER_VOTE_AND_CHECK(vr, -1, false, false, false, 0);
162 }
163
164 // Vote record becomes stale after too many rounds of inconclusive voting
165 REGISTER_VOTE_AND_CHECK(vr, -1, false, false, true, 0);
166}
167
168// Test all cases where records reach a specific confidence level and then go
169// stale.
170BOOST_AUTO_TEST_CASE(stale_vote_at_all_confidence_levels) {
171 for (uint32_t vote = 0; vote <= 1; vote++) {
172 for (uint32_t confidence = 0; confidence < AVALANCHE_FINALIZATION_SCORE;
173 confidence++) {
174 VoteRecord vr(!vote);
175
176 // Prepare to increase confidence with some votes
177 for (auto i = 0; i < 5; i++) {
178 REGISTER_VOTE_AND_CHECK(vr, vote, !vote, false, false, 0);
179 }
180
181 // Increase to target confidence
182 for (uint32_t i = 0; i < confidence; i++) {
183 REGISTER_VOTE_AND_CHECK(vr, vote, !vote, false, false, i);
184 }
185
186 uint32_t remainingVotes =
187 AVALANCHE_VOTE_STALE_THRESHOLD - confidence - 5;
188
189 // Special case where staying at confidence of 1 requires a
190 // different vote between agreeing votes
191 if (confidence == 1) {
192 REGISTER_VOTE_AND_CHECK(vr, -1, !vote, false, false, 0);
193 REGISTER_VOTE_AND_CHECK(vr, vote, !vote, false, false, 1);
194 remainingVotes -= 2;
195 }
196
197 // Vote neutral until stale
198 if (confidence >
200 remainingVotes =
201 confidence * AVALANCHE_VOTE_STALE_FACTOR - confidence - 5;
202 }
203 for (uint32_t i = 0; i < remainingVotes; i++) {
204 REGISTER_VOTE_AND_CHECK(vr, -1, !vote, false, false,
205 confidence);
206 }
207 REGISTER_VOTE_AND_CHECK(vr, -1, !vote, false, true, confidence);
208 }
209 }
210}
211
212// Test some cases where confidence may flip flop and then goes stale.
213BOOST_AUTO_TEST_CASE(stale_vote_random_then_inconclusive) {
214 VoteRecord vr(false);
215
216 for (uint32_t i = 0; i < AVALANCHE_FINALIZATION_SCORE - 14; i++) {
217 // Vote randomly. Confidence changes are ok.
218 vr.registerVote(nextNodeId(), m_rng.rand32());
219 BOOST_CHECK_EQUAL(vr.hasFinalized(), false);
220 BOOST_CHECK_EQUAL(vr.isStale(), false);
221 }
222
223 // Reset confidence, no matter what it is right now
224 for (uint32_t i = 0; i < 7; i++) {
225 vr.registerVote(nextNodeId(), 0);
226 }
227 for (uint32_t i = 0; i < 7; i++) {
228 vr.registerVote(nextNodeId(), 1);
229 }
230 BOOST_CHECK_EQUAL(vr.hasFinalized(), false);
231 BOOST_CHECK_EQUAL(vr.isStale(), false);
232
233 // Remainder of votes are neutral
234 for (uint32_t i = 0;
236 i++) {
237 REGISTER_VOTE_AND_CHECK(vr, -1, false, false, false, 1);
238 }
239
240 // Vote record becomes stale after too many rounds of voting
241 REGISTER_VOTE_AND_CHECK(vr, -1, false, false, true, 1);
242}
243
244// Test all cases where confidence flips as much as possible, ending at all
245// possible confidence levels.
246BOOST_AUTO_TEST_CASE(stale_vote_with_confidence_flips) {
247 // Start testing with yes or no votes
248 for (uint32_t voteInit = 0; voteInit <= 1; voteInit++) {
249 // Test stalling at all confidence levels
250 for (auto offset = 0; offset < AVALANCHE_FINALIZATION_SCORE; offset++) {
251 uint32_t vote = voteInit;
252 VoteRecord vr(!vote);
253 uint32_t count = 0;
254
255 // Offset with neutral votes
256 for (auto i = 0; i < offset; i++) {
257 REGISTER_VOTE_AND_CHECK(vr, -1, !vote, false, false, 0);
258 count++;
259 }
260
261 // Prepare to increase confidence with some votes
262 for (auto i = 0; i < 5; i++) {
263 REGISTER_VOTE_AND_CHECK(vr, vote, !vote, false, false, 0);
264 count++;
265 }
266
267 while (true) {
268 // Increase confidence as fast as possible
269 for (uint32_t i = 0; i < AVALANCHE_FINALIZATION_SCORE - 1;
270 i++) {
274 REGISTER_VOTE_AND_CHECK(vr, vote, !vote, false, true,
275 i);
276 goto finalsanitycheck;
277 }
281 REGISTER_VOTE_AND_CHECK(vr, vote, !vote, false, true,
282 i);
283 goto finalsanitycheck;
284 }
285
286 REGISTER_VOTE_AND_CHECK(vr, vote, !vote, false, false, i);
287 count++;
288 }
289
290 // Flip the vote
291 if (vote++ >= 1) {
292 vote = 0;
293 }
294
295 // Reset confidence
296 for (auto i = 0; i < 6; i++) {
299 REGISTER_VOTE_AND_CHECK(vr, vote, vote, false, true,
301 goto finalsanitycheck;
302 }
303
304 REGISTER_VOTE_AND_CHECK(vr, vote, vote, false, false,
306 count++;
307 }
308
309 // If this fails, we are probably infinite looping for some
310 // reason
313 }
314
315 finalsanitycheck:
316 BOOST_CHECK(vr.isStale());
317 }
318 }
319}
320
321BOOST_AUTO_TEST_CASE(duplicate_votes) {
322 VoteRecord vr(true);
323
324 // Register some votes, expecting confidence to increase
325 for (auto i = 0; i < 7; i++) {
327 BOOST_CHECK(!vr.registerVote(nextNodeId(), 0));
328 }
330
331 // Multiple duplicate votes do not advance confidence
332 for (auto i = 0; i < 8; i++) {
333 BOOST_CHECK(!vr.registerVote(currentNodeId, 0));
335 }
336
337 // Register more votes with duplicates mixed in. Confidence should only
338 // increase when duplicates are not used.
339 auto expectedConfidence = 1;
340 for (auto i = 0; i < 8; i++) {
341 BOOST_CHECK(!vr.registerVote(currentNodeId, 0));
342 BOOST_CHECK_EQUAL(vr.getConfidence(), expectedConfidence);
343 for (auto j = i; j < 8; j++) {
344 BOOST_CHECK(!vr.registerVote(nextNodeId(), 0));
345 BOOST_CHECK_EQUAL(vr.getConfidence(), ++expectedConfidence);
346 }
347 }
348
349 // Register enough votes to get just before finalization
350 for (auto i = 0; i < 90; i++) {
351 BOOST_CHECK(!vr.registerVote(nextNodeId(), 0));
352 BOOST_CHECK_EQUAL(vr.getConfidence(), ++expectedConfidence);
353 }
354
355 // Sanity check that finalization occurs on the expected vote
356 BOOST_CHECK(vr.registerVote(nextNodeId(), 0));
358}
359
360BOOST_AUTO_TEST_SUITE_END()
int64_t NodeId
Definition: eviction.h:16
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
Vote history.
Definition: voterecord.h:49
uint16_t getConfidence() const
Definition: voterecord.h:88
bool hasFinalized() const
Definition: voterecord.h:89
bool shouldPoll() const
Return if this item is in condition to be polled at the moment.
Definition: voterecord.h:115
void clearInflightRequest(uint8_t count=1) const
Clear count inflight requests.
Definition: voterecord.cpp:99
bool registerVote(NodeId nodeid, uint32_t error)
Register a new vote for an item and update confidence accordingly.
Definition: voterecord.cpp:14
bool isStale(uint32_t staleThreshold=AVALANCHE_VOTE_STALE_THRESHOLD, uint32_t staleFactor=AVALANCHE_VOTE_STALE_FACTOR) const
Definition: voterecord.h:93
bool registerPoll() const
Register that a request is being made regarding that item.
Definition: voterecord.cpp:88
bool isAccepted() const
Vote accounting facilities.
Definition: voterecord.h:86
static int count
static constexpr uint32_t AVALANCHE_VOTE_STALE_FACTOR
Scaling factor applied to confidence to determine staleness threshold.
Definition: voterecord.h:35
static constexpr int AVALANCHE_MAX_INFLIGHT_POLL
How many inflight requests can exist for one item.
Definition: voterecord.h:40
static constexpr uint32_t AVALANCHE_VOTE_STALE_THRESHOLD
Number of votes before a record may be considered as stale.
Definition: voterecord.h:22
static constexpr int AVALANCHE_FINALIZATION_SCORE
Finalization score.
Definition: voterecord.h:17
#define REGISTER_VOTE_AND_CHECK(vr, vote, state, finalized, stale, confidence)
BOOST_AUTO_TEST_CASE(vote_record)