github.com/btcsuite/btcd@v0.24.0/blockchain/versionbits.go (about) 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. 4 5 package blockchain 6 7 import ( 8 "github.com/btcsuite/btcd/chaincfg" 9 ) 10 11 const ( 12 // vbLegacyBlockVersion is the highest legacy block version before the 13 // version bits scheme became active. 14 vbLegacyBlockVersion = 4 15 16 // vbTopBits defines the bits to set in the version to signal that the 17 // version bits scheme is being used. 18 vbTopBits = 0x20000000 19 20 // vbTopMask is the bitmask to use to determine whether or not the 21 // version bits scheme is in use. 22 vbTopMask = 0xe0000000 23 24 // vbNumBits is the total number of bits available for use with the 25 // version bits scheme. 26 vbNumBits = 29 27 ) 28 29 // bitConditionChecker provides a thresholdConditionChecker which can be used to 30 // test whether or not a specific bit is set when it's not supposed to be 31 // according to the expected version based on the known deployments and the 32 // current state of the chain. This is useful for detecting and warning about 33 // unknown rule activations. 34 type bitConditionChecker struct { 35 bit uint32 36 chain *BlockChain 37 } 38 39 // Ensure the bitConditionChecker type implements the thresholdConditionChecker 40 // interface. 41 var _ thresholdConditionChecker = bitConditionChecker{} 42 43 // HasStarted returns true if based on the passed block blockNode the consensus 44 // is eligible for deployment. 45 // 46 // Since this implementation checks for unknown rules, it returns true so 47 // is always treated as active. 48 // 49 // This is part of the thresholdConditionChecker interface implementation. 50 func (c bitConditionChecker) HasStarted(_ *blockNode) bool { 51 return true 52 } 53 54 // HasStarted returns true if based on the passed block blockNode the consensus 55 // is eligible for deployment. 56 // 57 // Since this implementation checks for unknown rules, it returns false so the 58 // rule is always treated as active. 59 // 60 // This is part of the thresholdConditionChecker interface implementation. 61 func (c bitConditionChecker) HasEnded(_ *blockNode) bool { 62 return false 63 } 64 65 // RuleChangeActivationThreshold is the number of blocks for which the condition 66 // must be true in order to lock in a rule change. 67 // 68 // This implementation returns the value defined by the chain params the checker 69 // is associated with. 70 // 71 // This is part of the thresholdConditionChecker interface implementation. 72 func (c bitConditionChecker) RuleChangeActivationThreshold() uint32 { 73 return c.chain.chainParams.RuleChangeActivationThreshold 74 } 75 76 // MinerConfirmationWindow is the number of blocks in each threshold state 77 // retarget window. 78 // 79 // This implementation returns the value defined by the chain params the checker 80 // is associated with. 81 // 82 // This is part of the thresholdConditionChecker interface implementation. 83 func (c bitConditionChecker) MinerConfirmationWindow() uint32 { 84 return c.chain.chainParams.MinerConfirmationWindow 85 } 86 87 // Condition returns true when the specific bit associated with the checker is 88 // set and it's not supposed to be according to the expected version based on 89 // the known deployments and the current state of the chain. 90 // 91 // This function MUST be called with the chain state lock held (for writes). 92 // 93 // This is part of the thresholdConditionChecker interface implementation. 94 func (c bitConditionChecker) Condition(node *blockNode) (bool, error) { 95 conditionMask := uint32(1) << c.bit 96 version := uint32(node.version) 97 if version&vbTopMask != vbTopBits { 98 return false, nil 99 } 100 if version&conditionMask == 0 { 101 return false, nil 102 } 103 104 expectedVersion, err := c.chain.calcNextBlockVersion(node.parent) 105 if err != nil { 106 return false, err 107 } 108 return uint32(expectedVersion)&conditionMask == 0, nil 109 } 110 111 // EligibleToActivate returns true if a custom deployment can transition from 112 // the LockedIn to the Active state. For normal deployments, this always 113 // returns true. However, some deployments add extra rules like a minimum 114 // activation height, which can be abstracted into a generic arbitrary check at 115 // the final state via this method. 116 // 117 // This implementation always returns true, as it's used to warn about other 118 // unknown deployments. 119 // 120 // This is part of the thresholdConditionChecker interface implementation. 121 func (c bitConditionChecker) EligibleToActivate(blkNode *blockNode) bool { 122 return true 123 } 124 125 // IsSpeedy returns true if this is to be a "speedy" deployment. A speedy 126 // deployment differs from a regular one in that only after a miner block 127 // confirmation window can the deployment expire. 128 // 129 // This implementation returns false, as we want to always be warned if 130 // something is about to activate. 131 // 132 // This is part of the thresholdConditionChecker interface implementation. 133 func (c bitConditionChecker) IsSpeedy() bool { 134 return false 135 } 136 137 // deploymentChecker provides a thresholdConditionChecker which can be used to 138 // test a specific deployment rule. This is required for properly detecting 139 // and activating consensus rule changes. 140 type deploymentChecker struct { 141 deployment *chaincfg.ConsensusDeployment 142 chain *BlockChain 143 } 144 145 // Ensure the deploymentChecker type implements the thresholdConditionChecker 146 // interface. 147 var _ thresholdConditionChecker = deploymentChecker{} 148 149 // HasEnded returns true if the target consensus rule change has expired 150 // or timed out (at the next window). 151 // 152 // This implementation returns the value defined by the specific deployment the 153 // checker is associated with. 154 // 155 // This is part of the thresholdConditionChecker interface implementation. 156 func (c deploymentChecker) HasStarted(blkNode *blockNode) bool { 157 // Can't fail as we make sure to set the clock above when we 158 // instantiate *BlockChain. 159 header := blkNode.Header() 160 started, _ := c.deployment.DeploymentStarter.HasStarted(&header) 161 162 return started 163 } 164 165 // HasEnded returns true if the target consensus rule change has expired 166 // or timed out. 167 // 168 // This implementation returns the value defined by the specific deployment the 169 // checker is associated with. 170 // 171 // This is part of the thresholdConditionChecker interface implementation. 172 func (c deploymentChecker) HasEnded(blkNode *blockNode) bool { 173 // Can't fail as we make sure to set the clock above when we 174 // instantiate *BlockChain. 175 header := blkNode.Header() 176 ended, _ := c.deployment.DeploymentEnder.HasEnded(&header) 177 178 return ended 179 } 180 181 // RuleChangeActivationThreshold is the number of blocks for which the condition 182 // must be true in order to lock in a rule change. 183 // 184 // This implementation returns the value defined by the chain params the checker 185 // is associated with. 186 // 187 // This is part of the thresholdConditionChecker interface implementation. 188 func (c deploymentChecker) RuleChangeActivationThreshold() uint32 { 189 // Some deployments like taproot used a custom activation threshold 190 // that overrides the network level threshold. 191 if c.deployment.CustomActivationThreshold != 0 { 192 return c.deployment.CustomActivationThreshold 193 } 194 195 return c.chain.chainParams.RuleChangeActivationThreshold 196 } 197 198 // MinerConfirmationWindow is the number of blocks in each threshold state 199 // retarget window. 200 // 201 // This implementation returns the value defined by the chain params the checker 202 // is associated with. 203 // 204 // This is part of the thresholdConditionChecker interface implementation. 205 func (c deploymentChecker) MinerConfirmationWindow() uint32 { 206 return c.chain.chainParams.MinerConfirmationWindow 207 } 208 209 // EligibleToActivate returns true if a custom deployment can transition from 210 // the LockedIn to the Active state. For normal deployments, this always 211 // returns true. However, some deployments add extra rules like a minimum 212 // activation height, which can be abstracted into a generic arbitrary check at 213 // the final state via this method. 214 // 215 // This implementation always returns true, unless a minimum activation height 216 // is specified. 217 // 218 // This is part of the thresholdConditionChecker interface implementation. 219 func (c deploymentChecker) EligibleToActivate(blkNode *blockNode) bool { 220 // No activation height, so it's always ready to go. 221 if c.deployment.MinActivationHeight == 0 { 222 return true 223 } 224 225 // If the _next_ block (as this is the prior block to the one being 226 // connected is the min height or beyond, then this can activate. 227 return uint32(blkNode.height)+1 >= c.deployment.MinActivationHeight 228 } 229 230 // IsSpeedy returns true if this is to be a "speedy" deployment. A speedy 231 // deployment differs from a regular one in that only after a miner block 232 // confirmation window can the deployment expire. This implementation returns 233 // true if a min activation height is set. 234 // 235 // This is part of the thresholdConditionChecker interface implementation. 236 func (c deploymentChecker) IsSpeedy() bool { 237 return (c.deployment.MinActivationHeight != 0 || 238 c.deployment.CustomActivationThreshold != 0) 239 } 240 241 // Condition returns true when the specific bit defined by the deployment 242 // associated with the checker is set. 243 // 244 // This is part of the thresholdConditionChecker interface implementation. 245 func (c deploymentChecker) Condition(node *blockNode) (bool, error) { 246 conditionMask := uint32(1) << c.deployment.BitNumber 247 version := uint32(node.version) 248 return (version&vbTopMask == vbTopBits) && (version&conditionMask != 0), 249 nil 250 } 251 252 // calcNextBlockVersion calculates the expected version of the block after the 253 // passed previous block node based on the state of started and locked in 254 // rule change deployments. 255 // 256 // This function differs from the exported CalcNextBlockVersion in that the 257 // exported version uses the current best chain as the previous block node 258 // while this function accepts any block node. 259 // 260 // This function MUST be called with the chain state lock held (for writes). 261 func (b *BlockChain) calcNextBlockVersion(prevNode *blockNode) (int32, error) { 262 // Set the appropriate bits for each actively defined rule deployment 263 // that is either in the process of being voted on, or locked in for the 264 // activation at the next threshold window change. 265 expectedVersion := uint32(vbTopBits) 266 for id := 0; id < len(b.chainParams.Deployments); id++ { 267 deployment := &b.chainParams.Deployments[id] 268 cache := &b.deploymentCaches[id] 269 checker := deploymentChecker{deployment: deployment, chain: b} 270 state, err := b.thresholdState(prevNode, checker, cache) 271 if err != nil { 272 return 0, err 273 } 274 if state == ThresholdStarted || state == ThresholdLockedIn { 275 expectedVersion |= uint32(1) << deployment.BitNumber 276 } 277 } 278 return int32(expectedVersion), nil 279 } 280 281 // CalcNextBlockVersion calculates the expected version of the block after the 282 // end of the current best chain based on the state of started and locked in 283 // rule change deployments. 284 // 285 // This function is safe for concurrent access. 286 func (b *BlockChain) CalcNextBlockVersion() (int32, error) { 287 b.chainLock.Lock() 288 version, err := b.calcNextBlockVersion(b.bestChain.Tip()) 289 b.chainLock.Unlock() 290 return version, err 291 } 292 293 // warnUnknownRuleActivations displays a warning when any unknown new rules are 294 // either about to activate or have been activated. This will only happen once 295 // when new rules have been activated and every block for those about to be 296 // activated. 297 // 298 // This function MUST be called with the chain state lock held (for writes) 299 func (b *BlockChain) warnUnknownRuleActivations(node *blockNode) error { 300 // Warn if any unknown new rules are either about to activate or have 301 // already been activated. 302 for bit := uint32(0); bit < vbNumBits; bit++ { 303 checker := bitConditionChecker{bit: bit, chain: b} 304 cache := &b.warningCaches[bit] 305 state, err := b.thresholdState(node.parent, checker, cache) 306 if err != nil { 307 return err 308 } 309 310 switch state { 311 case ThresholdActive: 312 if !b.unknownRulesWarned { 313 log.Warnf("Unknown new rules activated (bit %d)", 314 bit) 315 b.unknownRulesWarned = true 316 } 317 318 case ThresholdLockedIn: 319 window := int32(checker.MinerConfirmationWindow()) 320 activationHeight := window - (node.height % window) 321 log.Warnf("Unknown new rules are about to activate in "+ 322 "%d blocks (bit %d)", activationHeight, bit) 323 } 324 } 325 326 return nil 327 }