forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathblockchain_tests.cpp
More file actions
157 lines (128 loc) · 5.37 KB
/
blockchain_tests.cpp
File metadata and controls
157 lines (128 loc) · 5.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <boost/test/unit_test.hpp>
#include <chain.h>
#include <node/blockstorage.h>
#include <rpc/blockchain.h>
#include <sync.h>
#include <test/util/setup_common.h>
#include <util/string.h>
#include <cstdlib>
using util::ToString;
/* Equality between doubles is imprecise. Comparison should be done
* with a small threshold of tolerance, rather than exact equality.
*/
static bool DoubleEquals(double a, double b, double epsilon)
{
return std::abs(a - b) < epsilon;
}
static CBlockIndex* CreateBlockIndexWithNbits(uint32_t nbits)
{
CBlockIndex* block_index = new CBlockIndex();
block_index->nHeight = 46367;
block_index->nTime = 1269211443;
block_index->nBits = nbits;
return block_index;
}
static void RejectDifficultyMismatch(double difficulty, double expected_difficulty) {
BOOST_CHECK_MESSAGE(
DoubleEquals(difficulty, expected_difficulty, 0.00001),
"Difficulty was " + ToString(difficulty)
+ " but was expected to be " + ToString(expected_difficulty));
}
/* Given a BlockIndex with the provided nbits,
* verify that the expected difficulty results.
*/
static void TestDifficulty(uint32_t nbits, double expected_difficulty)
{
CBlockIndex* block_index = CreateBlockIndexWithNbits(nbits);
double difficulty = GetDifficulty(*block_index);
delete block_index;
RejectDifficultyMismatch(difficulty, expected_difficulty);
}
BOOST_FIXTURE_TEST_SUITE(blockchain_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(get_difficulty_for_very_low_target)
{
TestDifficulty(0x1f111111, 0.000001);
}
BOOST_AUTO_TEST_CASE(get_difficulty_for_low_target)
{
TestDifficulty(0x1ef88f6f, 0.000016);
}
BOOST_AUTO_TEST_CASE(get_difficulty_for_mid_target)
{
TestDifficulty(0x1df88f6f, 0.004023);
}
BOOST_AUTO_TEST_CASE(get_difficulty_for_high_target)
{
TestDifficulty(0x1cf88f6f, 1.029916);
}
BOOST_AUTO_TEST_CASE(get_difficulty_for_very_high_target)
{
TestDifficulty(0x12345678, 5913134931067755359633408.0);
}
//! Prune chain from height down to genesis block and check that
//! GetPruneHeight returns the correct value
static void CheckGetPruneHeight(node::BlockManager& blockman, CChain& chain, int height) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
// Emulate pruning all blocks from `height` down to the genesis block
// by unsetting the `BLOCK_HAVE_DATA` flag from `nStatus`
for (CBlockIndex* it{chain[height]}; it != nullptr && it->nHeight > 0; it = it->pprev) {
it->nStatus &= ~BLOCK_HAVE_DATA;
}
const auto prune_height{GetPruneHeight(blockman, chain)};
BOOST_REQUIRE(prune_height.has_value());
BOOST_CHECK_EQUAL(*prune_height, height);
}
BOOST_FIXTURE_TEST_CASE(get_prune_height, TestChain100Setup)
{
LOCK(::cs_main);
auto& chain = m_node.chainman->ActiveChain();
auto& blockman = m_node.chainman->m_blockman;
// Fresh chain of 100 blocks without any pruned blocks, so std::nullopt should be returned
BOOST_CHECK(!GetPruneHeight(blockman, chain).has_value());
// Start pruning
CheckGetPruneHeight(blockman, chain, 1);
CheckGetPruneHeight(blockman, chain, 99);
CheckGetPruneHeight(blockman, chain, 100);
}
BOOST_AUTO_TEST_CASE(num_chain_tx_max)
{
CBlockIndex block_index{};
block_index.m_chain_tx_count = std::numeric_limits<uint64_t>::max();
BOOST_CHECK_EQUAL(block_index.m_chain_tx_count, std::numeric_limits<uint64_t>::max());
}
BOOST_FIXTURE_TEST_CASE(invalidate_block, TestChain100Setup)
{
const CChain& active{*WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return &Assert(m_node.chainman)->ActiveChain())};
// Check BlockStatus when doing InvalidateBlock()
BlockValidationState state;
auto* orig_tip = active.Tip();
int height_to_invalidate = orig_tip->nHeight - 10;
auto* tip_to_invalidate = active[height_to_invalidate];
m_node.chainman->ActiveChainstate().InvalidateBlock(state, tip_to_invalidate);
// tip_to_invalidate just got invalidated, so it's BLOCK_FAILED_VALID
WITH_LOCK(::cs_main, assert(tip_to_invalidate->nStatus & BLOCK_FAILED_VALID));
WITH_LOCK(::cs_main, assert((tip_to_invalidate->nStatus & BLOCK_FAILED_CHILD) == 0));
// check all ancestors of the invalidated block are validated up to BLOCK_VALID_TRANSACTIONS and are not invalid
auto pindex = tip_to_invalidate->pprev;
while (pindex) {
WITH_LOCK(::cs_main, assert(pindex->IsValid(BLOCK_VALID_TRANSACTIONS)));
WITH_LOCK(::cs_main, assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0));
pindex = pindex->pprev;
}
// check all descendants of the invalidated block are BLOCK_FAILED_CHILD
pindex = orig_tip;
while (pindex && pindex != tip_to_invalidate) {
WITH_LOCK(::cs_main, assert((pindex->nStatus & BLOCK_FAILED_VALID) == 0));
WITH_LOCK(::cs_main, assert(pindex->nStatus & BLOCK_FAILED_CHILD));
pindex = pindex->pprev;
}
// don't mark already invalidated block (orig_tip is BLOCK_FAILED_CHILD) with BLOCK_FAILED_VALID again
m_node.chainman->ActiveChainstate().InvalidateBlock(state, orig_tip);
WITH_LOCK(::cs_main, assert(orig_tip->nStatus & BLOCK_FAILED_CHILD));
WITH_LOCK(::cs_main, assert((orig_tip->nStatus & BLOCK_FAILED_VALID) == 0));
}
BOOST_AUTO_TEST_SUITE_END()