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