mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
122 lines
3.4 KiB
Go
122 lines
3.4 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package gas
|
|
|
|
import (
|
|
"math"
|
|
|
|
"github.com/holiman/uint256"
|
|
|
|
safemath "github.com/luxfi/math"
|
|
)
|
|
|
|
var maxUint64 = new(uint256.Int).SetUint64(math.MaxUint64)
|
|
|
|
type (
|
|
Gas uint64
|
|
Price uint64
|
|
)
|
|
|
|
// Cost converts the gas to nLUX based on the price.
|
|
//
|
|
// If overflow would occur, an error is returned.
|
|
func (g Gas) Cost(price Price) (uint64, error) {
|
|
return safemath.Mul64(uint64(g), uint64(price))
|
|
}
|
|
|
|
// AddPerSecond returns g + gasPerSecond * seconds.
|
|
//
|
|
// If overflow would occur, MaxUint64 is returned.
|
|
func (g Gas) AddPerSecond(gasPerSecond Gas, seconds uint64) Gas {
|
|
newGas, err := safemath.Mul64(uint64(gasPerSecond), seconds)
|
|
if err != nil {
|
|
return math.MaxUint64
|
|
}
|
|
totalGas, err := safemath.Add64(uint64(g), newGas)
|
|
if err != nil {
|
|
return math.MaxUint64
|
|
}
|
|
return Gas(totalGas)
|
|
}
|
|
|
|
// SubPerSecond returns g - gasPerSecond * seconds.
|
|
//
|
|
// If underflow would occur, 0 is returned.
|
|
func (g Gas) SubPerSecond(gasPerSecond Gas, seconds uint64) Gas {
|
|
gasToRemove, err := safemath.Mul64(uint64(gasPerSecond), seconds)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
totalGas, err := safemath.Sub(uint64(g), gasToRemove)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return Gas(totalGas)
|
|
}
|
|
|
|
// CalculatePrice returns the gas price given the minimum gas price, the
|
|
// excess gas, and the excess conversion constant.
|
|
//
|
|
// It is defined as an approximation of:
|
|
//
|
|
// minPrice * e^(excess / excessConversionConstant)
|
|
//
|
|
// This implements the EIP-4844 fake exponential formula:
|
|
//
|
|
// def fake_exponential(factor: int, numerator: int, denominator: int) -> int:
|
|
// i = 1
|
|
// output = 0
|
|
// numerator_accum = factor * denominator
|
|
// while numerator_accum > 0:
|
|
// output += numerator_accum
|
|
// numerator_accum = (numerator_accum * numerator) // (denominator * i)
|
|
// i += 1
|
|
// return output // denominator
|
|
//
|
|
// This implementation is optimized with the knowledge that any value greater
|
|
// than MaxUint64 gets returned as MaxUint64. This means that every intermediate
|
|
// value is guaranteed to be at most MaxUint193. So, we can safely use
|
|
// uint256.Int.
|
|
//
|
|
// This function does not perform any memory allocations.
|
|
//
|
|
//nolint:dupword // The python is copied from the EIP-4844 specification
|
|
func CalculatePrice(
|
|
minPrice Price,
|
|
excess Gas,
|
|
excessConversionConstant Gas,
|
|
) Price {
|
|
var (
|
|
numerator uint256.Int
|
|
denominator uint256.Int
|
|
|
|
i uint256.Int
|
|
output uint256.Int
|
|
numeratorAccum uint256.Int
|
|
|
|
maxOutput uint256.Int
|
|
)
|
|
numerator.SetUint64(uint64(excess)) // range is [0, MaxUint64]
|
|
denominator.SetUint64(uint64(excessConversionConstant)) // range is [0, MaxUint64]
|
|
|
|
i.SetOne()
|
|
numeratorAccum.SetUint64(uint64(minPrice)) // range is [0, MaxUint64]
|
|
numeratorAccum.Mul(&numeratorAccum, &denominator) // range is [0, MaxUint128]
|
|
|
|
maxOutput.Mul(&denominator, maxUint64) // range is [0, MaxUint128]
|
|
for numeratorAccum.Sign() > 0 {
|
|
output.Add(&output, &numeratorAccum) // range is [0, MaxUint192+MaxUint128]
|
|
if output.Cmp(&maxOutput) >= 0 {
|
|
return math.MaxUint64
|
|
}
|
|
// maxOutput < MaxUint128 so numeratorAccum < MaxUint128.
|
|
numeratorAccum.Mul(&numeratorAccum, &numerator) // range is [0, MaxUint192]
|
|
numeratorAccum.Div(&numeratorAccum, &denominator)
|
|
numeratorAccum.Div(&numeratorAccum, &i)
|
|
|
|
i.AddUint64(&i, 1)
|
|
}
|
|
return Price(output.Div(&output, &denominator).Uint64())
|
|
}
|