github.com/btcsuite/btcd@v0.24.0/blockchain/thresholdstate.go (about)

     1  // Copyright (c) 2016-2017 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package blockchain
     6  
     7  import (
     8  	"fmt"
     9  	"time"
    10  
    11  	"github.com/btcsuite/btcd/chaincfg/chainhash"
    12  	"github.com/btcsuite/btcd/wire"
    13  )
    14  
    15  // ThresholdState define the various threshold states used when voting on
    16  // consensus changes.
    17  type ThresholdState byte
    18  
    19  // These constants are used to identify specific threshold states.
    20  const (
    21  	// ThresholdDefined is the first state for each deployment and is the
    22  	// state for the genesis block has by definition for all deployments.
    23  	ThresholdDefined ThresholdState = iota
    24  
    25  	// ThresholdStarted is the state for a deployment once its start time
    26  	// has been reached.
    27  	ThresholdStarted
    28  
    29  	// ThresholdLockedIn is the state for a deployment during the retarget
    30  	// period which is after the ThresholdStarted state period and the
    31  	// number of blocks that have voted for the deployment equal or exceed
    32  	// the required number of votes for the deployment.
    33  	ThresholdLockedIn
    34  
    35  	// ThresholdActive is the state for a deployment for all blocks after a
    36  	// retarget period in which the deployment was in the ThresholdLockedIn
    37  	// state.
    38  	ThresholdActive
    39  
    40  	// ThresholdFailed is the state for a deployment once its expiration
    41  	// time has been reached and it did not reach the ThresholdLockedIn
    42  	// state.
    43  	ThresholdFailed
    44  
    45  	// numThresholdsStates is the maximum number of threshold states used in
    46  	// tests.
    47  	numThresholdsStates
    48  )
    49  
    50  // thresholdStateStrings is a map of ThresholdState values back to their
    51  // constant names for pretty printing.
    52  var thresholdStateStrings = map[ThresholdState]string{
    53  	ThresholdDefined:  "ThresholdDefined",
    54  	ThresholdStarted:  "ThresholdStarted",
    55  	ThresholdLockedIn: "ThresholdLockedIn",
    56  	ThresholdActive:   "ThresholdActive",
    57  	ThresholdFailed:   "ThresholdFailed",
    58  }
    59  
    60  // String returns the ThresholdState as a human-readable name.
    61  func (t ThresholdState) String() string {
    62  	if s := thresholdStateStrings[t]; s != "" {
    63  		return s
    64  	}
    65  	return fmt.Sprintf("Unknown ThresholdState (%d)", int(t))
    66  }
    67  
    68  // thresholdConditionChecker provides a generic interface that is invoked to
    69  // determine when a consensus rule change threshold should be changed.
    70  type thresholdConditionChecker interface {
    71  	// HasStarted returns true if based on the passed block blockNode the
    72  	// consensus is eligible for deployment.
    73  	HasStarted(*blockNode) bool
    74  
    75  	// HasEnded returns true if the target consensus rule change has
    76  	// expired or timed out.
    77  	HasEnded(*blockNode) bool
    78  
    79  	// RuleChangeActivationThreshold is the number of blocks for which the
    80  	// condition must be true in order to lock in a rule change.
    81  	RuleChangeActivationThreshold() uint32
    82  
    83  	// MinerConfirmationWindow is the number of blocks in each threshold
    84  	// state retarget window.
    85  	MinerConfirmationWindow() uint32
    86  
    87  	// EligibleToActivate returns true if a custom deployment can
    88  	// transition from the LockedIn to the Active state. For normal
    89  	// deployments, this always returns true. However, some deployments add
    90  	// extra rules like a minimum activation height, which can be
    91  	// abstracted into a generic arbitrary check at the final state via
    92  	// this method.
    93  	EligibleToActivate(*blockNode) bool
    94  
    95  	// IsSpeedy returns true if this is to be a "speedy" deployment. A
    96  	// speedy deployment differs from a regular one in that only after a
    97  	// miner block confirmation window can the deployment expire.
    98  	IsSpeedy() bool
    99  
   100  	// Condition returns whether or not the rule change activation
   101  	// condition has been met.  This typically involves checking whether or
   102  	// not the bit associated with the condition is set, but can be more
   103  	// complex as needed.
   104  	Condition(*blockNode) (bool, error)
   105  }
   106  
   107  // thresholdStateCache provides a type to cache the threshold states of each
   108  // threshold window for a set of IDs.
   109  type thresholdStateCache struct {
   110  	entries map[chainhash.Hash]ThresholdState
   111  }
   112  
   113  // Lookup returns the threshold state associated with the given hash along with
   114  // a boolean that indicates whether or not it is valid.
   115  func (c *thresholdStateCache) Lookup(hash *chainhash.Hash) (ThresholdState, bool) {
   116  	state, ok := c.entries[*hash]
   117  	return state, ok
   118  }
   119  
   120  // Update updates the cache to contain the provided hash to threshold state
   121  // mapping.
   122  func (c *thresholdStateCache) Update(hash *chainhash.Hash, state ThresholdState) {
   123  	c.entries[*hash] = state
   124  }
   125  
   126  // newThresholdCaches returns a new array of caches to be used when calculating
   127  // threshold states.
   128  func newThresholdCaches(numCaches uint32) []thresholdStateCache {
   129  	caches := make([]thresholdStateCache, numCaches)
   130  	for i := 0; i < len(caches); i++ {
   131  		caches[i] = thresholdStateCache{
   132  			entries: make(map[chainhash.Hash]ThresholdState),
   133  		}
   134  	}
   135  	return caches
   136  }
   137  
   138  // PastMedianTime returns the past median time from the PoV of the passed block
   139  // header. The past median time is the median time of the 11 blocks prior to
   140  // the passed block header.
   141  //
   142  // NOTE: This is part of the chainfg.BlockClock interface
   143  func (b *BlockChain) PastMedianTime(blockHeader *wire.BlockHeader) (time.Time, error) {
   144  	prevHash := blockHeader.PrevBlock
   145  	prevNode := b.index.LookupNode(&prevHash)
   146  
   147  	// If we can't find the previous node, then we can't compute the block
   148  	// time since it requires us to walk backwards from this node.
   149  	if prevNode == nil {
   150  		return time.Time{}, fmt.Errorf("blockHeader(%v) has no "+
   151  			"previous node", blockHeader.BlockHash())
   152  	}
   153  
   154  	blockNode := newBlockNode(blockHeader, prevNode)
   155  
   156  	return CalcPastMedianTime(blockNode), nil
   157  }
   158  
   159  // thresholdStateTransition given a state, a previous node, and a toeholds
   160  // checker, this function transitions to the next state as defined by BIP 009.
   161  // This state transition function is also aware of the "speedy trial"
   162  // modifications made to BIP 0009 as part of the taproot softfork activation.
   163  func thresholdStateTransition(state ThresholdState, prevNode *blockNode,
   164  	checker thresholdConditionChecker,
   165  	confirmationWindow int32) (ThresholdState, error) {
   166  
   167  	switch state {
   168  	case ThresholdDefined:
   169  		// The deployment of the rule change fails if it
   170  		// expires before it is accepted and locked in. However
   171  		// speed deployments can only transition to failed
   172  		// after a confirmation window.
   173  		if !checker.IsSpeedy() && checker.HasEnded(prevNode) {
   174  			log.Debugf("Moving from state=%v, to state=%v", state,
   175  				ThresholdFailed)
   176  
   177  			state = ThresholdFailed
   178  			break
   179  		}
   180  
   181  		// The state for the rule moves to the started state
   182  		// once its start time has been reached (and it hasn't
   183  		// already expired per the above).
   184  		if checker.HasStarted(prevNode) {
   185  			log.Debugf("Moving from state=%v, to state=%v", state,
   186  				ThresholdStarted)
   187  
   188  			state = ThresholdStarted
   189  		}
   190  
   191  	case ThresholdStarted:
   192  		// The deployment of the rule change fails if it
   193  		// expires before it is accepted and locked in, but
   194  		// only if this deployment isn't speedy.
   195  		if !checker.IsSpeedy() && checker.HasEnded(prevNode) {
   196  			log.Debugf("Moving from state=%v, to state=%v", state,
   197  				ThresholdFailed)
   198  
   199  			state = ThresholdFailed
   200  			break
   201  		}
   202  
   203  		// At this point, the rule change is still being voted
   204  		// on by the miners, so iterate backwards through the
   205  		// confirmation window to count all of the votes in it.
   206  		var count uint32
   207  		countNode := prevNode
   208  		for i := int32(0); i < confirmationWindow; i++ {
   209  			condition, err := checker.Condition(countNode)
   210  			if err != nil {
   211  				return ThresholdFailed, err
   212  			}
   213  			if condition {
   214  				count++
   215  			}
   216  
   217  			// Get the previous block node.
   218  			countNode = countNode.parent
   219  		}
   220  
   221  		switch {
   222  		// The state is locked in if the number of blocks in the
   223  		// period that voted for the rule change meets the
   224  		// activation threshold.
   225  		case count >= checker.RuleChangeActivationThreshold():
   226  			log.Debugf("Moving from state=%v, to state=%v", state,
   227  				ThresholdLockedIn)
   228  
   229  			state = ThresholdLockedIn
   230  
   231  		// If this is a speedy deployment, we didn't meet the
   232  		// threshold above, and the deployment has expired, then
   233  		// we transition to failed.
   234  		case checker.IsSpeedy() && checker.HasEnded(prevNode):
   235  			log.Debugf("Moving from state=%v, to state=%v", state,
   236  				ThresholdFailed)
   237  
   238  			state = ThresholdFailed
   239  
   240  		default:
   241  			log.Tracef("Still at state=%v, threshold=%v", state,
   242  				float64(count)/float64(checker.RuleChangeActivationThreshold()))
   243  		}
   244  
   245  	case ThresholdLockedIn:
   246  		// At this point, we'll consult the deployment see if a
   247  		// custom deployment has any other arbitrary conditions
   248  		// that need to pass before execution. This might be a
   249  		// minimum activation height or another policy.
   250  		//
   251  		// If we aren't eligible to active yet, then we'll just
   252  		// stay in the locked in position.
   253  		if !checker.EligibleToActivate(prevNode) {
   254  			log.Debugf("Moving from state=%v, to state=%v", state,
   255  				ThresholdLockedIn)
   256  
   257  			state = ThresholdLockedIn
   258  		} else {
   259  			log.Debugf("Moving from state=%v, to state=%v", state,
   260  				ThresholdActive)
   261  
   262  			// The new rule becomes active when its
   263  			// previous state was locked in assuming it's
   264  			// now eligible to activate.
   265  			state = ThresholdActive
   266  		}
   267  
   268  	// Nothing to do if the previous state is active or failed since
   269  	// they are both terminal states.
   270  	case ThresholdActive:
   271  	case ThresholdFailed:
   272  	}
   273  
   274  	return state, nil
   275  }
   276  
   277  // thresholdState returns the current rule change threshold state for the block
   278  // AFTER the given node and deployment ID.  The cache is used to ensure the
   279  // threshold states for previous windows are only calculated once.
   280  //
   281  // This function MUST be called with the chain state lock held (for writes).
   282  func (b *BlockChain) thresholdState(prevNode *blockNode, checker thresholdConditionChecker, cache *thresholdStateCache) (ThresholdState, error) {
   283  	// The threshold state for the window that contains the genesis block is
   284  	// defined by definition.
   285  	confirmationWindow := int32(checker.MinerConfirmationWindow())
   286  	if prevNode == nil || (prevNode.height+1) < confirmationWindow {
   287  		return ThresholdDefined, nil
   288  	}
   289  
   290  	// Get the ancestor that is the last block of the previous confirmation
   291  	// window in order to get its threshold state.  This can be done because
   292  	// the state is the same for all blocks within a given window.
   293  	prevNode = prevNode.Ancestor(prevNode.height -
   294  		(prevNode.height+1)%confirmationWindow)
   295  
   296  	// Iterate backwards through each of the previous confirmation windows
   297  	// to find the most recently cached threshold state.
   298  	var neededStates []*blockNode
   299  	for prevNode != nil {
   300  		// Nothing more to do if the state of the block is already
   301  		// cached.
   302  		if _, ok := cache.Lookup(&prevNode.hash); ok {
   303  			break
   304  		}
   305  
   306  		// The state is simply defined if the start time hasn't been
   307  		// been reached yet.
   308  		if !checker.HasStarted(prevNode) {
   309  			cache.Update(&prevNode.hash, ThresholdDefined)
   310  			break
   311  		}
   312  
   313  		// Add this node to the list of nodes that need the state
   314  		// calculated and cached.
   315  		neededStates = append(neededStates, prevNode)
   316  
   317  		// Get the ancestor that is the last block of the previous
   318  		// confirmation window.
   319  		prevNode = prevNode.RelativeAncestor(confirmationWindow)
   320  	}
   321  
   322  	// Start with the threshold state for the most recent confirmation
   323  	// window that has a cached state.
   324  	state := ThresholdDefined
   325  	if prevNode != nil {
   326  		var ok bool
   327  		state, ok = cache.Lookup(&prevNode.hash)
   328  		if !ok {
   329  			return ThresholdFailed, AssertError(fmt.Sprintf(
   330  				"thresholdState: cache lookup failed for %v",
   331  				prevNode.hash))
   332  		}
   333  	}
   334  
   335  	// Since each threshold state depends on the state of the previous
   336  	// window, iterate starting from the oldest unknown window.
   337  	var err error
   338  	for neededNum := len(neededStates) - 1; neededNum >= 0; neededNum-- {
   339  		prevNode := neededStates[neededNum]
   340  
   341  		// Based on the current state, the previous node, and the
   342  		// condition checker, transition to the next threshold state.
   343  		state, err = thresholdStateTransition(
   344  			state, prevNode, checker, confirmationWindow,
   345  		)
   346  		if err != nil {
   347  			return state, err
   348  		}
   349  
   350  		// Update the cache to avoid recalculating the state in the
   351  		// future.
   352  		cache.Update(&prevNode.hash, state)
   353  	}
   354  
   355  	return state, nil
   356  }
   357  
   358  // ThresholdState returns the current rule change threshold state of the given
   359  // deployment ID for the block AFTER the end of the current best chain.
   360  //
   361  // This function is safe for concurrent access.
   362  func (b *BlockChain) ThresholdState(deploymentID uint32) (ThresholdState, error) {
   363  	b.chainLock.Lock()
   364  	state, err := b.deploymentState(b.bestChain.Tip(), deploymentID)
   365  	b.chainLock.Unlock()
   366  
   367  	return state, err
   368  }
   369  
   370  // IsDeploymentActive returns true if the target deploymentID is active, and
   371  // false otherwise.
   372  //
   373  // This function is safe for concurrent access.
   374  func (b *BlockChain) IsDeploymentActive(deploymentID uint32) (bool, error) {
   375  	b.chainLock.Lock()
   376  	state, err := b.deploymentState(b.bestChain.Tip(), deploymentID)
   377  	b.chainLock.Unlock()
   378  	if err != nil {
   379  		return false, err
   380  	}
   381  
   382  	return state == ThresholdActive, nil
   383  }
   384  
   385  // deploymentState returns the current rule change threshold for a given
   386  // deploymentID. The threshold is evaluated from the point of view of the block
   387  // node passed in as the first argument to this method.
   388  //
   389  // It is important to note that, as the variable name indicates, this function
   390  // expects the block node prior to the block for which the deployment state is
   391  // desired.  In other words, the returned deployment state is for the block
   392  // AFTER the passed node.
   393  //
   394  // This function MUST be called with the chain state lock held (for writes).
   395  func (b *BlockChain) deploymentState(prevNode *blockNode, deploymentID uint32) (ThresholdState, error) {
   396  	if deploymentID > uint32(len(b.chainParams.Deployments)) {
   397  		return ThresholdFailed, DeploymentError(deploymentID)
   398  	}
   399  
   400  	deployment := &b.chainParams.Deployments[deploymentID]
   401  	checker := deploymentChecker{deployment: deployment, chain: b}
   402  	cache := &b.deploymentCaches[deploymentID]
   403  
   404  	return b.thresholdState(prevNode, checker, cache)
   405  }
   406  
   407  // initThresholdCaches initializes the threshold state caches for each warning
   408  // bit and defined deployment and provides warnings if the chain is current per
   409  // the warnUnknownRuleActivations function.
   410  func (b *BlockChain) initThresholdCaches() error {
   411  	// Initialize the warning and deployment caches by calculating the
   412  	// threshold state for each of them.  This will ensure the caches are
   413  	// populated and any states that needed to be recalculated due to
   414  	// definition changes is done now.
   415  	prevNode := b.bestChain.Tip().parent
   416  	for bit := uint32(0); bit < vbNumBits; bit++ {
   417  		checker := bitConditionChecker{bit: bit, chain: b}
   418  		cache := &b.warningCaches[bit]
   419  		_, err := b.thresholdState(prevNode, checker, cache)
   420  		if err != nil {
   421  			return err
   422  		}
   423  	}
   424  	for id := 0; id < len(b.chainParams.Deployments); id++ {
   425  		deployment := &b.chainParams.Deployments[id]
   426  		cache := &b.deploymentCaches[id]
   427  		checker := deploymentChecker{deployment: deployment, chain: b}
   428  		_, err := b.thresholdState(prevNode, checker, cache)
   429  		if err != nil {
   430  			return err
   431  		}
   432  	}
   433  
   434  	// No warnings about unknown rules until the chain is current.
   435  	if b.isCurrent() {
   436  		bestNode := b.bestChain.Tip()
   437  
   438  		// Warn if any unknown new rules are either about to activate or
   439  		// have already been activated.
   440  		if err := b.warnUnknownRuleActivations(bestNode); err != nil {
   441  			return err
   442  		}
   443  	}
   444  
   445  	return nil
   446  }