dcrd/blockchain/votebits.go
Dave Collins be7ab82cf9
chaincfg: Start v3 module dev cycle.
Upcoming changes constitute breaking public API changes to the chaincfg
module, therefore, this follows the process for introducing major API
breaks which consists of:

- Bump the major version in the go.mod of the affected module if not
  already done since the last release tag
- Add a replacement to the go.mod in the main module if not already done
  since the last release tag
- Update all imports in the repo to use the new major version as
  necessary
- Make necessary modifications to allow all other modules to use the
  new version in the same commit
  - Repeat the process for any other modules the require a new major as a
    result of consuming the new major(s)
2020-01-29 13:24:14 -06:00

135 lines
4.4 KiB
Go

// Copyright (c) 2016 The btcsuite developers
// Copyright (c) 2017-2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain
import (
"github.com/decred/dcrd/chaincfg/v3"
)
// deploymentChecker provides a thresholdConditionChecker which can be used to
// test a specific deployment rule. This is required for properly detecting
// and activating consensus rule changes.
type deploymentChecker struct {
deployment *chaincfg.ConsensusDeployment
chain *BlockChain
}
// Ensure the deploymentChecker type implements the thresholdConditionChecker
// interface.
var _ thresholdConditionChecker = deploymentChecker{}
// BeginTime returns the unix timestamp for the median block time after which
// voting on a rule change starts (at the next window).
//
// This implementation returns the value defined by the specific deployment the
// checker is associated with.
//
// This is part of the thresholdConditionChecker interface implementation.
func (c deploymentChecker) BeginTime() uint64 {
return c.deployment.StartTime
}
// EndTime returns the unix timestamp for the median block time after which an
// attempted rule change fails if it has not already been locked in or
// activated.
//
// This implementation returns the value defined by the specific deployment the
// checker is associated with.
//
// This is part of the thresholdConditionChecker interface implementation.
func (c deploymentChecker) EndTime() uint64 {
return c.deployment.ExpireTime
}
// RuleChangeActivationQuorum is the minimum votes required to reach quorum.
//
// This implementation returns the value defined by the chain params the checker
// is associated with.
//
// This is part of the thresholdConditionChecker interface implementation.
func (c deploymentChecker) RuleChangeActivationQuorum() uint32 {
return c.chain.chainParams.RuleChangeActivationQuorum
}
// RuleChangeActivationThreshold is the number of votes required to reach the
// threshold as defined by chain params.
//
// This implementation returns the value defined by the chain params the checker
// is associated with.
//
// This is part of the thresholdConditionChecker interface implementation.
func (c deploymentChecker) RuleChangeActivationThreshold(totalVotes uint32) uint32 {
return totalVotes * c.chain.chainParams.RuleChangeActivationMultiplier /
c.chain.chainParams.RuleChangeActivationDivisor
}
// RuleChangeActivationInterval is the number of blocks in each threshold state
// retarget window.
//
// This implementation returns the value defined by the chain params the checker
// is associated with.
//
// This is part of the thresholdConditionChecker interface implementation.
func (c deploymentChecker) RuleChangeActivationInterval() uint32 {
return c.chain.chainParams.RuleChangeActivationInterval
}
// StakeValidationHeight is the minimum height required before votes start
// counting.
//
// This implementation returns the value defined by the chain params the checker
// is associated with.
//
// This is part of the thresholdConditionChecker interface implementation.
func (c deploymentChecker) StakeValidationHeight() int64 {
return c.chain.chainParams.StakeValidationHeight
}
// Condition returns true when the specific bit defined by the deployment
// associated with the checker is set.
//
// This is part of the thresholdConditionChecker interface implementation.
func (c deploymentChecker) Condition(node *blockNode, version uint32) ([]thresholdConditionTally, error) {
if c.deployment.Vote.Mask == 0 {
return []thresholdConditionTally{}, AssertError("invalid mask")
}
// Calculate shift in order to make a zero based index later.
var shift uint16
mask := c.deployment.Vote.Mask
for {
if mask&0x0001 == 0x0001 {
break
}
shift++
mask >>= 1
}
// Setup tally array and iterate over Choices to assemble the vote
// information into the thresholdConditionTally array.
tally := make([]thresholdConditionTally, len(c.deployment.Vote.Choices))
for t, choice := range c.deployment.Vote.Choices {
tally[t].isAbstain = choice.IsAbstain
tally[t].isNo = choice.IsNo
}
for _, vote := range node.votes {
if version != vote.Version {
// Wrong version, ignore.
continue
}
idx := c.deployment.Vote.Mask & vote.Bits >> shift
if int(idx) > len(c.deployment.Vote.Choices)-1 {
// Invalid choice.
continue
}
tally[idx].count++
}
return tally, nil
}