<commit_before>package versionbits

import (
	"math"
	"sync"

	"github.com/btcboost/copernicus/model/blockindex"
	"github.com/btcboost/copernicus/model/chainparams"
	"github.com/btcboost/copernicus/model/consensus"
)

const (
	// VersionBitsLastOldBlockVersion what block version to use for new blocks (pre versionBits)
	VersionBitsLastOldBlockVersion = 4
	// VersionBitsTopBits what bits to set in version for versionBits blocks
	VersionBitsTopBits = 0x20000000
	// VersionBitsTopMask What bitMask determines whether versionBits is in use
	VersionBitsTopMask int64 = 0xE0000000
	// VersionBitsNumBits Total bits available for versionBits
	VersionBitsNumBits = 29
)

type ThresholdState int

const (
	ThresholdDefined ThresholdState = iota
	ThresholdStarted
	ThresholdLockedIn
	ThresholdActive
	ThresholdFailed
)

type BIP9DeploymentInfo struct {
	Name     string
	GbtForce bool
}

type ThresholdConditionCache map[*blockindex.BlockIndex]ThresholdState

var VersionBitsDeploymentInfo = []BIP9DeploymentInfo{
	{
		Name:     "testdummy",
		GbtForce: true,
	},
	{
		Name:     "csv",
		GbtForce: true,
	},
}

type AbstractThresholdConditionChecker interface {
	Condition(index *blockindex.BlockIndex, params *chainparams.BitcoinParams) bool
	BeginTime(params *chainparams.BitcoinParams) int64
	EndTime(params *chainparams.BitcoinParams) int64
	Period(params *chainparams.BitcoinParams) int
	Threshold(params *chainparams.BitcoinParams) int
}

var VBCache *VersionBitsCache // todo waring: there is a global variable(used as cache)

type VersionBitsCache struct {
	sync.RWMutex
	cache [consensus.MaxVersionBitsDeployments]ThresholdConditionCache
}

func NewVersionBitsCache() *VersionBitsCache {
	var cache [consensus.MaxVersionBitsDeployments]ThresholdConditionCache
	for i := 0; i < int(consensus.MaxVersionBitsDeployments); i++ {
		cache[i] = make(ThresholdConditionCache)
	}
	return &VersionBitsCache{cache: cache}
}

func (vbc *VersionBitsCache) Clear() {
	for i := 0; i < int(consensus.MaxVersionBitsDeployments); i++ {
		vbc.cache[i] = make(ThresholdConditionCache)
	}
}

func NewWarnBitsCache(bitNum int) []ThresholdConditionCache {
	w := make([]ThresholdConditionCache, 0)
	for i := 0; i < bitNum; i++ {
		thres := make(ThresholdConditionCache)
		w = append(w, thres)
	}

	return w
}

func VersionBitsState(indexPrev *blockindex.BlockIndex, params *chainparams.BitcoinParams, pos consensus.DeploymentPos, vbc *VersionBitsCache) ThresholdState {
	vc := &VersionBitsConditionChecker{id: pos}
	return GetStateFor(vc, indexPrev, params, vbc.cache[pos])
}

func VersionBitsStateSinceHeight(indexPrev *blockindex.BlockIndex, params *chainparams.BitcoinParams, pos consensus.DeploymentPos, vbc *VersionBitsCache) int {
	vc := &VersionBitsConditionChecker{id: pos}
	return GetStateSinceHeightFor(vc, indexPrev, params, vbc.cache[pos])
}

func VersionBitsMask(params *chainparams.BitcoinParams, pos consensus.DeploymentPos) uint32 {
	vc := VersionBitsConditionChecker{id: pos}
	return uint32(vc.Mask(params))
}

type VersionBitsConditionChecker struct {
	id consensus.DeploymentPos
}

func (vc *VersionBitsConditionChecker) BeginTime(params *chainparams.BitcoinParams) int64 {
	return params.Deployments[vc.id].StartTime
}

func (vc *VersionBitsConditionChecker) EndTime(params *chainparams.BitcoinParams) int64 {
	return params.Deployments[vc.id].Timeout
}

func (vc *VersionBitsConditionChecker) Period(params *chainparams.BitcoinParams) int {
	return int(params.MinerConfirmationWindow)
}

func (vc *VersionBitsConditionChecker) Threshold(params *chainparams.BitcoinParams) int {
	return int(params.RuleChangeActivationThreshold)
}

func (vc *VersionBitsConditionChecker) Condition(index *blockindex.BlockIndex, params *chainparams.BitcoinParams) bool {
	return ((int64(index.Header.Version) & VersionBitsTopMask) == VersionBitsTopBits) &&
		(index.Header.Version&vc.Mask(params)) != 0
}

