blockchain: guard enforcement of segwit rules by a BIP0009 state check

This commit updates the new segwit validation logic within block
validation to be guarded by an initial check to the version bits state
before conditionally enforcing the logic based off of the state.
This commit is contained in:
Olaoluwa Osuntokun 2017-01-03 21:14:05 -08:00 committed by Dave Collins
parent b1893ed228
commit 728c0a4398
3 changed files with 20 additions and 19 deletions

View file

@ -249,6 +249,10 @@ func checkBlockScripts(block *btcutil.Block, utxoView *UtxoViewpoint,
scriptFlags txscript.ScriptFlags, sigCache *txscript.SigCache, scriptFlags txscript.ScriptFlags, sigCache *txscript.SigCache,
hashCache *txscript.HashCache) error { hashCache *txscript.HashCache) error {
// First determine if segwit is active according to the scriptFlags. If
// it isn't then we don't need to interact with the HashCache.
segwitActive := scriptFlags&txscript.ScriptVerifyWitness == txscript.ScriptVerifyWitness
// Collect all of the transaction inputs and required information for // Collect all of the transaction inputs and required information for
// validation for all transactions in the block into a single slice. // validation for all transactions in the block into a single slice.
numInputs := 0 numInputs := 0
@ -308,7 +312,7 @@ func checkBlockScripts(block *btcutil.Block, utxoView *UtxoViewpoint,
// If the HashCache is present, once we have validated the block, we no // If the HashCache is present, once we have validated the block, we no
// longer need the cached hashes for these transactions, so we purge // longer need the cached hashes for these transactions, so we purge
// them from the cache. // them from the cache.
if hashCache != nil { if segwitActive && hashCache != nil {
for _, tx := range block.Transactions() { for _, tx := range block.Transactions() {
hashCache.PurgeSigHashes(tx.Hash()) hashCache.PurgeSigHashes(tx.Hash())
} }

View file

@ -343,7 +343,6 @@ func (b *BlockChain) IsDeploymentActive(deploymentID uint32) (bool, error) {
// This function MUST be called with the chain state lock held (for writes). // This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) deploymentState(prevNode *blockNode, func (b *BlockChain) deploymentState(prevNode *blockNode,
deploymentID uint32) (ThresholdState, error) { deploymentID uint32) (ThresholdState, error) {
if deploymentID > uint32(len(b.chainParams.Deployments)) { if deploymentID > uint32(len(b.chainParams.Deployments)) {
return ThresholdFailed, DeploymentError(deploymentID) return ThresholdFailed, DeploymentError(deploymentID)
} }

View file

@ -537,17 +537,6 @@ func checkBlockSanity(block *btcutil.Block, powLimit *big.Int, timeSource Median
return ruleError(ErrBadMerkleRoot, str) return ruleError(ErrBadMerkleRoot, str)
} }
// Next, validate the witness commitment (if any) within the block.
// This involves asserting that if the coinbase contains the special
// commitment output, then this merkle root matches a computed merkle
// root of all the wtxid's of the transactions within the block. In
// addition, various other checks against the coinbase's witness stack.
// TODO(roasbeef): only perform this check if we expect block to have a
// witness commitment
if err := ValidateWitnessCommitment(block); err != nil {
return err
}
// Check for duplicate transactions. This check will be fairly quick // Check for duplicate transactions. This check will be fairly quick
// since the transaction hashes are already cached due to building the // since the transaction hashes are already cached due to building the
// merkle tree above. // merkle tree above.
@ -1076,8 +1065,15 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi
// after the timestamp defined by txscript.Bip16Activation. See // after the timestamp defined by txscript.Bip16Activation. See
// https://en.bitcoin.it/wiki/BIP_0016 for more details. // https://en.bitcoin.it/wiki/BIP_0016 for more details.
enforceBIP0016 := node.timestamp >= txscript.Bip16Activation.Unix() enforceBIP0016 := node.timestamp >= txscript.Bip16Activation.Unix()
// TODO(roasbeef): should check flag, consult bip 9 log etc
enforceSegWit := true // Query for the Version Bits state for the segwit soft-fork
// deployment. If segwit is active, we'll switch over to enforcing all
// the new rules.
segwitState, err := b.deploymentState(node.parent, chaincfg.DeploymentSegwit)
if err != nil {
return err
}
enforceSegWit := segwitState == ThresholdActive
// The number of signature operations must be less than the maximum // The number of signature operations must be less than the maximum
// allowed per block. Note that the preliminary sanity checks on a // allowed per block. Note that the preliminary sanity checks on a
@ -1105,7 +1101,6 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi
lastSigOpCost := totalSigOpCost lastSigOpCost := totalSigOpCost
totalSigOpCost += sigOpCost totalSigOpCost += sigOpCost
if totalSigOpCost < lastSigOpCost || totalSigOpCost > MaxBlockSigOpsCost { if totalSigOpCost < lastSigOpCost || totalSigOpCost > MaxBlockSigOpsCost {
// TODO(roasbeef): modify error
str := fmt.Sprintf("block contains too many "+ str := fmt.Sprintf("block contains too many "+
"signature operations - got %v, max %v", "signature operations - got %v, max %v",
totalSigOpCost, MaxBlockSigOpsCost) totalSigOpCost, MaxBlockSigOpsCost)
@ -1239,9 +1234,12 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi
} }
} }
// TODO(roasbeef): check bip9 for segwit here, others also // Enforce the segwit soft-fork package once the soft-fork has shifted
// into the "active" version bits state.
if enforceSegWit {
scriptFlags |= txscript.ScriptVerifyWitness scriptFlags |= txscript.ScriptVerifyWitness
scriptFlags |= txscript.ScriptStrictMultiSig scriptFlags |= txscript.ScriptStrictMultiSig
}
// Now that the inexpensive checks are done and have passed, verify the // Now that the inexpensive checks are done and have passed, verify the
// transactions are actually allowed to spend the coins by running the // transactions are actually allowed to spend the coins by running the