mirror of
https://github.com/btcsuite/btcd.git
synced 2024-11-19 01:40:07 +01:00
f523d4ccaa
In this commit, we fix a bug that would cause nodes to be unable to parse a given block from the wire. The block would be properly accepted if fed in via other mechanisms. The issue here is that the old checks for the maximum witness size, circa segwit v0 where placed in the wire package _as well_ as the tx engine. This check should only be in the engine, since it's properly gated by other related scrip validation flags. The fix itself is simple: limit witnesses only based on the maximum block size in bytes, or ~4MB.
118 lines
4.3 KiB
Go
118 lines
4.3 KiB
Go
// Copyright (c) 2013-2017 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package blockchain
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/btcsuite/btcd/btcutil"
|
|
"github.com/btcsuite/btcd/txscript"
|
|
"github.com/btcsuite/btcd/wire"
|
|
)
|
|
|
|
const (
|
|
// MaxBlockWeight defines the maximum block weight, where "block
|
|
// weight" is interpreted as defined in BIP0141. A block's weight is
|
|
// calculated as the sum of the of bytes in the existing transactions
|
|
// and header, plus the weight of each byte within a transaction. The
|
|
// weight of a "base" byte is 4, while the weight of a witness byte is
|
|
// 1. As a result, for a block to be valid, the BlockWeight MUST be
|
|
// less than, or equal to MaxBlockWeight.
|
|
MaxBlockWeight = 4000000
|
|
|
|
// MaxBlockBaseSize is the maximum number of bytes within a block
|
|
// which can be allocated to non-witness data.
|
|
MaxBlockBaseSize = 1000000
|
|
|
|
// MaxBlockSigOpsCost is the maximum number of signature operations
|
|
// allowed for a block. It is calculated via a weighted algorithm which
|
|
// weights segregated witness sig ops lower than regular sig ops.
|
|
MaxBlockSigOpsCost = 80000
|
|
|
|
// WitnessScaleFactor determines the level of "discount" witness data
|
|
// receives compared to "base" data. A scale factor of 4, denotes that
|
|
// witness data is 1/4 as cheap as regular non-witness data.
|
|
WitnessScaleFactor = 4
|
|
|
|
// MinTxOutputWeight is the minimum possible weight for a transaction
|
|
// output.
|
|
MinTxOutputWeight = WitnessScaleFactor * wire.MinTxOutPayload
|
|
|
|
// MaxOutputsPerBlock is the maximum number of transaction outputs there
|
|
// can be in a block of max weight size.
|
|
MaxOutputsPerBlock = MaxBlockWeight / MinTxOutputWeight
|
|
)
|
|
|
|
// GetBlockWeight computes the value of the weight metric for a given block.
|
|
// Currently the weight metric is simply the sum of the block's serialized size
|
|
// without any witness data scaled proportionally by the WitnessScaleFactor,
|
|
// and the block's serialized size including any witness data.
|
|
func GetBlockWeight(blk *btcutil.Block) int64 {
|
|
msgBlock := blk.MsgBlock()
|
|
|
|
baseSize := msgBlock.SerializeSizeStripped()
|
|
totalSize := msgBlock.SerializeSize()
|
|
|
|
// (baseSize * 3) + totalSize
|
|
return int64((baseSize * (WitnessScaleFactor - 1)) + totalSize)
|
|
}
|
|
|
|
// GetTransactionWeight computes the value of the weight metric for a given
|
|
// transaction. Currently the weight metric is simply the sum of the
|
|
// transactions's serialized size without any witness data scaled
|
|
// proportionally by the WitnessScaleFactor, and the transaction's serialized
|
|
// size including any witness data.
|
|
func GetTransactionWeight(tx *btcutil.Tx) int64 {
|
|
msgTx := tx.MsgTx()
|
|
|
|
baseSize := msgTx.SerializeSizeStripped()
|
|
totalSize := msgTx.SerializeSize()
|
|
|
|
// (baseSize * 3) + totalSize
|
|
return int64((baseSize * (WitnessScaleFactor - 1)) + totalSize)
|
|
}
|
|
|
|
// GetSigOpCost returns the unified sig op cost for the passed transaction
|
|
// respecting current active soft-forks which modified sig op cost counting.
|
|
// The unified sig op cost for a transaction is computed as the sum of: the
|
|
// legacy sig op count scaled according to the WitnessScaleFactor, the sig op
|
|
// count for all p2sh inputs scaled by the WitnessScaleFactor, and finally the
|
|
// unscaled sig op count for any inputs spending witness programs.
|
|
func GetSigOpCost(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint, bip16, segWit bool) (int, error) {
|
|
numSigOps := CountSigOps(tx) * WitnessScaleFactor
|
|
if bip16 {
|
|
numP2SHSigOps, err := CountP2SHSigOps(tx, isCoinBaseTx, utxoView)
|
|
if err != nil {
|
|
return 0, nil
|
|
}
|
|
numSigOps += (numP2SHSigOps * WitnessScaleFactor)
|
|
}
|
|
|
|
if segWit && !isCoinBaseTx {
|
|
msgTx := tx.MsgTx()
|
|
for txInIndex, txIn := range msgTx.TxIn {
|
|
// Ensure the referenced output is available and hasn't
|
|
// already been spent.
|
|
utxo := utxoView.LookupEntry(txIn.PreviousOutPoint)
|
|
if utxo == nil || utxo.IsSpent() {
|
|
str := fmt.Sprintf("output %v referenced from "+
|
|
"transaction %s:%d either does not "+
|
|
"exist or has already been spent",
|
|
txIn.PreviousOutPoint, tx.Hash(),
|
|
txInIndex)
|
|
return 0, ruleError(ErrMissingTxOut, str)
|
|
}
|
|
|
|
witness := txIn.Witness
|
|
sigScript := txIn.SignatureScript
|
|
pkScript := utxo.PkScript()
|
|
numSigOps += txscript.GetWitnessSigOpCount(sigScript, pkScript, witness)
|
|
}
|
|
|
|
}
|
|
|
|
return numSigOps, nil
|
|
}
|