1 // Copyright (c) 2016-2017 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
10 "github.com/btcsuite/btcd/chaincfg/chainhash"
13 // ThresholdState define the various threshold states used when voting on
15 type ThresholdState byte
17 // These constants are used to identify specific threshold states.
19 // ThresholdDefined is the first state for each deployment and is the
20 // state for the genesis block has by definition for all deployments.
21 ThresholdDefined ThresholdState = iota
23 // ThresholdStarted is the state for a deployment once its start time
27 // ThresholdLockedIn is the state for a deployment during the retarget
28 // period which is after the ThresholdStarted state period and the
29 // number of blocks that have voted for the deployment equal or exceed
30 // the required number of votes for the deployment.
33 // ThresholdActive is the state for a deployment for all blocks after a
34 // retarget period in which the deployment was in the ThresholdLockedIn
38 // ThresholdFailed is the state for a deployment once its expiration
39 // time has been reached and it did not reach the ThresholdLockedIn
43 // numThresholdsStates is the maximum number of threshold states used in
48 // thresholdStateStrings is a map of ThresholdState values back to their
49 // constant names for pretty printing.
50 var thresholdStateStrings = map[ThresholdState]string{
51 ThresholdDefined: "ThresholdDefined",
52 ThresholdStarted: "ThresholdStarted",
53 ThresholdLockedIn: "ThresholdLockedIn",
54 ThresholdActive: "ThresholdActive",
55 ThresholdFailed: "ThresholdFailed",
58 // String returns the ThresholdState as a human-readable name.
59 func (t ThresholdState) String() string {
60 if s := thresholdStateStrings[t]; s != "" {
63 return fmt.Sprintf("Unknown ThresholdState (%d)", int(t))
66 // thresholdConditionChecker provides a generic interface that is invoked to
67 // determine when a consensus rule change threshold should be changed.
68 type thresholdConditionChecker interface {
69 // BeginTime returns the unix timestamp for the median block time after
70 // which voting on a rule change starts (at the next window).
73 // EndTime returns the unix timestamp for the median block time after
74 // which an attempted rule change fails if it has not already been
75 // locked in or activated.
78 // RuleChangeActivationThreshold is the number of blocks for which the
79 // condition must be true in order to lock in a rule change.
80 RuleChangeActivationThreshold() uint32
82 // MinerConfirmationWindow is the number of blocks in each threshold
83 // state retarget window.
84 MinerConfirmationWindow() uint32
86 // Condition returns whether or not the rule change activation condition
87 // has been met. This typically involves checking whether or not the
88 // bit assocaited with the condition is set, but can be more complex as
90 Condition(*blockNode) (bool, error)
93 // thresholdStateCache provides a type to cache the threshold states of each
94 // threshold window for a set of IDs.
95 type thresholdStateCache struct {
96 entries map[chainhash.Hash]ThresholdState
99 // Lookup returns the threshold state associated with the given hash along with
100 // a boolean that indicates whether or not it is valid.
101 func (c *thresholdStateCache) Lookup(hash *chainhash.Hash) (ThresholdState, bool) {
102 state, ok := c.entries[*hash]
106 // Update updates the cache to contain the provided hash to threshold state
108 func (c *thresholdStateCache) Update(hash *chainhash.Hash, state ThresholdState) {
109 c.entries[*hash] = state
112 // newThresholdCaches returns a new array of caches to be used when calculating
114 func newThresholdCaches(numCaches uint32) []thresholdStateCache {
115 caches := make([]thresholdStateCache, numCaches)
116 for i := 0; i < len(caches); i++ {
117 caches[i] = thresholdStateCache{
118 entries: make(map[chainhash.Hash]ThresholdState),
124 // thresholdState returns the current rule change threshold state for the block
125 // AFTER the given node and deployment ID. The cache is used to ensure the
126 // threshold states for previous windows are only calculated once.
128 // This function MUST be called with the chain state lock held (for writes).
129 func (b *BlockChain) thresholdState(prevNode *blockNode, checker thresholdConditionChecker, cache *thresholdStateCache) (ThresholdState, error) {
130 // The threshold state for the window that contains the genesis block is
131 // defined by definition.
132 confirmationWindow := int32(checker.MinerConfirmationWindow())
133 if prevNode == nil || (prevNode.height+1) < confirmationWindow {
134 return ThresholdDefined, nil
137 // Get the ancestor that is the last block of the previous confirmation
138 // window in order to get its threshold state. This can be done because
139 // the state is the same for all blocks within a given window.
140 prevNode = prevNode.Ancestor(prevNode.height -
141 (prevNode.height+1)%confirmationWindow)
143 // Iterate backwards through each of the previous confirmation windows
144 // to find the most recently cached threshold state.
145 var neededStates []*blockNode
146 for prevNode != nil {
147 // Nothing more to do if the state of the block is already
149 if _, ok := cache.Lookup(&prevNode.hash); ok {
153 // The start and expiration times are based on the median block
154 // time, so calculate it now.
155 medianTime := prevNode.CalcPastMedianTime()
157 // The state is simply defined if the start time hasn't been
159 if uint64(medianTime.Unix()) < checker.BeginTime() {
160 cache.Update(&prevNode.hash, ThresholdDefined)
164 // Add this node to the list of nodes that need the state
165 // calculated and cached.
166 neededStates = append(neededStates, prevNode)
168 // Get the ancestor that is the last block of the previous
169 // confirmation window.
170 prevNode = prevNode.RelativeAncestor(confirmationWindow)
173 // Start with the threshold state for the most recent confirmation
174 // window that has a cached state.
175 state := ThresholdDefined
178 state, ok = cache.Lookup(&prevNode.hash)
180 return ThresholdFailed, AssertError(fmt.Sprintf(
181 "thresholdState: cache lookup failed for %v",
186 // Since each threshold state depends on the state of the previous
187 // window, iterate starting from the oldest unknown window.
188 for neededNum := len(neededStates) - 1; neededNum >= 0; neededNum-- {
189 prevNode := neededStates[neededNum]
192 case ThresholdDefined:
193 // The deployment of the rule change fails if it expires
194 // before it is accepted and locked in.
195 medianTime := prevNode.CalcPastMedianTime()
196 medianTimeUnix := uint64(medianTime.Unix())
197 if medianTimeUnix >= checker.EndTime() {
198 state = ThresholdFailed
202 // The state for the rule moves to the started state
203 // once its start time has been reached (and it hasn't
204 // already expired per the above).
205 if medianTimeUnix >= checker.BeginTime() {
206 state = ThresholdStarted
209 case ThresholdStarted:
210 // The deployment of the rule change fails if it expires
211 // before it is accepted and locked in.
212 medianTime := prevNode.CalcPastMedianTime()
213 if uint64(medianTime.Unix()) >= checker.EndTime() {
214 state = ThresholdFailed
218 // At this point, the rule change is still being voted
219 // on by the miners, so iterate backwards through the
220 // confirmation window to count all of the votes in it.
222 countNode := prevNode
223 for i := int32(0); i < confirmationWindow; i++ {
224 condition, err := checker.Condition(countNode)
226 return ThresholdFailed, err
232 // Get the previous block node.
233 countNode = countNode.parent
236 // The state is locked in if the number of blocks in the
237 // period that voted for the rule change meets the
238 // activation threshold.
239 if count >= checker.RuleChangeActivationThreshold() {
240 state = ThresholdLockedIn
243 case ThresholdLockedIn:
244 // The new rule becomes active when its previous state
246 state = ThresholdActive
248 // Nothing to do if the previous state is active or failed since
249 // they are both terminal states.
250 case ThresholdActive:
251 case ThresholdFailed:
254 // Update the cache to avoid recalculating the state in the
256 cache.Update(&prevNode.hash, state)
262 // ThresholdState returns the current rule change threshold state of the given
263 // deployment ID for the block AFTER the end of the current best chain.
265 // This function is safe for concurrent access.
266 func (b *BlockChain) ThresholdState(deploymentID uint32) (ThresholdState, error) {
268 state, err := b.deploymentState(b.bestChain.Tip(), deploymentID)
274 // IsDeploymentActive returns true if the target deploymentID is active, and
277 // This function is safe for concurrent access.
278 func (b *BlockChain) IsDeploymentActive(deploymentID uint32) (bool, error) {
280 state, err := b.deploymentState(b.bestChain.Tip(), deploymentID)
286 return state == ThresholdActive, nil
289 // deploymentState returns the current rule change threshold for a given
290 // deploymentID. The threshold is evaluated from the point of view of the block
291 // node passed in as the first argument to this method.
293 // It is important to note that, as the variable name indicates, this function
294 // expects the block node prior to the block for which the deployment state is
295 // desired. In other words, the returned deployment state is for the block
296 // AFTER the passed node.
298 // This function MUST be called with the chain state lock held (for writes).
299 func (b *BlockChain) deploymentState(prevNode *blockNode, deploymentID uint32) (ThresholdState, error) {
300 if deploymentID > uint32(len(b.chainParams.Deployments)) {
301 return ThresholdFailed, DeploymentError(deploymentID)
304 deployment := &b.chainParams.Deployments[deploymentID]
305 checker := deploymentChecker{deployment: deployment, chain: b}
306 cache := &b.deploymentCaches[deploymentID]
308 return b.thresholdState(prevNode, checker, cache)
311 // initThresholdCaches initializes the threshold state caches for each warning
312 // bit and defined deployment and provides warnings if the chain is current per
313 // the warnUnknownVersions and warnUnknownRuleActivations functions.
314 func (b *BlockChain) initThresholdCaches() error {
315 // Initialize the warning and deployment caches by calculating the
316 // threshold state for each of them. This will ensure the caches are
317 // populated and any states that needed to be recalculated due to
318 // definition changes is done now.
319 prevNode := b.bestChain.Tip().parent
320 for bit := uint32(0); bit < vbNumBits; bit++ {
321 checker := bitConditionChecker{bit: bit, chain: b}
322 cache := &b.warningCaches[bit]
323 _, err := b.thresholdState(prevNode, checker, cache)
328 for id := 0; id < len(b.chainParams.Deployments); id++ {
329 deployment := &b.chainParams.Deployments[id]
330 cache := &b.deploymentCaches[id]
331 checker := deploymentChecker{deployment: deployment, chain: b}
332 _, err := b.thresholdState(prevNode, checker, cache)
338 // No warnings about unknown rules or versions until the chain is
341 // Warn if a high enough percentage of the last blocks have
342 // unexpected versions.
343 bestNode := b.bestChain.Tip()
344 if err := b.warnUnknownVersions(bestNode); err != nil {
348 // Warn if any unknown new rules are either about to activate or
349 // have already been activated.
350 if err := b.warnUnknownRuleActivations(bestNode); err != nil {