github.com/btcsuite/btcd@v0.24.0/blockchain/versionbits.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  	"github.com/btcsuite/btcd/chaincfg"
     9  )
    10  
    11  const (
    12  	// vbLegacyBlockVersion is the highest legacy block version before the
    13  	// version bits scheme became active.
    14  	vbLegacyBlockVersion = 4
    15  
    16  	// vbTopBits defines the bits to set in the version to signal that the
    17  	// version bits scheme is being used.
    18  	vbTopBits = 0x20000000
    19  
    20  	// vbTopMask is the bitmask to use to determine whether or not the
    21  	// version bits scheme is in use.
    22  	vbTopMask = 0xe0000000
    23  
    24  	// vbNumBits is the total number of bits available for use with the
    25  	// version bits scheme.
    26  	vbNumBits = 29
    27  )
    28  
    29  // bitConditionChecker provides a thresholdConditionChecker which can be used to
    30  // test whether or not a specific bit is set when it's not supposed to be
    31  // according to the expected version based on the known deployments and the
    32  // current state of the chain.  This is useful for detecting and warning about
    33  // unknown rule activations.
    34  type bitConditionChecker struct {
    35  	bit   uint32
    36  	chain *BlockChain
    37  }
    38  
    39  // Ensure the bitConditionChecker type implements the thresholdConditionChecker
    40  // interface.
    41  var _ thresholdConditionChecker = bitConditionChecker{}
    42  
    43  // HasStarted returns true if based on the passed block blockNode the consensus
    44  // is eligible for deployment.
    45  //
    46  // Since this implementation checks for unknown rules, it returns true so
    47  // is always treated as active.
    48  //
    49  // This is part of the thresholdConditionChecker interface implementation.
    50  func (c bitConditionChecker) HasStarted(_ *blockNode) bool {
    51  	return true
    52  }
    53  
    54  // HasStarted returns true if based on the passed block blockNode the consensus
    55  // is eligible for deployment.
    56  //
    57  // Since this implementation checks for unknown rules, it returns false so the
    58  // rule is always treated as active.
    59  //
    60  // This is part of the thresholdConditionChecker interface implementation.
    61  func (c bitConditionChecker) HasEnded(_ *blockNode) bool {
    62  	return false
    63  }
    64  
    65  // RuleChangeActivationThreshold is the number of blocks for which the condition
    66  // must be true in order to lock in a rule change.
    67  //
    68  // This implementation returns the value defined by the chain params the checker
    69  // is associated with.
    70  //
    71  // This is part of the thresholdConditionChecker interface implementation.
    72  func (c bitConditionChecker) RuleChangeActivationThreshold() uint32 {
    73  	return c.chain.chainParams.RuleChangeActivationThreshold
    74  }
    75  
    76  // MinerConfirmationWindow is the number of blocks in each threshold state
    77  // retarget window.
    78  //
    79  // This implementation returns the value defined by the chain params the checker
    80  // is associated with.
    81  //
    82  // This is part of the thresholdConditionChecker interface implementation.
    83  func (c bitConditionChecker) MinerConfirmationWindow() uint32 {
    84  	return c.chain.chainParams.MinerConfirmationWindow
    85  }
    86  
    87  // Condition returns true when the specific bit associated with the checker is
    88  // set and it's not supposed to be according to the expected version based on
    89  // the known deployments and the current state of the chain.
    90  //
    91  // This function MUST be called with the chain state lock held (for writes).
    92  //
    93  // This is part of the thresholdConditionChecker interface implementation.
    94  func (c bitConditionChecker) Condition(node *blockNode) (bool, error) {
    95  	conditionMask := uint32(1) << c.bit
    96  	version := uint32(node.version)
    97  	if version&vbTopMask != vbTopBits {
    98  		return false, nil
    99  	}
   100  	if version&conditionMask == 0 {
   101  		return false, nil
   102  	}
   103  
   104  	expectedVersion, err := c.chain.calcNextBlockVersion(node.parent)
   105  	if err != nil {
   106  		return false, err
   107  	}
   108  	return uint32(expectedVersion)&conditionMask == 0, nil
   109  }
   110  
   111  // EligibleToActivate returns true if a custom deployment can transition from
   112  // the LockedIn to the Active state. For normal deployments, this always
   113  // returns true. However, some deployments add extra rules like a minimum
   114  // activation height, which can be abstracted into a generic arbitrary check at
   115  // the final state via this method.
   116  //
   117  // This implementation always returns true, as it's used to warn about other
   118  // unknown deployments.
   119  //
   120  // This is part of the thresholdConditionChecker interface implementation.
   121  func (c bitConditionChecker) EligibleToActivate(blkNode *blockNode) bool {
   122  	return true
   123  }
   124  
   125  // IsSpeedy returns true if this is to be a "speedy" deployment. A speedy
   126  // deployment differs from a regular one in that only after a miner block
   127  // confirmation window can the deployment expire.
   128  //
   129  // This implementation returns false, as we want to always be warned if
   130  // something is about to activate.
   131  //
   132  // This is part of the thresholdConditionChecker interface implementation.
   133  func (c bitConditionChecker) IsSpeedy() bool {
   134  	return false
   135  }
   136  
   137  // deploymentChecker provides a thresholdConditionChecker which can be used to
   138  // test a specific deployment rule.  This is required for properly detecting
   139  // and activating consensus rule changes.
   140  type deploymentChecker struct {
   141  	deployment *chaincfg.ConsensusDeployment
   142  	chain      *BlockChain
   143  }
   144  
   145  // Ensure the deploymentChecker type implements the thresholdConditionChecker
   146  // interface.
   147  var _ thresholdConditionChecker = deploymentChecker{}
   148  
   149  // HasEnded returns true if the target consensus rule change has expired
   150  // or timed out (at the next window).
   151  //
   152  // This implementation returns the value defined by the specific deployment the
   153  // checker is associated with.
   154  //
   155  // This is part of the thresholdConditionChecker interface implementation.
   156  func (c deploymentChecker) HasStarted(blkNode *blockNode) bool {
   157  	// Can't fail as we make sure to set the clock above when we
   158  	// instantiate *BlockChain.
   159  	header := blkNode.Header()
   160  	started, _ := c.deployment.DeploymentStarter.HasStarted(&header)
   161  
   162  	return started
   163  }
   164  
   165  // HasEnded returns true if the target consensus rule change has expired
   166  // or timed out.
   167  //
   168  // This implementation returns the value defined by the specific deployment the
   169  // checker is associated with.
   170  //
   171  // This is part of the thresholdConditionChecker interface implementation.
   172  func (c deploymentChecker) HasEnded(blkNode *blockNode) bool {
   173  	// Can't fail as we make sure to set the clock above when we
   174  	// instantiate *BlockChain.
   175  	header := blkNode.Header()
   176  	ended, _ := c.deployment.DeploymentEnder.HasEnded(&header)
   177  
   178  	return ended
   179  }
   180  
   181  // RuleChangeActivationThreshold is the number of blocks for which the condition
   182  // must be true in order to lock in a rule change.
   183  //
   184  // This implementation returns the value defined by the chain params the checker
   185  // is associated with.
   186  //
   187  // This is part of the thresholdConditionChecker interface implementation.
   188  func (c deploymentChecker) RuleChangeActivationThreshold() uint32 {
   189  	// Some deployments like taproot used a custom activation threshold
   190  	// that overrides the network level threshold.
   191  	if c.deployment.CustomActivationThreshold != 0 {
   192  		return c.deployment.CustomActivationThreshold
   193  	}
   194  
   195  	return c.chain.chainParams.RuleChangeActivationThreshold
   196  }
   197  
   198  // MinerConfirmationWindow is the number of blocks in each threshold state
   199  // retarget window.
   200  //
   201  // This implementation returns the value defined by the chain params the checker
   202  // is associated with.
   203  //
   204  // This is part of the thresholdConditionChecker interface implementation.
   205  func (c deploymentChecker) MinerConfirmationWindow() uint32 {
   206  	return c.chain.chainParams.MinerConfirmationWindow
   207  }
   208  
   209  // EligibleToActivate returns true if a custom deployment can transition from
   210  // the LockedIn to the Active state. For normal deployments, this always
   211  // returns true. However, some deployments add extra rules like a minimum
   212  // activation height, which can be abstracted into a generic arbitrary check at
   213  // the final state via this method.
   214  //
   215  // This implementation always returns true, unless a minimum activation height
   216  // is specified.
   217  //
   218  // This is part of the thresholdConditionChecker interface implementation.
   219  func (c deploymentChecker) EligibleToActivate(blkNode *blockNode) bool {
   220  	// No activation height, so it's always ready to go.
   221  	if c.deployment.MinActivationHeight == 0 {
   222  		return true
   223  	}
   224  
   225  	// If the _next_ block (as this is the prior block to the one being
   226  	// connected is the min height or beyond, then this can activate.
   227  	return uint32(blkNode.height)+1 >= c.deployment.MinActivationHeight
   228  }
   229  
   230  // IsSpeedy returns true if this is to be a "speedy" deployment. A speedy
   231  // deployment differs from a regular one in that only after a miner block
   232  // confirmation window can the deployment expire.  This implementation returns
   233  // true if a min activation height is set.
   234  //
   235  // This is part of the thresholdConditionChecker interface implementation.
   236  func (c deploymentChecker) IsSpeedy() bool {
   237  	return (c.deployment.MinActivationHeight != 0 ||
   238  		c.deployment.CustomActivationThreshold != 0)
   239  }
   240  
   241  // Condition returns true when the specific bit defined by the deployment
   242  // associated with the checker is set.
   243  //
   244  // This is part of the thresholdConditionChecker interface implementation.
   245  func (c deploymentChecker) Condition(node *blockNode) (bool, error) {
   246  	conditionMask := uint32(1) << c.deployment.BitNumber
   247  	version := uint32(node.version)
   248  	return (version&vbTopMask == vbTopBits) && (version&conditionMask != 0),
   249  		nil
   250  }
   251  
   252  // calcNextBlockVersion calculates the expected version of the block after the
   253  // passed previous block node based on the state of started and locked in
   254  // rule change deployments.
   255  //
   256  // This function differs from the exported CalcNextBlockVersion in that the
   257  // exported version uses the current best chain as the previous block node
   258  // while this function accepts any block node.
   259  //
   260  // This function MUST be called with the chain state lock held (for writes).
   261  func (b *BlockChain) calcNextBlockVersion(prevNode *blockNode) (int32, error) {
   262  	// Set the appropriate bits for each actively defined rule deployment
   263  	// that is either in the process of being voted on, or locked in for the
   264  	// activation at the next threshold window change.
   265  	expectedVersion := uint32(vbTopBits)
   266  	for id := 0; id < len(b.chainParams.Deployments); id++ {
   267  		deployment := &b.chainParams.Deployments[id]
   268  		cache := &b.deploymentCaches[id]
   269  		checker := deploymentChecker{deployment: deployment, chain: b}
   270  		state, err := b.thresholdState(prevNode, checker, cache)
   271  		if err != nil {
   272  			return 0, err
   273  		}
   274  		if state == ThresholdStarted || state == ThresholdLockedIn {
   275  			expectedVersion |= uint32(1) << deployment.BitNumber
   276  		}
   277  	}
   278  	return int32(expectedVersion), nil
   279  }
   280  
   281  // CalcNextBlockVersion calculates the expected version of the block after the
   282  // end of the current best chain based on the state of started and locked in
   283  // rule change deployments.
   284  //
   285  // This function is safe for concurrent access.
   286  func (b *BlockChain) CalcNextBlockVersion() (int32, error) {
   287  	b.chainLock.Lock()
   288  	version, err := b.calcNextBlockVersion(b.bestChain.Tip())
   289  	b.chainLock.Unlock()
   290  	return version, err
   291  }
   292  
   293  // warnUnknownRuleActivations displays a warning when any unknown new rules are
   294  // either about to activate or have been activated.  This will only happen once
   295  // when new rules have been activated and every block for those about to be
   296  // activated.
   297  //
   298  // This function MUST be called with the chain state lock held (for writes)
   299  func (b *BlockChain) warnUnknownRuleActivations(node *blockNode) error {
   300  	// Warn if any unknown new rules are either about to activate or have
   301  	// already been activated.
   302  	for bit := uint32(0); bit < vbNumBits; bit++ {
   303  		checker := bitConditionChecker{bit: bit, chain: b}
   304  		cache := &b.warningCaches[bit]
   305  		state, err := b.thresholdState(node.parent, checker, cache)
   306  		if err != nil {
   307  			return err
   308  		}
   309  
   310  		switch state {
   311  		case ThresholdActive:
   312  			if !b.unknownRulesWarned {
   313  				log.Warnf("Unknown new rules activated (bit %d)",
   314  					bit)
   315  				b.unknownRulesWarned = true
   316  			}
   317  
   318  		case ThresholdLockedIn:
   319  			window := int32(checker.MinerConfirmationWindow())
   320  			activationHeight := window - (node.height % window)
   321  			log.Warnf("Unknown new rules are about to activate in "+
   322  				"%d blocks (bit %d)", activationHeight, bit)
   323  		}
   324  	}
   325  
   326  	return nil
   327  }