aergoio/aergo

View on GitHub
fee/gas.go

Summary

Maintainability
A
35 mins
Test Coverage
A
96%
package fee

import (
    "errors"
    "math"
    "math/big"
)

const (
    txGasSize      = uint64(100000)
    payloadGasSize = uint64(5)
)

func GasEnabled(version int32) bool {
    return !IsZeroFee() && version >= 2
}

//---------------------------------------------------------------//
// calc gas

// gas = fee / gas price
func CalcGas(fee, gasPrice *big.Int) *big.Int {
    return new(big.Int).Div(fee, gasPrice)
}

func ReceiptGasUsed(version int32, isGovernance bool, txFee, gasPrice *big.Int) uint64 {
    if GasEnabled(version) && !isGovernance {
        return CalcGas(txFee, gasPrice).Uint64()
    }
    return 0
}

func TxGas(payloadSize int) uint64 {
    if IsZeroFee() {
        return 0
    }
    size := paymentDataSize(int64(payloadSize))
    if size > payloadMaxSize {
        size = payloadMaxSize
    }
    txGas := txGasSize
    payloadGas := uint64(size) * payloadGasSize
    return txGas + payloadGas
}

func GasLimit(version int32, isFeeDelegation bool, txGasLimit uint64, payloadSize int, gasPrice, usedFee, senderBalance, receiverBalance *big.Int) (gasLimit uint64, err error) {
    // 1. no gas limit
    if GasEnabled(version) != true {
        return
    }

    // 2. fee delegation
    if isFeeDelegation {
        // check if the contract has enough balance for fee
        balance := new(big.Int).Sub(receiverBalance, usedFee)
        gasLimit = MaxGasLimit(balance, gasPrice)
        if gasLimit == 0 {
            err = errors.New("not enough gas")
        }
        return
    }

    // read the gas limit from the tx
    gasLimit = txGasLimit
    // 3. no gas limit specified, the limit is the sender's balance
    if gasLimit == 0 {
        balance := new(big.Int).Sub(senderBalance, usedFee)
        gasLimit = MaxGasLimit(balance, gasPrice)
        if gasLimit == 0 {
            err = errors.New("not enough gas")
        }
        return
    }

    // 4. check if the sender has enough balance for gas
    usedGas := TxGas(payloadSize)
    if gasLimit <= usedGas {
        err = errors.New("not enough gas")
        return
    }
    // subtract the used gas from the gas limit
    gasLimit -= usedGas

    return gasLimit, nil
}

func MaxGasLimit(balance, gasPrice *big.Int) uint64 {
    gasLimit := uint64(math.MaxUint64)
    if n := CalcGas(balance, gasPrice); n.IsUint64() {
        gasLimit = n.Uint64()
    }
    return gasLimit
}