4 "github.com/bytom/consensus"
5 "github.com/bytom/consensus/segwit"
6 "github.com/bytom/protocol/bc/types"
7 "github.com/bytom/protocol/vm/vmutil"
11 baseSize = int64(176) // inputSize(112) + outputSize(64)
12 baseP2WPKHSize = int64(98)
13 baseP2WPKHGas = int64(1409)
17 //ChainTxUtxoNum maximum utxo quantity in a tx
19 //ChainTxMergeGas chain tx gas
20 ChainTxMergeGas = uint64(10000000)
23 // EstimateTxGasInfo estimate transaction consumed gas
24 type EstimateTxGasInfo struct {
25 TotalNeu int64 `json:"total_neu"`
26 FlexibleNeu int64 `json:"flexible_neu"`
27 StorageNeu int64 `json:"storage_neu"`
28 VMNeu int64 `json:"vm_neu"`
29 ChainTxNeu int64 `json:"chain_tx_neu"`
32 func EstimateChainTxGas(templates []Template) (*EstimateTxGasInfo, error) {
33 estimated, err := EstimateTxGas(templates[len(templates)-1])
38 if len(templates) > 1 {
39 estimated.ChainTxNeu = int64(ChainTxMergeGas) * int64(len(templates)-1)
44 // EstimateTxGas estimate consumed neu for transaction
45 func EstimateTxGas(template Template) (*EstimateTxGasInfo, error) {
46 var baseP2WSHSize, totalWitnessSize, baseP2WSHGas, totalP2WPKHGas, totalP2WSHGas, totalIssueGas int64
47 for pos, input := range template.Transaction.TxData.Inputs {
48 switch input.InputType() {
49 case types.SpendInputType:
50 controlProgram := input.ControlProgram()
51 if segwit.IsP2WPKHScript(controlProgram) {
52 totalWitnessSize += baseP2WPKHSize
53 totalP2WPKHGas += baseP2WPKHGas
54 } else if segwit.IsP2WSHScript(controlProgram) {
55 baseP2WSHSize, baseP2WSHGas = estimateP2WSHGas(template.SigningInstructions[pos])
56 totalWitnessSize += baseP2WSHSize
57 totalP2WSHGas += baseP2WSHGas
60 case types.IssuanceInputType:
61 issuanceProgram := input.IssuanceProgram()
62 if height := vmutil.GetIssuanceProgramRestrictHeight(issuanceProgram); height > 0 {
63 // the gas for issue program with checking block height
66 baseIssueSize, baseIssueGas := estimateIssueGas(template.SigningInstructions[pos])
67 totalWitnessSize += baseIssueSize
68 totalIssueGas += baseIssueGas
72 flexibleGas := int64(0)
73 if totalP2WPKHGas > 0 {
74 flexibleGas += baseP2WPKHGas + (baseSize+baseP2WPKHSize)*consensus.StorageGasRate
75 } else if totalP2WSHGas > 0 {
76 flexibleGas += baseP2WSHGas + (baseSize+baseP2WSHSize)*consensus.StorageGasRate
77 } else if totalIssueGas > 0 {
78 totalIssueGas += baseP2WPKHGas
79 totalWitnessSize += baseSize + baseP2WPKHSize
82 // the total transaction storage gas
83 totalTxSizeGas := (int64(template.Transaction.TxData.SerializedSize) + totalWitnessSize) * consensus.StorageGasRate
85 // the total transaction gas is composed of storage and virtual machines
86 totalGas := totalTxSizeGas + totalP2WPKHGas + totalP2WSHGas + totalIssueGas + flexibleGas
87 return &EstimateTxGasInfo{
88 TotalNeu: totalGas * consensus.VMGasRate,
89 FlexibleNeu: flexibleGas * consensus.VMGasRate,
90 StorageNeu: totalTxSizeGas * consensus.VMGasRate,
91 VMNeu: (totalP2WPKHGas + totalP2WSHGas + totalIssueGas) * consensus.VMGasRate,
95 // estimateP2WSH return the witness size and the gas consumed to execute the virtual machine for P2WSH program
96 func estimateP2WSHGas(sigInst *SigningInstruction) (int64, int64) {
97 var witnessSize, gas int64
98 for _, witness := range sigInst.WitnessComponents {
99 switch t := witness.(type) {
100 case *SignatureWitness:
101 witnessSize += 33*int64(len(t.Keys)) + 65*int64(t.Quorum)
102 gas += 1131*int64(len(t.Keys)) + 72*int64(t.Quorum) + 659
103 if int64(len(t.Keys)) == 1 && int64(t.Quorum) == 1 {
106 case *RawTxSigWitness:
107 witnessSize += 33*int64(len(t.Keys)) + 65*int64(t.Quorum)
108 gas += 1131*int64(len(t.Keys)) + 72*int64(t.Quorum) + 659
109 if int64(len(t.Keys)) == 1 && int64(t.Quorum) == 1 {
114 return witnessSize, gas
117 // estimateIssueGas return the witness size and the gas consumed to execute the virtual machine for issuance program
118 func estimateIssueGas(sigInst *SigningInstruction) (int64, int64) {
119 var witnessSize, gas int64
120 for _, witness := range sigInst.WitnessComponents {
121 switch t := witness.(type) {
122 case *SignatureWitness:
123 witnessSize += 65 * int64(t.Quorum)
124 gas += 1065*int64(len(t.Keys)) + 72*int64(t.Quorum) + 316
125 case *RawTxSigWitness:
126 witnessSize += 65 * int64(t.Quorum)
127 gas += 1065*int64(len(t.Keys)) + 72*int64(t.Quorum) + 316
130 return witnessSize, gas