/root/bitcoin/src/versionbits.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2016-2022 The Bitcoin Core 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 <consensus/params.h> |
6 | | #include <deploymentinfo.h> |
7 | | #include <kernel/chainparams.h> |
8 | | #include <util/check.h> |
9 | | #include <versionbits.h> |
10 | | #include <versionbits_impl.h> |
11 | | |
12 | | using enum ThresholdState; |
13 | | |
14 | | std::string StateName(ThresholdState state) |
15 | 0 | { |
16 | 0 | switch (state) { |
17 | 0 | case DEFINED: return "defined"; |
18 | 0 | case STARTED: return "started"; |
19 | 0 | case LOCKED_IN: return "locked_in"; |
20 | 0 | case ACTIVE: return "active"; |
21 | 0 | case FAILED: return "failed"; |
22 | 0 | } |
23 | 0 | return "invalid"; |
24 | 0 | } |
25 | | |
26 | | ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, ThresholdConditionCache& cache) const |
27 | 0 | { |
28 | 0 | int nPeriod = Period(); |
29 | 0 | int nThreshold = Threshold(); |
30 | 0 | int min_activation_height = MinActivationHeight(); |
31 | 0 | int64_t nTimeStart = BeginTime(); |
32 | 0 | int64_t nTimeTimeout = EndTime(); |
33 | | |
34 | | // Check if this deployment is always active. |
35 | 0 | if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) { |
36 | 0 | return ThresholdState::ACTIVE; |
37 | 0 | } |
38 | | |
39 | | // Check if this deployment is never active. |
40 | 0 | if (nTimeStart == Consensus::BIP9Deployment::NEVER_ACTIVE) { |
41 | 0 | return ThresholdState::FAILED; |
42 | 0 | } |
43 | | |
44 | | // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1. |
45 | 0 | if (pindexPrev != nullptr) { |
46 | 0 | pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod)); |
47 | 0 | } |
48 | | |
49 | | // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known |
50 | 0 | std::vector<const CBlockIndex*> vToCompute; |
51 | 0 | while (cache.count(pindexPrev) == 0) { |
52 | 0 | if (pindexPrev == nullptr) { |
53 | | // The genesis block is by definition defined. |
54 | 0 | cache[pindexPrev] = ThresholdState::DEFINED; |
55 | 0 | break; |
56 | 0 | } |
57 | 0 | if (pindexPrev->GetMedianTimePast() < nTimeStart) { |
58 | | // Optimization: don't recompute down further, as we know every earlier block will be before the start time |
59 | 0 | cache[pindexPrev] = ThresholdState::DEFINED; |
60 | 0 | break; |
61 | 0 | } |
62 | 0 | vToCompute.push_back(pindexPrev); |
63 | 0 | pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod); |
64 | 0 | } |
65 | | |
66 | | // At this point, cache[pindexPrev] is known |
67 | 0 | assert(cache.count(pindexPrev)); |
68 | 0 | ThresholdState state = cache[pindexPrev]; |
69 | | |
70 | | // Now walk forward and compute the state of descendants of pindexPrev |
71 | 0 | while (!vToCompute.empty()) { |
72 | 0 | ThresholdState stateNext = state; |
73 | 0 | pindexPrev = vToCompute.back(); |
74 | 0 | vToCompute.pop_back(); |
75 | |
|
76 | 0 | switch (state) { |
77 | 0 | case ThresholdState::DEFINED: { |
78 | 0 | if (pindexPrev->GetMedianTimePast() >= nTimeStart) { |
79 | 0 | stateNext = ThresholdState::STARTED; |
80 | 0 | } |
81 | 0 | break; |
82 | 0 | } |
83 | 0 | case ThresholdState::STARTED: { |
84 | | // We need to count |
85 | 0 | const CBlockIndex* pindexCount = pindexPrev; |
86 | 0 | int count = 0; |
87 | 0 | for (int i = 0; i < nPeriod; i++) { |
88 | 0 | if (Condition(pindexCount)) { |
89 | 0 | count++; |
90 | 0 | } |
91 | 0 | pindexCount = pindexCount->pprev; |
92 | 0 | } |
93 | 0 | if (count >= nThreshold) { |
94 | 0 | stateNext = ThresholdState::LOCKED_IN; |
95 | 0 | } else if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { |
96 | 0 | stateNext = ThresholdState::FAILED; |
97 | 0 | } |
98 | 0 | break; |
99 | 0 | } |
100 | 0 | case ThresholdState::LOCKED_IN: { |
101 | | // Progresses into ACTIVE provided activation height will have been reached. |
102 | 0 | if (pindexPrev->nHeight + 1 >= min_activation_height) { |
103 | 0 | stateNext = ThresholdState::ACTIVE; |
104 | 0 | } |
105 | 0 | break; |
106 | 0 | } |
107 | 0 | case ThresholdState::FAILED: |
108 | 0 | case ThresholdState::ACTIVE: { |
109 | | // Nothing happens, these are terminal states. |
110 | 0 | break; |
111 | 0 | } |
112 | 0 | } |
113 | 0 | cache[pindexPrev] = state = stateNext; |
114 | 0 | } |
115 | | |
116 | 0 | return state; |
117 | 0 | } |
118 | | |
119 | | BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, std::vector<bool>* signalling_blocks) const |
120 | 0 | { |
121 | 0 | BIP9Stats stats = {}; |
122 | |
|
123 | 0 | stats.period = Period(); |
124 | 0 | stats.threshold = Threshold(); |
125 | |
|
126 | 0 | if (pindex == nullptr) return stats; |
127 | | |
128 | | // Find how many blocks are in the current period |
129 | 0 | int blocks_in_period = 1 + (pindex->nHeight % stats.period); |
130 | | |
131 | | // Reset signalling_blocks |
132 | 0 | if (signalling_blocks) { |
133 | 0 | signalling_blocks->assign(blocks_in_period, false); |
134 | 0 | } |
135 | | |
136 | | // Count from current block to beginning of period |
137 | 0 | int elapsed = 0; |
138 | 0 | int count = 0; |
139 | 0 | const CBlockIndex* currentIndex = pindex; |
140 | 0 | do { |
141 | 0 | ++elapsed; |
142 | 0 | --blocks_in_period; |
143 | 0 | if (Condition(currentIndex)) { |
144 | 0 | ++count; |
145 | 0 | if (signalling_blocks) signalling_blocks->at(blocks_in_period) = true; |
146 | 0 | } |
147 | 0 | currentIndex = currentIndex->pprev; |
148 | 0 | } while(blocks_in_period > 0); |
149 | |
|
150 | 0 | stats.elapsed = elapsed; |
151 | 0 | stats.count = count; |
152 | 0 | stats.possible = (stats.period - stats.threshold ) >= (stats.elapsed - count); |
153 | |
|
154 | 0 | return stats; |
155 | 0 | } |
156 | | |
157 | | int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, ThresholdConditionCache& cache) const |
158 | 0 | { |
159 | 0 | int64_t start_time = BeginTime(); |
160 | 0 | if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE || start_time == Consensus::BIP9Deployment::NEVER_ACTIVE) { |
161 | 0 | return 0; |
162 | 0 | } |
163 | | |
164 | 0 | const ThresholdState initialState = GetStateFor(pindexPrev, cache); |
165 | | |
166 | | // BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment." |
167 | 0 | if (initialState == ThresholdState::DEFINED) { |
168 | 0 | return 0; |
169 | 0 | } |
170 | | |
171 | 0 | const int nPeriod = Period(); |
172 | | |
173 | | // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1. |
174 | | // To ease understanding of the following height calculation, it helps to remember that |
175 | | // right now pindexPrev points to the block prior to the block that we are computing for, thus: |
176 | | // if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and |
177 | | // if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period. |
178 | | // The parent of the genesis block is represented by nullptr. |
179 | 0 | pindexPrev = Assert(pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod))); |
180 | |
|
181 | 0 | const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod); |
182 | |
|
183 | 0 | while (previousPeriodParent != nullptr && GetStateFor(previousPeriodParent, cache) == initialState) { |
184 | 0 | pindexPrev = previousPeriodParent; |
185 | 0 | previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod); |
186 | 0 | } |
187 | | |
188 | | // Adjust the result because right now we point to the parent block. |
189 | 0 | return pindexPrev->nHeight + 1; |
190 | 0 | } |
191 | | |
192 | | BIP9Info VersionBitsCache::Info(const CBlockIndex& block_index, const Consensus::Params& params, Consensus::DeploymentPos id) |
193 | 0 | { |
194 | 0 | BIP9Info result; |
195 | |
|
196 | 0 | VersionBitsConditionChecker checker(params, id); |
197 | |
|
198 | 0 | ThresholdState current_state, next_state; |
199 | |
|
200 | 0 | { |
201 | 0 | LOCK(m_mutex); |
202 | 0 | current_state = checker.GetStateFor(block_index.pprev, m_caches[id]); |
203 | 0 | next_state = checker.GetStateFor(&block_index, m_caches[id]); |
204 | 0 | result.since = checker.GetStateSinceHeightFor(block_index.pprev, m_caches[id]); |
205 | 0 | } |
206 | |
|
207 | 0 | result.current_state = StateName(current_state); |
208 | 0 | result.next_state = StateName(next_state); |
209 | |
|
210 | 0 | const bool has_signal = (STARTED == current_state || LOCKED_IN == current_state); |
211 | 0 | if (has_signal) { |
212 | 0 | result.stats.emplace(checker.GetStateStatisticsFor(&block_index, &result.signalling_blocks)); |
213 | 0 | if (LOCKED_IN == current_state) { |
214 | 0 | result.stats->threshold = 0; |
215 | 0 | result.stats->possible = false; |
216 | 0 | } |
217 | 0 | } |
218 | |
|
219 | 0 | if (current_state == ACTIVE) { |
220 | 0 | result.active_since = result.since; |
221 | 0 | } else if (next_state == ACTIVE) { |
222 | 0 | result.active_since = block_index.nHeight + 1; |
223 | 0 | } |
224 | |
|
225 | 0 | return result; |
226 | 0 | } |
227 | | |
228 | | BIP9GBTStatus VersionBitsCache::GBTStatus(const CBlockIndex& block_index, const Consensus::Params& params) |
229 | 0 | { |
230 | 0 | BIP9GBTStatus result; |
231 | |
|
232 | 0 | LOCK(m_mutex); |
233 | 0 | for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { |
234 | 0 | auto pos = static_cast<Consensus::DeploymentPos>(i); |
235 | 0 | VersionBitsConditionChecker checker(params, pos); |
236 | 0 | ThresholdState state = checker.GetStateFor(&block_index, m_caches[pos]); |
237 | 0 | const VBDeploymentInfo& vbdepinfo = VersionBitsDeploymentInfo[pos]; |
238 | 0 | BIP9GBTStatus::Info gbtinfo{.bit=params.vDeployments[pos].bit, .mask=checker.Mask(), .gbt_optional_rule=vbdepinfo.gbt_optional_rule}; |
239 | |
|
240 | 0 | switch (state) { |
241 | 0 | case DEFINED: |
242 | 0 | case FAILED: |
243 | | // Not exposed to GBT |
244 | 0 | break; |
245 | 0 | case STARTED: |
246 | 0 | result.signalling.try_emplace(vbdepinfo.name, gbtinfo); |
247 | 0 | break; |
248 | 0 | case LOCKED_IN: |
249 | 0 | result.locked_in.try_emplace(vbdepinfo.name, gbtinfo); |
250 | 0 | break; |
251 | 0 | case ACTIVE: |
252 | 0 | result.active.try_emplace(vbdepinfo.name, gbtinfo); |
253 | 0 | break; |
254 | 0 | } |
255 | 0 | } |
256 | 0 | return result; |
257 | 0 | } |
258 | | |
259 | | bool VersionBitsCache::IsActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos) |
260 | 0 | { |
261 | 0 | LOCK(m_mutex); |
262 | 0 | return ThresholdState::ACTIVE == VersionBitsConditionChecker(params, pos).GetStateFor(pindexPrev, m_caches[pos]); |
263 | 0 | } |
264 | | |
265 | | static int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params, std::array<ThresholdConditionCache, Consensus::MAX_VERSION_BITS_DEPLOYMENTS>& caches) |
266 | 0 | { |
267 | 0 | int32_t nVersion = VERSIONBITS_TOP_BITS; |
268 | |
|
269 | 0 | for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { |
270 | 0 | Consensus::DeploymentPos pos = static_cast<Consensus::DeploymentPos>(i); |
271 | 0 | VersionBitsConditionChecker checker(params, pos); |
272 | 0 | ThresholdState state = checker.GetStateFor(pindexPrev, caches[pos]); |
273 | 0 | if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) { |
274 | 0 | nVersion |= checker.Mask(); |
275 | 0 | } |
276 | 0 | } |
277 | |
|
278 | 0 | return nVersion; |
279 | 0 | } |
280 | | |
281 | | int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) |
282 | 0 | { |
283 | 0 | LOCK(m_mutex); |
284 | 0 | return ::ComputeBlockVersion(pindexPrev, params, m_caches); |
285 | 0 | } |
286 | | |
287 | | void VersionBitsCache::Clear() |
288 | 0 | { |
289 | 0 | LOCK(m_mutex); |
290 | 0 | for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) { |
291 | 0 | m_caches[d].clear(); |
292 | 0 | } |
293 | 0 | } |
294 | | |
295 | | namespace { |
296 | | /** |
297 | | * Threshold condition checker that triggers when unknown versionbits are seen on the network. |
298 | | */ |
299 | | class WarningBitsConditionChecker : public AbstractThresholdConditionChecker |
300 | | { |
301 | | private: |
302 | | const Consensus::Params& m_params; |
303 | | std::array<ThresholdConditionCache, Consensus::MAX_VERSION_BITS_DEPLOYMENTS>& m_caches; |
304 | | int m_bit; |
305 | | int period{2016}; |
306 | | int threshold{1815}; // 90% threshold used in BIP 341 |
307 | | |
308 | | public: |
309 | | explicit WarningBitsConditionChecker(const CChainParams& chainparams, std::array<ThresholdConditionCache, Consensus::MAX_VERSION_BITS_DEPLOYMENTS>& caches, int bit) |
310 | 0 | : m_params{chainparams.GetConsensus()}, m_caches{caches}, m_bit(bit) |
311 | 0 | { |
312 | 0 | if (chainparams.IsTestChain()) { |
313 | 0 | period = chainparams.GetConsensus().DifficultyAdjustmentInterval(); |
314 | 0 | threshold = period * 3 / 4; // 75% for test nets per BIP9 suggestion |
315 | 0 | } |
316 | 0 | } |
317 | | |
318 | 0 | int64_t BeginTime() const override { return 0; } |
319 | 0 | int64_t EndTime() const override { return std::numeric_limits<int64_t>::max(); } |
320 | 0 | int Period() const override { return period; } |
321 | 0 | int Threshold() const override { return threshold; } |
322 | | |
323 | | bool Condition(const CBlockIndex* pindex) const override |
324 | 0 | { |
325 | 0 | return pindex->nHeight >= m_params.MinBIP9WarningHeight && |
326 | 0 | ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && |
327 | 0 | ((pindex->nVersion >> m_bit) & 1) != 0 && |
328 | 0 | ((::ComputeBlockVersion(pindex->pprev, m_params, m_caches) >> m_bit) & 1) == 0; |
329 | 0 | } |
330 | | }; |
331 | | } // anonymous namespace |
332 | | |
333 | | std::vector<std::pair<int, bool>> VersionBitsCache::CheckUnknownActivations(const CBlockIndex* pindex, const CChainParams& chainparams) |
334 | 0 | { |
335 | 0 | LOCK(m_mutex); |
336 | 0 | std::vector<std::pair<int, bool>> result; |
337 | 0 | for (int bit = 0; bit < VERSIONBITS_NUM_BITS; ++bit) { |
338 | 0 | WarningBitsConditionChecker checker(chainparams, m_caches, bit); |
339 | 0 | ThresholdState state = checker.GetStateFor(pindex, m_warning_caches.at(bit)); |
340 | 0 | if (state == ACTIVE || state == LOCKED_IN) { |
341 | 0 | result.emplace_back(bit, state == ACTIVE); |
342 | 0 | } |
343 | 0 | } |
344 | 0 | return result; |
345 | 0 | } |