github.com/palcoin-project/palcd@v1.0.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 "math" 9 10 "github.com/palcoin-project/palcd/chaincfg" 11 ) 12 13 const ( 14 // vbLegacyBlockVersion is the highest legacy block version before the 15 // version bits scheme became active. 16 vbLegacyBlockVersion = 4 17 18 // vbTopBits defines the bits to set in the version to signal that the 19 // version bits scheme is being used. 20 vbTopBits = 0x20000000 21 22 // vbTopMask is the bitmask to use to determine whether or not the 23 // version bits scheme is in use. 24 vbTopMask = 0xe0000000 25 26 // vbNumBits is the total number of bits available for use with the 27 // version bits scheme. 28 vbNumBits = 29 29 ) 30 31 // bitConditionChecker provides a thresholdConditionChecker which can be used to 32 // test whether or not a specific bit is set when it's not supposed to be 33 // according to the expected version based on the known deployments and the 34 // current state of the chain. This is useful for detecting and warning about 35 // unknown rule activations. 36 type bitConditionChecker struct { 37 bit uint32 38 chain *BlockChain 39 } 40 41 // Ensure the bitConditionChecker type implements the thresholdConditionChecker 42 // interface. 43 var _ thresholdConditionChecker = bitConditionChecker{} 44 45 // BeginTime returns the unix timestamp for the median block time after which 46 // voting on a rule change starts (at the next window). 47 // 48 // Since this implementation checks for unknown rules, it returns 0 so the rule 49 // is always treated as active. 50 // 51 // This is part of the thresholdConditionChecker interface implementation. 52 func (c bitConditionChecker) BeginTime() uint64 { 53 return 0 54 } 55 56 // EndTime returns the unix timestamp for the median block time after which an 57 // attempted rule change fails if it has not already been locked in or 58 // activated. 59 // 60 // Since this implementation checks for unknown rules, it returns the maximum 61 // possible timestamp so the rule is always treated as active. 62 // 63 // This is part of the thresholdConditionChecker interface implementation. 64 func (c bitConditionChecker) EndTime() uint64 { 65 return math.MaxUint64 66 } 67 68 // RuleChangeActivationThreshold is the number of blocks for which the condition 69 // must be true in order to lock in a rule change. 70 // 71 // This implementation returns the value defined by the chain params the checker 72 // is associated with. 73 // 74 // This is part of the thresholdConditionChecker interface implementation. 75 func (c bitConditionChecker) RuleChangeActivationThreshold() uint32 { 76 return c.chain.chainParams.RuleChangeActivationThreshold 77 } 78 79 // MinerConfirmationWindow is the number of blocks in each threshold state 80 // retarget window. 81 // 82 // This implementation returns the value defined by the chain params the checker 83 // is associated with. 84 // 85 // This is part of the thresholdConditionChecker interface implementation. 86 func (c bitConditionChecker) MinerConfirmationWindow() uint32 { 87 return c.chain.chainParams.MinerConfirmationWindow 88 } 89 90 // Condition returns true when the specific bit associated with the checker is 91 // set and it's not supposed to be according to the expected version based on 92 // the known deployments and the current state of the chain. 93 // 94 // This function MUST be called with the chain state lock held (for writes). 95 // 96 // This is part of the thresholdConditionChecker interface implementation. 97 func (c bitConditionChecker) Condition(node *blockNode) (bool, error) { 98 conditionMask := uint32(1) << c.bit 99 version := uint32(node.version) 100 if version&vbTopMask != vbTopBits { 101 return false, nil 102 } 103 if version&conditionMask == 0 { 104 return false, nil 105 } 106 107 expectedVersion, err := c.chain.calcNextBlockVersion(node.parent) 108 if err != nil { 109 return false, err 110 } 111 return uint32(expectedVersion)&conditionMask == 0, nil 112 } 113 114 // deploymentChecker provides a thresholdConditionChecker which can be used to 115 // test a specific deployment rule. This is required for properly detecting 116 // and activating consensus rule changes. 117 type deploymentChecker struct { 118 deployment *chaincfg.ConsensusDeployment 119 chain *BlockChain 120 } 121 122 // Ensure the deploymentChecker type implements the thresholdConditionChecker 123 // interface. 124 var _ thresholdConditionChecker = deploymentChecker{} 125 126 // BeginTime returns the unix timestamp for the median block time after which 127 // voting on a rule change starts (at the next window). 128 // 129 // This implementation returns the value defined by the specific deployment the 130 // checker is associated with. 131 // 132 // This is part of the thresholdConditionChecker interface implementation. 133 func (c deploymentChecker) BeginTime() uint64 { 134 return c.deployment.StartTime 135 } 136 137 // EndTime returns the unix timestamp for the median block time after which an 138 // attempted rule change fails if it has not already been locked in or 139 // activated. 140 // 141 // This implementation returns the value defined by the specific deployment the 142 // checker is associated with. 143 // 144 // This is part of the thresholdConditionChecker interface implementation. 145 func (c deploymentChecker) EndTime() uint64 { 146 return c.deployment.ExpireTime 147 } 148 149 // RuleChangeActivationThreshold is the number of blocks for which the condition 150 // must be true in order to lock in a rule change. 151 // 152 // This implementation returns the value defined by the chain params the checker 153 // is associated with. 154 // 155 // This is part of the thresholdConditionChecker interface implementation. 156 func (c deploymentChecker) RuleChangeActivationThreshold() uint32 { 157 return c.chain.chainParams.RuleChangeActivationThreshold 158 } 159 160 // MinerConfirmationWindow is the number of blocks in each threshold state 161 // retarget window. 162 // 163 // This implementation returns the value defined by the chain params the checker 164 // is associated with. 165 // 166 // This is part of the thresholdConditionChecker interface implementation. 167 func (c deploymentChecker) MinerConfirmationWindow() uint32 { 168 return c.chain.chainParams.MinerConfirmationWindow 169 } 170 171 // Condition returns true when the specific bit defined by the deployment 172 // associated with the checker is set. 173 // 174 // This is part of the thresholdConditionChecker interface implementation. 175 func (c deploymentChecker) Condition(node *blockNode) (bool, error) { 176 conditionMask := uint32(1) << c.deployment.BitNumber 177 version := uint32(node.version) 178 return (version&vbTopMask == vbTopBits) && (version&conditionMask != 0), 179 nil 180 } 181 182 // calcNextBlockVersion calculates the expected version of the block after the 183 // passed previous block node based on the state of started and locked in 184 // rule change deployments. 185 // 186 // This function differs from the exported CalcNextBlockVersion in that the 187 // exported version uses the current best chain as the previous block node 188 // while this function accepts any block node. 189 // 190 // This function MUST be called with the chain state lock held (for writes). 191 func (b *BlockChain) calcNextBlockVersion(prevNode *blockNode) (int32, error) { 192 // Set the appropriate bits for each actively defined rule deployment 193 // that is either in the process of being voted on, or locked in for the 194 // activation at the next threshold window change. 195 expectedVersion := uint32(vbTopBits) 196 for id := 0; id < len(b.chainParams.Deployments); id++ { 197 deployment := &b.chainParams.Deployments[id] 198 cache := &b.deploymentCaches[id] 199 checker := deploymentChecker{deployment: deployment, chain: b} 200 state, err := b.thresholdState(prevNode, checker, cache) 201 if err != nil { 202 return 0, err 203 } 204 if state == ThresholdStarted || state == ThresholdLockedIn { 205 expectedVersion |= uint32(1) << deployment.BitNumber 206 } 207 } 208 return int32(expectedVersion), nil 209 } 210 211 // CalcNextBlockVersion calculates the expected version of the block after the 212 // end of the current best chain based on the state of started and locked in 213 // rule change deployments. 214 // 215 // This function is safe for concurrent access. 216 func (b *BlockChain) CalcNextBlockVersion() (int32, error) { 217 b.chainLock.Lock() 218 version, err := b.calcNextBlockVersion(b.bestChain.Tip()) 219 b.chainLock.Unlock() 220 return version, err 221 } 222 223 // warnUnknownRuleActivations displays a warning when any unknown new rules are 224 // either about to activate or have been activated. This will only happen once 225 // when new rules have been activated and every block for those about to be 226 // activated. 227 // 228 // This function MUST be called with the chain state lock held (for writes) 229 func (b *BlockChain) warnUnknownRuleActivations(node *blockNode) error { 230 // Warn if any unknown new rules are either about to activate or have 231 // already been activated. 232 for bit := uint32(0); bit < vbNumBits; bit++ { 233 checker := bitConditionChecker{bit: bit, chain: b} 234 cache := &b.warningCaches[bit] 235 state, err := b.thresholdState(node.parent, checker, cache) 236 if err != nil { 237 return err 238 } 239 240 switch state { 241 case ThresholdActive: 242 if !b.unknownRulesWarned { 243 log.Warnf("Unknown new rules activated (bit %d)", 244 bit) 245 b.unknownRulesWarned = true 246 } 247 248 case ThresholdLockedIn: 249 window := int32(checker.MinerConfirmationWindow()) 250 activationHeight := window - (node.height % window) 251 log.Warnf("Unknown new rules are about to activate in "+ 252 "%d blocks (bit %d)", activationHeight, bit) 253 } 254 } 255 256 return nil 257 }