func (b *BlockDAG) calcNextBlockVersion(prevNodes []*blockNode) (int32, error) {
	versions := make(map[int32]int)
	for id := 0; id < len(b.chainParams.Deployments); id++ {
		deployment := &b.chainParams.Deployments[id]
		cache := &b.deploymentCaches[id]
		checker := deploymentChecker{deployment: deployment, chain: b}
		states, err := b.thresholdStates(prevNodes, checker, cache)
		if err != nil {
			return 0, err
		}
		for _, state := range states {
			expectedVersion := uint32(vbTopBits)
			if state == ThresholdStarted || state == ThresholdLockedIn {
				expectedVersion |= uint32(1) << deployment.BitNumber
			}
			_, ok := versions[int32(expectedVersion)]
			if !ok {
				versions[int32(expectedVersion)] = 1
			} else {
				versions[int32(expectedVersion)]++
			}
		}
	}
	var mostPopularVersion int32
	var highestCount int
	for version, count := range versions {
		if count > highestCount {
			mostPopularVersion = version
			highestCount = count
		}
	}
	return mostPopularVersion, nil
}
calcNextBlockVersion calculates the expected version of the block after the
passed previous block node based on the state of started and locked in
rule change deployments.

This function differs from the exported CalcNextBlockVersion in that the
exported version uses the current best chain as the previous block node
while this function accepts any block node.

This function MUST be called with the chain state lock held (for writes).
package blockdag
import (
	"math"
	"github.com/soteria-dag/soterd/chaincfg"
)
const (
	vbLegacyBlockVersion = 4
	vbTopBits = 0x20000000
	vbTopMask = 0xe0000000
	vbNumBits = 29
	unknownVerNumToCheck = 100
	unknownVerWarnNum = unknownVerNumToCheck / 2
)
type bitConditionChecker struct {
	bit   uint32
	chain *BlockDAG
}
var _ thresholdConditionChecker = bitConditionChecker{}
func (c bitConditionChecker) BeginTime() uint64 {
	return 0
}
func (c bitConditionChecker) EndTime() uint64 {
	return math.MaxUint64
}
func (c bitConditionChecker) RuleChangeActivationThreshold() uint32 {
	return c.chain.chainParams.RuleChangeActivationThreshold
}
func (c bitConditionChecker) MinerConfirmationWindow() uint32 {
	return c.chain.chainParams.MinerConfirmationWindow
}
func (c bitConditionChecker) Condition(node *blockNode) (bool, error) {
	conditionMask := uint32(1) << c.bit
	version := uint32(node.version)
	if version&vbTopMask != vbTopBits {
		return false, nil
	}
	if version&conditionMask == 0 {
		return false, nil
	}
	expectedVersion, err := c.chain.calcNextBlockVersion(node.parents)
	if err != nil {
		return false, err
	}
	return uint32(expectedVersion)&conditionMask == 0, nil
}
type deploymentChecker struct {
	deployment *chaincfg.ConsensusDeployment
	chain      *BlockDAG
}
var _ thresholdConditionChecker = deploymentChecker{}
func (c deploymentChecker) BeginTime() uint64 {
	return c.deployment.StartTime
}
func (c deploymentChecker) EndTime() uint64 {
	return c.deployment.ExpireTime
}
func (c deploymentChecker) RuleChangeActivationThreshold() uint32 {
	return c.chain.chainParams.RuleChangeActivationThreshold
}
func (c deploymentChecker) MinerConfirmationWindow() uint32 {
	return c.chain.chainParams.MinerConfirmationWindow
}
func (c deploymentChecker) Condition(node *blockNode) (bool, error) {
	conditionMask := uint32(1) << c.deployment.BitNumber
	version := uint32(node.version)
	return (version&vbTopMask == vbTopBits) && (version&conditionMask != 0),
		nil
}