weight.go raw

   1  package blockchain
   2  
   3  import (
   4  	"github.com/p9c/p9/pkg/block"
   5  	"github.com/p9c/p9/pkg/util"
   6  	"github.com/p9c/p9/pkg/wire"
   7  )
   8  
   9  const (
  10  	// MaxBlockWeight defines the maximum block weight, where "block weight" is
  11  	// interpreted as defined in BIP0141. A block's weight is calculated as the sum
  12  	// of the of bytes in the existing transactions and header, plus the weight of
  13  	// each byte within a transaction. The weight of a "base" byte is 4, while the
  14  	// weight of a witness byte is 1. As a result, for a block to be valid, the
  15  	// BlockWeight MUST be less than, or equal to MaxBlockWeight.
  16  	MaxBlockWeight = 4000000
  17  	// MaxBlockBaseSize is the maximum number of bytes within a block which can be
  18  	// allocated to non-witness data.
  19  	MaxBlockBaseSize = 1000000
  20  	// MaxBlockSigOpsCost is the maximum number of signature operations allowed for
  21  	// a block. It is calculated via a weighted algorithm which weights segregated
  22  	// witness sig ops lower than regular sig ops.
  23  	MaxBlockSigOpsCost = 80000
  24  	// WitnessScaleFactor determines the level of "discount" witness data receives
  25  	// compared to "base" data. A scale factor of 4, denotes that witness data is
  26  	// 1/4 as cheap as regular non-witness data.
  27  	WitnessScaleFactor = 4
  28  	// MinTxOutputWeight is the minimum possible weight for a transaction output.
  29  	MinTxOutputWeight = WitnessScaleFactor * wire.MinTxOutPayload
  30  	// MaxOutputsPerBlock is the maximum number of transaction outputs there can be
  31  	// in a block of max weight size.
  32  	MaxOutputsPerBlock = MaxBlockWeight / MinTxOutputWeight
  33  )
  34  
  35  // GetBlockWeight computes the value of the weight metric for a given block.
  36  // Currently the weight metric is simply the sum of the block's serialized size
  37  // without any witness data scaled proportionally by the WitnessScaleFactor, and
  38  // the block's serialized size including any witness data.
  39  func GetBlockWeight(blk *block.Block) int64 {
  40  	msgBlock := blk.WireBlock()
  41  	baseSize := msgBlock.SerializeSizeStripped()
  42  	totalSize := msgBlock.SerializeSize()
  43  	// (baseSize * 3) + totalSize
  44  	return int64((baseSize * (WitnessScaleFactor - 1)) + totalSize)
  45  }
  46  
  47  // GetTransactionWeight computes the value of the weight metric for a given
  48  // transaction. Currently the weight metric is simply the sum of the
  49  // transactions's serialized size without any witness data scaled proportionally
  50  // by the WitnessScaleFactor, and the transaction's serialized size including
  51  // any witness data.
  52  func GetTransactionWeight(tx *util.Tx) int64 {
  53  	msgTx := tx.MsgTx()
  54  	baseSize := msgTx.SerializeSizeStripped()
  55  	totalSize := msgTx.SerializeSize()
  56  	// (baseSize * 3) + totalSize
  57  	return int64((baseSize * (WitnessScaleFactor - 1)) + totalSize)
  58  }
  59  
  60  // GetSigOpCost returns the unified sig op cost for the passed transaction
  61  // respecting current active soft-forks which modified sig op cost counting. The
  62  // unified sig op cost for a transaction is computed as the sum of: the legacy
  63  // sig op count scaled according to the WitnessScaleFactor, the sig op count for
  64  // all p2sh inputs scaled by the WitnessScaleFactor, and finally the unscaled
  65  // sig op count for any inputs spending witness programs.
  66  func GetSigOpCost(tx *util.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint, bip16 bool) (int, error) {
  67  	numSigOps := CountSigOps(tx) * WitnessScaleFactor
  68  	if bip16 {
  69  		numP2SHSigOps, e := CountP2SHSigOps(tx, isCoinBaseTx, utxoView)
  70  		if e != nil {
  71  			return 0, nil
  72  		}
  73  		numSigOps += numP2SHSigOps * WitnessScaleFactor
  74  	}
  75  	// if segWit && !isCoinBaseTx {
  76  	// 	msgTx := tx.MsgTx()
  77  	// 	for txInIndex, txIn := range msgTx.TxIn {
  78  	// 		// Ensure the referenced output is available and hasn't already been spent.
  79  	// 		utxo := utxoView.LookupEntry(txIn.PreviousOutPoint)
  80  	// 		if utxo == nil || utxo.IsSpent() {
  81  	// 			str := fmt.Sprintf("output %v referenced from "+
  82  	// 				"transaction %s:%d either does not "+
  83  	// 				"exist or has already been spent",
  84  	// 				txIn.PreviousOutPoint, tx.Hash(),
  85  	// 				txInIndex)
  86  	// 			return 0, ruleError(ErrMissingTxOut, str)
  87  	// 		}
  88  	// 		witness := txIn.Witness
  89  	// 		sigScript := txIn.SignatureScript
  90  	// 		pkScript := utxo.PkScript()
  91  	// 		numSigOps += txscript.GetWitnessSigOpCount(sigScript, pkScript, witness)
  92  	// 	}
  93  	// }
  94  	return numSigOps, nil
  95  }
  96