github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/btcutil/blockchain/weight.go (about)

     1  // Copyright (c) 2013-2016 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  
    10  	"github.com/mit-dci/lit/btcutil"
    11  	"github.com/mit-dci/lit/btcutil/txscript"
    12  )
    13  
    14  const (
    15  	// MaxBlockWeight defines the maximum block weight, where "block
    16  	// weight" is interpreted as defined in BIP0141. A block's weight is
    17  	// calculated as the sum of the of bytes in the existing transactions
    18  	// and header, plus the weight of each byte within a transaction. The
    19  	// weight of a "base" byte is 4, while the weight of a witness byte is
    20  	// 1. As a result, for a block to be valid, the BlockWeight MUST be
    21  	// less then, or equal to MaxBlockWeight.
    22  	MaxBlockWeight = 4000000
    23  
    24  	// MaxBlockBaseSize is the maximum number of bytes within a block
    25  	// which can be allocated to non-witness data.
    26  	MaxBlockBaseSize = 1000000
    27  
    28  	// MaxBlockSigOpsCost is the maximum number of signature operations
    29  	// allowed for a block. It is calculated via a weighted algorithm which
    30  	// weights segregated witness sig ops lower than regular sig ops.
    31  	MaxBlockSigOpsCost = 80000
    32  
    33  	// WitnessScaleFactor determines the level of "discount" witness data
    34  	// receives compared to "base" data. A scale factor of 4, denotes that
    35  	// witness data is 1/4 as cheap as regular non-witness data.
    36  	WitnessScaleFactor = 4
    37  )
    38  
    39  // TxVirtualSize computes the virtual size of a given transaction. A
    40  // transaction's virtual is based off it's weight, creating a discount for any
    41  // witness data it contains, proportional to the current WitnessScaleFactor
    42  // value.
    43  func GetTxVirtualSize(tx *btcutil.Tx) int64 {
    44  	// vSize := (weight(tx) + 3) / 4
    45  	//       := (((baseSize * 3) + totalSize) + 3) / 4
    46  	// We add 3 here as a way to compute the ceiling of the prior arithmetic
    47  	// to 4. The division by 4 creates a discount for wit witness data.
    48  	return (GetTransactionWeight(tx) + (WitnessScaleFactor - 1)) /
    49  		WitnessScaleFactor
    50  }
    51  
    52  // GetBlockWeight computes the value of the weight metric for a given block.
    53  // Currently the weight metric is simply the sum of the block's serialized size
    54  // without any witness data scaled proportionally by the WitnessScaleFactor,
    55  // and the block's serialized size including any witness data.
    56  func GetBlockWeight(blk *btcutil.Block) int64 {
    57  	msgBlock := blk.MsgBlock()
    58  
    59  	baseSize := msgBlock.SerializeSizeStripped()
    60  	totalSize := msgBlock.SerializeSize()
    61  
    62  	// (baseSize * 3) + totalSize
    63  	return int64((baseSize * (WitnessScaleFactor - 1)) + totalSize)
    64  }
    65  
    66  // GetTransactionWeight computes the value of the weight metric for a given
    67  // transaction. Currently the weight metric is simply the sum of the
    68  // transactions's serialized size without any witness data scaled
    69  // proportionally by the WitnessScaleFactor, and the transaction's serialized
    70  // size including any witness data.
    71  func GetTransactionWeight(tx *btcutil.Tx) int64 {
    72  	msgTx := tx.MsgTx()
    73  
    74  	baseSize := msgTx.SerializeSizeStripped()
    75  	totalSize := msgTx.SerializeSize()
    76  
    77  	// (baseSize * 3) + totalSize
    78  	return int64((baseSize * (WitnessScaleFactor - 1)) + totalSize)
    79  }
    80  
    81  // GetSigOpCost returns the unified sig op cost for the passed transaction
    82  // respecting current active soft-forks which modified sig op cost counting.
    83  // The unified sig op cost for a transaction is computed as the sum of: the
    84  // legacy sig op count scaled according to the WitnessScaleFactor, the sig op
    85  // count for all p2sh inputs scaled by the WitnessScaleFactor, and finally the
    86  // unscaled sig op count for any inputs spending witness programs.
    87  func GetSigOpCost(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint,
    88  	bip16, segWit bool) (int, error) {
    89  
    90  	numSigOps := CountSigOps(tx) * WitnessScaleFactor
    91  	if bip16 {
    92  		numP2SHSigOps, err := CountP2SHSigOps(tx, isCoinBaseTx, utxoView)
    93  		if err != nil {
    94  			return 0, nil
    95  		}
    96  		numSigOps += (numP2SHSigOps * WitnessScaleFactor)
    97  	}
    98  
    99  	if segWit && !isCoinBaseTx {
   100  		msgTx := tx.MsgTx()
   101  		for txInIndex, txIn := range msgTx.TxIn {
   102  			// Ensure the referenced input transaction is available.
   103  			originTxHash := &txIn.PreviousOutPoint.Hash
   104  			originTxIndex := txIn.PreviousOutPoint.Index
   105  			txEntry := utxoView.LookupEntry(originTxHash)
   106  			if txEntry == nil || txEntry.IsOutputSpent(originTxIndex) {
   107  				str := fmt.Sprintf("unable to find unspent output "+
   108  					"%v referenced from transaction %s:%d",
   109  					txIn.PreviousOutPoint, tx.Hash(), txInIndex)
   110  				return 0, ruleError(ErrMissingTx, str)
   111  			}
   112  
   113  			witness := txIn.Witness
   114  			sigScript := txIn.SignatureScript
   115  			pkScript := txEntry.PkScriptByIndex(originTxIndex)
   116  
   117  			numSigOps += txscript.GetWitnessSigOpCount(sigScript, pkScript, witness)
   118  		}
   119  
   120  	}
   121  
   122  	return numSigOps, nil
   123  }