4 "github.com/bytom/vapor/consensus"
5 "github.com/bytom/vapor/consensus/segwit"
6 "github.com/bytom/vapor/protocol/bc/types"
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"`
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
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
45 // the total transaction storage gas
46 totalTxSizeGas := (int64(template.Transaction.TxData.SerializedSize) + totalWitnessSize) * consensus.ActiveNetParams.StorageGasRate
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
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,
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 {
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 {
83 return witnessSize, gas