github.com/decred/dcrd/blockchain@v1.2.1/votebits.go (about) 1 // Copyright (c) 2017-2018 The Decred developers 2 // Copyright (c) 2016 The btcsuite developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package blockchain 7 8 import ( 9 "github.com/decred/dcrd/chaincfg" 10 ) 11 12 // deploymentChecker provides a thresholdConditionChecker which can be used to 13 // test a specific deployment rule. This is required for properly detecting 14 // and activating consensus rule changes. 15 type deploymentChecker struct { 16 deployment *chaincfg.ConsensusDeployment 17 chain *BlockChain 18 } 19 20 // Ensure the deploymentChecker type implements the thresholdConditionChecker 21 // interface. 22 var _ thresholdConditionChecker = deploymentChecker{} 23 24 // BeginTime returns the unix timestamp for the median block time after which 25 // voting on a rule change starts (at the next window). 26 // 27 // This implementation returns the value defined by the specific deployment the 28 // checker is associated with. 29 // 30 // This is part of the thresholdConditionChecker interface implementation. 31 func (c deploymentChecker) BeginTime() uint64 { 32 return c.deployment.StartTime 33 } 34 35 // EndTime returns the unix timestamp for the median block time after which an 36 37 // attempted rule change fails if it has not already been locked in or 38 // activated. 39 // 40 // This implementation returns the value defined by the specific deployment the 41 // checker is associated with. 42 // 43 // This is part of the thresholdConditionChecker interface implementation. 44 func (c deploymentChecker) EndTime() uint64 { 45 return c.deployment.ExpireTime 46 } 47 48 // RuleChangeActivationQuorum is the minimum votes required to reach quorum. 49 // 50 // This implementation returns the value defined by the chain params the checker 51 // is associated with. 52 // 53 // This is part of the thresholdConditionChecker interface implementation. 54 func (c deploymentChecker) RuleChangeActivationQuorum() uint32 { 55 return c.chain.chainParams.RuleChangeActivationQuorum 56 } 57 58 // RuleChangeActivationThreshold is the number of votes required to reach the 59 // threshold as defined by chain params. 60 // 61 // This implementation returns the value defined by the chain params the checker 62 // is associated with. 63 // 64 // This is part of the thresholdConditionChecker interface implementation. 65 func (c deploymentChecker) RuleChangeActivationThreshold(totalVotes uint32) uint32 { 66 return totalVotes * c.chain.chainParams.RuleChangeActivationMultiplier / 67 c.chain.chainParams.RuleChangeActivationDivisor 68 } 69 70 // RuleChangeActivationInterval is the number of blocks in each threshold state 71 // retarget window. 72 // 73 // This implementation returns the value defined by the chain params the checker 74 // is associated with. 75 // 76 // This is part of the thresholdConditionChecker interface implementation. 77 func (c deploymentChecker) RuleChangeActivationInterval() uint32 { 78 return c.chain.chainParams.RuleChangeActivationInterval 79 } 80 81 // StakeValidationHeight is the minimum height required before votes start 82 // counting. 83 // 84 // This implementation returns the value defined by the chain params the checker 85 // is associated with. 86 // 87 // This is part of the thresholdConditionChecker interface implementation. 88 func (c deploymentChecker) StakeValidationHeight() int64 { 89 return c.chain.chainParams.StakeValidationHeight 90 } 91 92 // Condition returns true when the specific bit defined by the deployment 93 // associated with the checker is set. 94 // 95 // This is part of the thresholdConditionChecker interface implementation. 96 func (c deploymentChecker) Condition(node *blockNode, version uint32) ([]thresholdConditionTally, error) { 97 if c.deployment.Vote.Mask == 0 { 98 return []thresholdConditionTally{}, AssertError("invalid mask") 99 } 100 101 // Calculate shift in order to make a zero based index later. 102 var shift uint16 103 mask := c.deployment.Vote.Mask 104 for { 105 if mask&0x0001 == 0x0001 { 106 break 107 } 108 shift++ 109 mask >>= 1 110 } 111 112 // Setup tally array and iterate over Choices to assemble the vote 113 // information into the thresholdConditionTally array. 114 tally := make([]thresholdConditionTally, len(c.deployment.Vote.Choices)) 115 for t, choice := range c.deployment.Vote.Choices { 116 tally[t].isAbstain = choice.IsAbstain 117 tally[t].isNo = choice.IsNo 118 } 119 120 for _, vote := range node.votes { 121 if version != vote.Version { 122 // Wrong version, ignore. 123 continue 124 } 125 idx := c.deployment.Vote.Mask & vote.Bits >> shift 126 if int(idx) > len(c.deployment.Vote.Choices)-1 { 127 // Invalid choice. 128 continue 129 } 130 tally[idx].count++ 131 } 132 133 return tally, nil 134 }