OSDN Git Service

modify estimate gas (#304)
[bytom/vapor.git] / blockchain / txbuilder / estimate.go
1 package txbuilder
2
3 import (
4         "github.com/vapor/consensus"
5         "github.com/vapor/consensus/segwit"
6         "github.com/vapor/protocol/bc/types"
7 )
8
9 // EstimateTxGasInfo estimate transaction consumed gas
10 type EstimateTxGasInfo struct {
11         TotalNeu    int64 `json:"total_neu"`
12         FlexibleNeu int64 `json:"flexible_neu"`
13         StorageNeu  int64 `json:"storage_neu"`
14         VMNeu       int64 `json:"vm_neu"`
15 }
16
17 // EstimateTxGas estimate consumed neu for transaction
18 func EstimateTxGas(template Template) (*EstimateTxGasInfo, error) {
19         var baseP2WSHSize, totalWitnessSize, baseP2WSHGas, totalP2WPKHGas, totalP2WSHGas int64
20         baseSize := int64(176) // inputSize(112) + outputSize(64)
21         baseP2WPKHSize := int64(98)
22         baseP2WPKHGas := int64(1409)
23         for pos, input := range template.Transaction.TxData.Inputs {
24                 switch input.InputType() {
25                 case types.SpendInputType:
26                         controlProgram := input.ControlProgram()
27                         if segwit.IsP2WPKHScript(controlProgram) {
28                                 totalWitnessSize += baseP2WPKHSize
29                                 totalP2WPKHGas += baseP2WPKHGas
30                         } else if segwit.IsP2WSHScript(controlProgram) {
31                                 baseP2WSHSize, baseP2WSHGas = estimateP2WSHGas(template.SigningInstructions[pos])
32                                 totalWitnessSize += baseP2WSHSize
33                                 totalP2WSHGas += baseP2WSHGas
34                         }
35                 }
36         }
37
38         flexibleGas := int64(0)
39         if totalP2WPKHGas > 0 {
40                 flexibleGas += baseP2WPKHGas + (baseSize+baseP2WPKHSize)*consensus.ActiveNetParams.StorageGasRate
41         } else if totalP2WSHGas > 0 {
42                 flexibleGas += baseP2WSHGas + (baseSize+baseP2WSHSize)*consensus.ActiveNetParams.StorageGasRate
43         }
44
45         // the total transaction storage gas
46         totalTxSizeGas := (int64(template.Transaction.TxData.SerializedSize) + totalWitnessSize) * consensus.ActiveNetParams.StorageGasRate
47
48         // the total transaction gas is composed of storage and virtual machines
49         totalGas := totalTxSizeGas + totalP2WPKHGas + totalP2WSHGas + flexibleGas
50         if totalGas > consensus.ActiveNetParams.DefaultGasCredit {
51                 totalGas -= consensus.ActiveNetParams.DefaultGasCredit
52         } else {
53                 totalGas = 0
54         }
55
56         return &EstimateTxGasInfo{
57                 TotalNeu:    totalGas * consensus.ActiveNetParams.VMGasRate,
58                 FlexibleNeu: flexibleGas * consensus.ActiveNetParams.VMGasRate,
59                 StorageNeu:  totalTxSizeGas * consensus.ActiveNetParams.VMGasRate,
60                 VMNeu:       (totalP2WPKHGas + totalP2WSHGas) * consensus.ActiveNetParams.VMGasRate,
61         }, nil
62 }
63
64 // estimateP2WSH return the witness size and the gas consumed to execute the virtual machine for P2WSH program
65 func estimateP2WSHGas(sigInst *SigningInstruction) (int64, int64) {
66         var witnessSize, gas int64
67         for _, witness := range sigInst.WitnessComponents {
68                 switch t := witness.(type) {
69                 case *SignatureWitness:
70                         witnessSize += 33*int64(len(t.Keys)) + 65*int64(t.Quorum)
71                         gas += 1131*int64(len(t.Keys)) + 72*int64(t.Quorum) + 659
72                         if int64(len(t.Keys)) == 1 && int64(t.Quorum) == 1 {
73                                 gas += 27
74                         }
75                 case *RawTxSigWitness:
76                         witnessSize += 33*int64(len(t.Keys)) + 65*int64(t.Quorum)
77                         gas += 1131*int64(len(t.Keys)) + 72*int64(t.Quorum) + 659
78                         if int64(len(t.Keys)) == 1 && int64(t.Quorum) == 1 {
79                                 gas += 27
80                         }
81                 }
82         }
83         return witnessSize, gas
84 }