PIVX Core  5.6.99
P2P Digital Currency
skiplist_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014 The Bitcoin Core developers
2 // Copyright (c) 2017-2021 The PIVX Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "test/test_pivx.h"
7 
8 #include "util/system.h"
9 #include "validation.h"
10 
11 #include <vector>
12 
13 #include <boost/test/unit_test.hpp>
14 
15 #define SKIPLIST_LENGTH 300000
16 
18 
19 BOOST_AUTO_TEST_CASE(skiplist_test)
20 {
21  std::vector<CBlockIndex> vIndex(SKIPLIST_LENGTH);
22 
23  for (int i=0; i<SKIPLIST_LENGTH; i++) {
24  vIndex[i].nHeight = i;
25  vIndex[i].pprev = (i == 0) ? nullptr : &vIndex[i - 1];
26  vIndex[i].BuildSkip();
27  }
28 
29  for (int i=0; i<SKIPLIST_LENGTH; i++) {
30  if (i > 0) {
31  BOOST_CHECK(vIndex[i].pskip == &vIndex[vIndex[i].pskip->nHeight]);
32  BOOST_CHECK(vIndex[i].pskip->nHeight < i);
33  } else {
34  BOOST_CHECK(vIndex[i].pskip == nullptr);
35  }
36  }
37 
38  for (int i=0; i < 1000; i++) {
39  int from = InsecureRandRange(SKIPLIST_LENGTH - 1);
40  int to = InsecureRandRange(from + 1);
41 
42  BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]);
43  BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]);
44  BOOST_CHECK(vIndex[from].GetAncestor(0) == vIndex.data());
45  }
46 }
47 
48 BOOST_AUTO_TEST_CASE(getlocator_test)
49 {
50  // Build a main chain 100000 blocks long.
51  std::vector<uint256> vHashMain(100000);
52  std::vector<CBlockIndex> vBlocksMain(100000);
53  for (unsigned int i=0; i<vBlocksMain.size(); i++) {
54  vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height, so we can quickly check the distances.
55  vBlocksMain[i].nHeight = i;
56  vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr;
57  vBlocksMain[i].phashBlock = &vHashMain[i];
58  vBlocksMain[i].BuildSkip();
59  BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksMain[i].GetBlockHash()).GetLow64(), vBlocksMain[i].nHeight);
60  BOOST_CHECK(vBlocksMain[i].pprev == nullptr || vBlocksMain[i].nHeight == vBlocksMain[i].pprev->nHeight + 1);
61  }
62 
63  // Build a branch that splits off at block 49999, 50000 blocks long.
64  std::vector<uint256> vHashSide(50000);
65  std::vector<CBlockIndex> vBlocksSide(50000);
66  for (unsigned int i=0; i<vBlocksSide.size(); i++) {
67  vHashSide[i] = ArithToUint256(i + 50000 + (ARITH_UINT256_ONE << 128)); // Add 1<<128 to the hashes, so GetLow64() still returns the height.
68  vBlocksSide[i].nHeight = i + 50000;
69  vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : (vBlocksMain.data()+49999);
70  vBlocksSide[i].phashBlock = &vHashSide[i];
71  vBlocksSide[i].BuildSkip();
72  BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksSide[i].GetBlockHash()).GetLow64(), vBlocksSide[i].nHeight);
73  BOOST_CHECK(vBlocksSide[i].pprev == nullptr || vBlocksSide[i].nHeight == vBlocksSide[i].pprev->nHeight + 1);
74  }
75 
76  // Build a CChain for the main branch.
77  CChain chain;
78  chain.SetTip(&vBlocksMain.back());
79 
80  // Test 100 random starting points for locators.
81  for (int n=0; n<100; n++) {
82  int r = InsecureRandRange(150000);
83  CBlockIndex* tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000];
84  CBlockLocator locator = chain.GetLocator(tip);
85 
86  // The first result must be the block itself, the last one must be genesis.
87  BOOST_CHECK(locator.vHave.front() == tip->GetBlockHash());
88  BOOST_CHECK(locator.vHave.back() == vBlocksMain[0].GetBlockHash());
89 
90  // Entries 1 through 11 (inclusive) go back one step each.
91  for (unsigned int i = 1; i < 12 && i < locator.vHave.size() - 1; i++) {
92  BOOST_CHECK_EQUAL(UintToArith256(locator.vHave[i]).GetLow64(), tip->nHeight - i);
93  }
94 
95  // The further ones (excluding the last one) go back with exponential steps.
96  unsigned int dist = 2;
97  for (unsigned int i = 12; i < locator.vHave.size() - 1; i++) {
98  BOOST_CHECK_EQUAL(UintToArith256(locator.vHave[i - 1]).GetLow64() - UintToArith256(locator.vHave[i]).GetLow64(), dist);
99  dist *= 2;
100  }
101  }
102 }
103 
104 BOOST_AUTO_TEST_CASE(findearliestatleast_test)
105 {
106  std::vector<uint256> vHashMain(100000);
107  std::vector<CBlockIndex> vBlocksMain(100000);
108  for (unsigned int i=0; i<vBlocksMain.size(); i++) {
109  vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height
110  vBlocksMain[i].nHeight = i;
111  vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr;
112  vBlocksMain[i].phashBlock = &vHashMain[i];
113  vBlocksMain[i].BuildSkip();
114  if (i < 10) {
115  vBlocksMain[i].nTime = i;
116  vBlocksMain[i].nTimeMax = i;
117  } else {
118  // randomly choose something in the range [MTP, MTP*2]
119  int64_t medianTimePast = vBlocksMain[i].GetMedianTimePast();
120  int r = InsecureRandRange(medianTimePast);
121  vBlocksMain[i].nTime = r + medianTimePast;
122  vBlocksMain[i].nTimeMax = std::max(vBlocksMain[i].nTime, vBlocksMain[i-1].nTimeMax);
123  }
124  }
125  // Check that we set nTimeMax up correctly.
126  unsigned int curTimeMax = 0;
127  for (unsigned int i=0; i<vBlocksMain.size(); ++i) {
128  curTimeMax = std::max(curTimeMax, vBlocksMain[i].nTime);
129  BOOST_CHECK(curTimeMax == vBlocksMain[i].nTimeMax);
130  }
131 
132  // Build a CChain for the main branch.
133  CChain chain;
134  chain.SetTip(&vBlocksMain.back());
135 
136  // Verify that FindEarliestAtLeast is correct.
137  for (unsigned int i=0; i<10000; ++i) {
138  // Pick a random element in vBlocksMain.
139  int r = InsecureRandRange(vBlocksMain.size());
140  int64_t test_time = vBlocksMain[r].nTime;
141  CBlockIndex *ret = chain.FindEarliestAtLeast(test_time);
142  BOOST_CHECK(ret->nTimeMax >= test_time);
143  BOOST_CHECK((ret->pprev==nullptr) || ret->pprev->nTimeMax < test_time);
144  BOOST_CHECK(vBlocksMain[r].GetAncestor(ret->nHeight) == ret);
145  }
146 }
arith_uint256 UintToArith256(const uint256 &a)
uint256 ArithToUint256(const arith_uint256 &a)
const arith_uint256 ARITH_UINT256_ONE
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:139
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:145
unsigned int nTimeMax
(memory only) Maximum nTime in the chain upto and including this block.
Definition: chain.h:205
uint256 GetBlockHash() const
Definition: chain.h:215
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
An in-memory indexed chain of blocks.
Definition: chain.h:393
CBlockLocator GetLocator(const CBlockIndex *pindex=nullptr) const
Return a CBlockLocator that refers to a block in this chain (by default the tip).
Definition: chain.cpp:27
void SetTip(CBlockIndex *pindex)
Set/initialize a chain with a given tip.
Definition: chain.cpp:14
CBlockIndex * FindEarliestAtLeast(int64_t nTime) const
Find the earliest block with timestamp equal or greater than the given.
Definition: chain.cpp:67
uint64_t GetLow64() const
BOOST_AUTO_TEST_SUITE_END()
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
#define SKIPLIST_LENGTH
BOOST_AUTO_TEST_CASE(skiplist_test)
Basic testing setup.
Definition: test_pivx.h:51
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
Definition: block.h:154
std::vector< uint256 > vHave
Definition: block.h:155