fee/gas.go
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
}