6f5311d7c6
Co-authored-by: Brannon King <countprimes@gmail.com>
117 lines
4.3 KiB
Go
117 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/lbryio/lbcd/txscript"
|
|
"github.com/lbryio/lbcd/wire"
|
|
btcutil "github.com/lbryio/lbcutil"
|
|
)
|
|
|
|
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 = 8000000
|
|
|
|
// MaxBlockBaseSize is the maximum number of bytes within a block
|
|
// which can be allocated to non-witness data.
|
|
MaxBlockBaseSize = 8000000
|
|
|
|
// 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
|
|
}
|