+++ /dev/null
-package bytom
-
-import (
- "math"
-
- "github.com/vapor/claim/bytom/mainchain"
- "github.com/vapor/consensus"
- "github.com/vapor/consensus/segwit"
- "github.com/vapor/errors"
- "github.com/vapor/math/checked"
-)
-
-// EstimateTxGas estimate consumed neu for transaction
-func EstimateTxGasForMainchain(template mainchain.Template) (*EstimateTxGasResp, error) {
- // base tx size and not include sign
- data, err := template.Transaction.TxData.MarshalText()
- if err != nil {
- return nil, err
- }
- baseTxSize := int64(len(data))
-
- // extra tx size for sign witness parts
- signSize := estimateSignSizeForMainchain(template.SigningInstructions)
-
- // total gas for tx storage
- totalTxSizeGas, ok := checked.MulInt64(baseTxSize+signSize, consensus.StorageGasRate)
- if !ok {
- return nil, errors.New("calculate txsize gas got a math error")
- }
-
- // consume gas for run VM
- totalP2WPKHGas := int64(0)
- totalP2WSHGas := int64(0)
- baseP2WPKHGas := int64(1419)
-
- for pos, inpID := range template.Transaction.Tx.InputIDs {
- sp, err := template.Transaction.Spend(inpID)
- if err != nil {
- continue
- }
-
- resOut, err := template.Transaction.Output(*sp.SpentOutputId)
- if err != nil {
- continue
- }
-
- if segwit.IsP2WPKHScript(resOut.ControlProgram.Code) {
- totalP2WPKHGas += baseP2WPKHGas
- } else if segwit.IsP2WSHScript(resOut.ControlProgram.Code) {
- sigInst := template.SigningInstructions[pos]
- totalP2WSHGas += estimateP2WSHGasForMainchain(sigInst)
- }
- }
-
- // total estimate gas
- totalGas := totalTxSizeGas + totalP2WPKHGas + totalP2WSHGas
-
- // rounding totalNeu with base rate 100000
- totalNeu := float64(totalGas*consensus.VMGasRate) / defaultBaseRate
- roundingNeu := math.Ceil(totalNeu)
- estimateNeu := int64(roundingNeu) * int64(defaultBaseRate)
-
- // TODO add priority
-
- return &EstimateTxGasResp{
- TotalNeu: estimateNeu,
- StorageNeu: totalTxSizeGas * consensus.VMGasRate,
- VMNeu: (totalP2WPKHGas + totalP2WSHGas) * consensus.VMGasRate,
- }, nil
-}
-
-// estimate p2wsh gas.
-// OP_CHECKMULTISIG consume (984 * a - 72 * b - 63) gas,
-// where a represent the num of public keys, and b represent the num of quorum.
-func estimateP2WSHGasForMainchain(sigInst *mainchain.SigningInstruction) int64 {
- P2WSHGas := int64(0)
- baseP2WSHGas := int64(738)
-
- for _, witness := range sigInst.WitnessComponents {
- switch t := witness.(type) {
- case *mainchain.SignatureWitness:
- P2WSHGas += baseP2WSHGas + (984*int64(len(t.Keys)) - 72*int64(t.Quorum) - 63)
- case *mainchain.RawTxSigWitness:
- P2WSHGas += baseP2WSHGas + (984*int64(len(t.Keys)) - 72*int64(t.Quorum) - 63)
- }
- }
- return P2WSHGas
-}
-
-// estimate signature part size.
-// if need multi-sign, calculate the size according to the length of keys.
-func estimateSignSizeForMainchain(signingInstructions []*mainchain.SigningInstruction) int64 {
- signSize := int64(0)
- baseWitnessSize := int64(300)
-
- for _, sigInst := range signingInstructions {
- for _, witness := range sigInst.WitnessComponents {
- switch t := witness.(type) {
- case *mainchain.SignatureWitness:
- signSize += int64(t.Quorum) * baseWitnessSize
- case *mainchain.RawTxSigWitness:
- signSize += int64(t.Quorum) * baseWitnessSize
- }
- }
- }
- return signSize
-}