func (vc *VersionBitsConditionChecker) Mask(params *chainparams.BitcoinParams) int32 {
	return int32(1) << uint(params.Deployments[vc.id].Bit)
}

func GetStateFor(vc AbstractThresholdConditionChecker, indexPrev *blockindex.BlockIndex,
	params *chainparams.BitcoinParams, cache ThresholdConditionCache) ThresholdState {

	nPeriod := vc.Period(params)
	nThreshold := vc.Threshold(params)
	nTimeStart := vc.BeginTime(params)
	nTimeTimeout := vc.EndTime(params)

	// A block's state is always the same as that of the first of its period, so
	// it is computed based on a indexPrev whose height equals a multiple of
	// nPeriod - 1.
	if indexPrev != nil {
		indexPrev = indexPrev.GetAncestor(indexPrev.Height - (indexPrev.Height+1)%int32(nPeriod))
	}

	// Walk backwards in steps of nPeriod to find a indexPrev whose information
	// is known
	toCompute := make([]*blockindex.BlockIndex, 0)
	for {
		if _, ok := cache[indexPrev]; !ok {
			if indexPrev == nil {
				// The genesis block is by definition defined.
				cache[indexPrev] = ThresholdDefined
				break
			}
			if indexPrev.GetMedianTimePast() < nTimeStart {
				// Optimization: don't recompute down further, as we know every
				// earlier block will be before the start time
				cache[indexPrev] = ThresholdDefined
				break
			}
			toCompute = append(toCompute, indexPrev)
			indexPrev = indexPrev.GetAncestor(indexPrev.Height - nPeriod)
		} else {
			break
		}
	}

	// At this point, cache[indexPrev] is known
	state, ok := cache[indexPrev]
	if !ok {
		panic("there should be a element in cache")
	}

	// Now walk forward and compute the state of descendants of indexPrev
	for n := 0; n < len(toCompute); n++ {
		stateNext := state
		indexPrev = toCompute[len(toCompute)-1]
		toCompute = toCompute[:(len(toCompute) - 1)]

		switch state {
		case ThresholdDefined:
			{<commit_msg>versionbits: fix type error<commit_after>package versionbits

import (
	"math"
	"sync"

	"github.com/btcboost/copernicus/model/blockindex"
	"github.com/btcboost/copernicus/model/chainparams"
	"github.com/btcboost/copernicus/model/consensus"
)

const (
	// VersionBitsLastOldBlockVersion what block version to use for new blocks (pre versionBits)
	VersionBitsLastOldBlockVersion = 4
	// VersionBitsTopBits what bits to set in version for versionBits blocks
	VersionBitsTopBits = 0x20000000
	// VersionBitsTopMask What bitMask determines whether versionBits is in use
	VersionBitsTopMask int64 = 0xE0000000
	// VersionBitsNumBits Total bits available for versionBits
	VersionBitsNumBits = 29
)

type ThresholdState int

const (
	ThresholdDefined ThresholdState = iota
	ThresholdStarted
	ThresholdLockedIn
	ThresholdActive
	ThresholdFailed
)

type BIP9DeploymentInfo struct {
	Name     string
	GbtForce bool
}

type ThresholdConditionCache map[*blockindex.BlockIndex]ThresholdState

var VersionBitsDeploymentInfo = []BIP9DeploymentInfo{
	{
		Name:     "testdummy",
		GbtForce: true,
	},
	{
		Name:     "csv",
		GbtForce: true,
	},
}

type AbstractThresholdConditionChecker interface {
	Condition(index *blockindex.BlockIndex, params *chainparams.BitcoinParams) bool
	BeginTime(params *chainparams.BitcoinParams) int64
	EndTime(params *chainparams.BitcoinParams) int64
	Period(params *chainparams.BitcoinParams) int
	Threshold(params *chainparams.BitcoinParams) int
}

var VBCache *VersionBitsCache // todo waring: there is a global variable(used as cache)

type VersionBitsCache struct {
	sync.RWMutex
	cache [consensus.MaxVersionBitsDeployments]ThresholdConditionCache
}

func NewVersionBitsCache() *VersionBitsCache {
	var cache [consensus.MaxVersionBitsDeployments]ThresholdConditionCache
	for i := 0; i < int(consensus.MaxVersionBitsDeployments); i++ {
		cache[i] = make(ThresholdConditionCache)
	}
	return &VersionBitsCache{cache: cache}
}

func (vbc *VersionBitsCache) Clear() {
	for i := 0; i < int(consensus.MaxVersionBitsDeployments); i++ {
		vbc.cache[i] = make(ThresholdConditionCache)
	}
}

func NewWarnBitsCache(bitNum int) []ThresholdConditionCache {
	w := make([]ThresholdConditionCache, 0)
	for i := 0; i < bitNum; i++ {
		thres := make(ThresholdConditionCache)
		w = append(w, thres)
	}

	return w
}

func VersionBitsState(indexPrev *blockindex.BlockIndex, params *chainparams.BitcoinParams, pos consensus.DeploymentPos, vbc *VersionBitsCache) ThresholdState {
	vc := &VersionBitsConditionChecker{id: pos}
	return GetStateFor(vc, indexPrev, params, vbc.cache[pos])
}

func VersionBitsStateSinceHeight(indexPrev *blockindex.BlockIndex, params *chainparams.BitcoinParams, pos consensus.DeploymentPos, vbc *VersionBitsCache) int {
	vc := &VersionBitsConditionChecker{id: pos}
	return GetStateSinceHeightFor(vc, indexPrev, params, vbc.cache[pos])
}

func VersionBitsMask(params *chainparams.BitcoinParams, pos consensus.DeploymentPos) uint32 {
	vc := VersionBitsConditionChecker{id: pos}
	return uint32(vc.Mask(params))
}

type VersionBitsConditionChecker struct {
	id consensus.DeploymentPos
}

func (vc *VersionBitsConditionChecker) BeginTime(params *chainparams.BitcoinParams) int64 {
	return params.Deployments[vc.id].StartTime
}

func (vc *VersionBitsConditionChecker) EndTime(params *chainparams.BitcoinParams) int64 {
	return params.Deployments[vc.id].Timeout
}

func (vc *VersionBitsConditionChecker) Period(params *chainparams.BitcoinParams) int {
	return int(params.MinerConfirmationWindow)
}

func (vc *VersionBitsConditionChecker) Threshold(params *chainparams.BitcoinParams) int {
	return int(params.RuleChangeActivationThreshold)
}

func (vc *VersionBitsConditionChecker) Condition(index *blockindex.BlockIndex, params *chainparams.BitcoinParams) bool {
	return ((int64(index.Header.Version) & VersionBitsTopMask) == VersionBitsTopBits) &&
		(index.Header.Version&vc.Mask(params)) != 0
}

func (vc *VersionBitsConditionChecker) Mask(params *chainparams.BitcoinParams) int32 {
	return int32(1) << uint(params.Deployments[vc.id].Bit)
}

func GetStateFor(vc AbstractThresholdConditionChecker, indexPrev *blockindex.BlockIndex,
	params *chainparams.BitcoinParams, cache ThresholdConditionCache) ThresholdState {

	nPeriod := vc.Period(params)
	nThreshold := vc.Threshold(params)
	nTimeStart := vc.BeginTime(params)
	nTimeTimeout := vc.EndTime(params)

	// A block's state is always the same as that of the first of its period, so
	// it is computed based on a indexPrev whose height equals a multiple of
	// nPeriod - 1.
	if indexPrev != nil {
		indexPrev = indexPrev.GetAncestor(indexPrev.Height - (indexPrev.Height+1)%int32(nPeriod))
	}

	// Walk backwards in steps of nPeriod to find a indexPrev whose information
	// is known
	toCompute := make([]*blockindex.BlockIndex, 0)
	for {
		if _, ok := cache[indexPrev]; !ok {
			if indexPrev == nil {
				// The genesis block is by definition defined.
				cache[indexPrev] = ThresholdDefined
				break
			}
			if indexPrev.GetMedianTimePast() < nTimeStart {
				// Optimization: don't recompute down further, as we know every
				// earlier block will be before the start time
				cache[indexPrev] = ThresholdDefined
				break
			}
			toCompute = append(toCompute, indexPrev)
			indexPrev = indexPrev.GetAncestor(indexPrev.Height - int32(nPeriod))
		} else {
			break
		}
	}

	// At this point, cache[indexPrev] is known
	state, ok := cache[indexPrev]
	if !ok {
		panic("there should be a element in cache")
	}

	// Now walk forward and compute the state of descendants of indexPrev
	for n := 0; n < len(toCompute); n++ {
		stateNext := state
		indexPrev = toCompute[len(toCompute)-1]
		toCompute = toCompute[:(len(toCompute) - 1)]

		switch state {
		case ThresholdDefined:
			{
{'fraction_non_alphanumeric': 0.0959811699067213, 'fraction_numerical': 0.009938104785982041, 'mean_word_length': 5.35920177383592, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3723870', 'n_tokens_mistral': 3760, 'n_tokens_neox': 3596, 'n_words': 897}