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)
135 lines
4.4 KiB
Go
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
|
|
}
|