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 }