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