OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / blockchain / weight.go
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/btcsuite/btcd/txscript"
11         "github.com/btcsuite/btcutil"
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 than, 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 segragated 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 // GetBlockWeight computes the value of the weight metric for a given block.
40 // Currently the weight metric is simply the sum of the block's serialized size
41 // without any witness data scaled proportionally by the WitnessScaleFactor,
42 // and the block's serialized size including any witness data.
43 func GetBlockWeight(blk *btcutil.Block) int64 {
44         msgBlock := blk.MsgBlock()
45
46         baseSize := msgBlock.SerializeSizeStripped()
47         totalSize := msgBlock.SerializeSize()
48
49         // (baseSize * 3) + totalSize
50         return int64((baseSize * (WitnessScaleFactor - 1)) + totalSize)
51 }
52
53 // GetTransactionWeight computes the value of the weight metric for a given
54 // transaction. Currently the weight metric is simply the sum of the
55 // transactions's serialized size without any witness data scaled
56 // proportionally by the WitnessScaleFactor, and the transaction's serialized
57 // size including any witness data.
58 func GetTransactionWeight(tx *btcutil.Tx) int64 {
59         msgTx := tx.MsgTx()
60
61         baseSize := msgTx.SerializeSizeStripped()
62         totalSize := msgTx.SerializeSize()
63
64         // (baseSize * 3) + totalSize
65         return int64((baseSize * (WitnessScaleFactor - 1)) + totalSize)
66 }
67
68 // GetSigOpCost returns the unified sig op cost for the passed transaction
69 // respecting current active soft-forks which modified sig op cost counting.
70 // The unified sig op cost for a transaction is computed as the sum of: the
71 // legacy sig op count scaled according to the WitnessScaleFactor, the sig op
72 // count for all p2sh inputs scaled by the WitnessScaleFactor, and finally the
73 // unscaled sig op count for any inputs spending witness programs.
74 func GetSigOpCost(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint,
75         bip16, segWit bool) (int, error) {
76
77         numSigOps := CountSigOps(tx) * WitnessScaleFactor
78         if bip16 {
79                 numP2SHSigOps, err := CountP2SHSigOps(tx, isCoinBaseTx, utxoView)
80                 if err != nil {
81                         return 0, nil
82                 }
83                 numSigOps += (numP2SHSigOps * WitnessScaleFactor)
84         }
85
86         if segWit && !isCoinBaseTx {
87                 msgTx := tx.MsgTx()
88                 for txInIndex, txIn := range msgTx.TxIn {
89                         // Ensure the referenced input transaction is available.
90                         originTxHash := &txIn.PreviousOutPoint.Hash
91                         originTxIndex := txIn.PreviousOutPoint.Index
92                         txEntry := utxoView.LookupEntry(originTxHash)
93                         if txEntry == nil || txEntry.IsOutputSpent(originTxIndex) {
94                                 str := fmt.Sprintf("output %v referenced from "+
95                                         "transaction %s:%d either does not "+
96                                         "exist or has already been spent",
97                                         txIn.PreviousOutPoint, tx.Hash(),
98                                         txInIndex)
99                                 return 0, ruleError(ErrMissingTxOut, str)
100                         }
101
102                         witness := txIn.Witness
103                         sigScript := txIn.SignatureScript
104                         pkScript := txEntry.PkScriptByIndex(originTxIndex)
105                         numSigOps += txscript.GetWitnessSigOpCount(sigScript, pkScript, witness)
106                 }
107
108         }
109
110         return numSigOps, nil
111 }