4 "github.com/vapor/consensus"
5 "github.com/vapor/consensus/segwit"
6 "github.com/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.StorageGasRate
41 } else if totalP2WSHGas > 0 {
42 flexibleGas += baseP2WSHGas + (baseSize+baseP2WSHSize)*consensus.StorageGasRate
45 // the total transaction storage gas
46 totalTxSizeGas := (int64(template.Transaction.TxData.SerializedSize) + totalWitnessSize) * consensus.StorageGasRate
48 // the total transaction gas is composed of storage and virtual machines
49 totalGas := totalTxSizeGas + totalP2WPKHGas + totalP2WSHGas + flexibleGas
50 return &EstimateTxGasInfo{
51 TotalNeu: totalGas * consensus.VMGasRate,
52 FlexibleNeu: flexibleGas * consensus.VMGasRate,
53 StorageNeu: totalTxSizeGas * consensus.VMGasRate,
54 VMNeu: (totalP2WPKHGas + totalP2WSHGas) * consensus.VMGasRate,
58 // estimateP2WSH return the witness size and the gas consumed to execute the virtual machine for P2WSH program
59 func estimateP2WSHGas(sigInst *SigningInstruction) (int64, int64) {
60 var witnessSize, gas int64
61 for _, witness := range sigInst.WitnessComponents {
62 switch t := witness.(type) {
63 case *SignatureWitness:
64 witnessSize += 33*int64(len(t.Keys)) + 65*int64(t.Quorum)
65 gas += 1131*int64(len(t.Keys)) + 72*int64(t.Quorum) + 659
66 if int64(len(t.Keys)) == 1 && int64(t.Quorum) == 1 {
69 case *RawTxSigWitness:
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 {
77 return witnessSize, gas