mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-03 01:27:38 +00:00
eip-4844: data gas fees & related check (#7449)
Logic to compute fees for data blobs as well as additional check that verifies if user was willing to pay the current `data_gas` price. Updated `FakeExponential` function to work with uint256.
This commit is contained in:
parent
5a56b45b40
commit
36e70c545b
@ -791,7 +791,11 @@ func marshalReceipt(receipt *types.Receipt, txn types.Transaction, chainConfig *
|
||||
if excessDataGas == nil {
|
||||
log.Warn("excess data gas not set when trying to marshal blob tx")
|
||||
} else {
|
||||
fields["dataGasPrice"] = misc.GetDataGasPrice(excessDataGas)
|
||||
dataGasPrice, err := misc.GetDataGasPrice(excessDataGas)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
fields["dataGasPrice"] = dataGasPrice
|
||||
fields["dataGasUsed"] = misc.GetDataGasUsed(numBlobs)
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/ledgerwatch/erigon-lib/chain"
|
||||
|
||||
"github.com/ledgerwatch/erigon/core/types"
|
||||
@ -45,16 +46,33 @@ func CalcExcessDataGas(parentExcessDataGas *big.Int, newBlobs int) *big.Int {
|
||||
|
||||
// FakeExponential approximates factor * e ** (num / denom) using a taylor expansion
|
||||
// as described in the EIP-4844 spec.
|
||||
func FakeExponential(factor, num, denom *big.Int) *big.Int {
|
||||
output := new(big.Int)
|
||||
numAccum := new(big.Int).Mul(factor, denom)
|
||||
for i := 1; numAccum.Sign() > 0; i++ {
|
||||
output.Add(output, numAccum)
|
||||
numAccum.Mul(numAccum, num)
|
||||
iBig := big.NewInt(int64(i))
|
||||
numAccum.Div(numAccum, iBig.Mul(iBig, denom))
|
||||
func FakeExponential(factor, denom *uint256.Int, edg *big.Int) (*uint256.Int, error) {
|
||||
numerator, overflow := uint256.FromBig(edg)
|
||||
if overflow {
|
||||
return nil, fmt.Errorf("FakeExponential: overflow converting excessDataGas: %v", edg)
|
||||
}
|
||||
return output.Div(output, denom)
|
||||
output := uint256.NewInt(0)
|
||||
numeratorAccum := new(uint256.Int)
|
||||
_, overflow = numeratorAccum.MulOverflow(factor, denom)
|
||||
if overflow {
|
||||
return nil, fmt.Errorf("FakeExponential: overflow in MulOverflow(factor=%v, denom=%v)", factor, denom)
|
||||
}
|
||||
divisor := new(uint256.Int)
|
||||
for i := 1; numeratorAccum.Sign() > 0; i++ {
|
||||
_, overflow = output.AddOverflow(output, numeratorAccum)
|
||||
if overflow {
|
||||
return nil, fmt.Errorf("FakeExponential: overflow in AddOverflow(output=%v, numeratorAccum=%v)", output, numeratorAccum)
|
||||
}
|
||||
_, overflow = divisor.MulOverflow(denom, uint256.NewInt(uint64(i)))
|
||||
if overflow {
|
||||
return nil, fmt.Errorf("FakeExponential: overflow in MulOverflow(denom=%v, i=%v)", denom, i)
|
||||
}
|
||||
_, overflow = numeratorAccum.MulDivOverflow(numeratorAccum, numerator, divisor)
|
||||
if overflow {
|
||||
return nil, fmt.Errorf("FakeExponential: overflow in MulDivOverflow(numeratorAccum=%v, numerator=%v, divisor=%v)", numeratorAccum, numerator, divisor)
|
||||
}
|
||||
}
|
||||
return output.Div(output, denom), nil
|
||||
}
|
||||
|
||||
// CountBlobs returns the number of blob transactions in txs
|
||||
@ -75,8 +93,8 @@ func VerifyEip4844Header(config *chain.Config, parent, header *types.Header) err
|
||||
}
|
||||
|
||||
// GetDataGasPrice implements get_data_gas_price from EIP-4844
|
||||
func GetDataGasPrice(excessDataGas *big.Int) *big.Int {
|
||||
return FakeExponential(big.NewInt(params.MinDataGasPrice), excessDataGas, big.NewInt(params.DataGasPriceUpdateFraction))
|
||||
func GetDataGasPrice(excessDataGas *big.Int) (*uint256.Int, error) {
|
||||
return FakeExponential(uint256.NewInt(params.MinDataGasPrice), uint256.NewInt(params.DataGasPriceUpdateFraction), excessDataGas)
|
||||
}
|
||||
|
||||
func GetDataGasUsed(numBlobs int) uint64 {
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/ledgerwatch/erigon/params"
|
||||
)
|
||||
|
||||
@ -46,12 +47,15 @@ func TestFakeExponential(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
factor := big.NewInt(tt.factor)
|
||||
factor := uint256.NewInt(uint64(tt.factor))
|
||||
num := big.NewInt(tt.num)
|
||||
denom := big.NewInt(tt.denom)
|
||||
result := FakeExponential(factor, num, denom)
|
||||
denom := uint256.NewInt(uint64(tt.denom))
|
||||
result, err := FakeExponential(factor, denom, num)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
//t.Logf("%v*e^(%v/%v): %v", factor, num, denom, result)
|
||||
if tt.want != result.Int64() {
|
||||
if tt.want != result.ToBig().Int64() {
|
||||
t.Errorf("got %v want %v", result, tt.want)
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,10 @@ var (
|
||||
// transaction with a tip higher than the total fee cap.
|
||||
ErrTipAboveFeeCap = errors.New("tip higher than fee cap")
|
||||
|
||||
// ErrMaxFeePerDataGas is returned if the transaction specified a
|
||||
// max_fee_per_data_gas that is below the current data gas price.
|
||||
ErrMaxFeePerDataGas = errors.New("max fee per data gas too low")
|
||||
|
||||
// ErrTipVeryHigh is a sanity error to avoid extremely big numbers specified
|
||||
// in the tip field.
|
||||
ErrTipVeryHigh = errors.New("tip higher than 2^256-1")
|
||||
@ -43,6 +47,10 @@ var (
|
||||
// ErrFeeCapVeryHigh is a sanity error to avoid extremely big numbers specified
|
||||
// in the fee cap field.
|
||||
ErrFeeCapVeryHigh = errors.New("fee cap higher than 2^256-1")
|
||||
|
||||
// ErrInternalFailure is returned when an unexpected internal error condition
|
||||
// prevents execution.
|
||||
ErrInternalFailure = errors.New("internal failure")
|
||||
)
|
||||
|
||||
// List of evm-call-message pre-checking errors. All state transition messages will
|
||||
|
@ -201,6 +201,25 @@ func (st *StateTransition) buyGas(gasBailout bool) error {
|
||||
if overflow {
|
||||
return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex())
|
||||
}
|
||||
|
||||
// compute data fee for eip-4844 data blobs if any
|
||||
dgval := new(uint256.Int)
|
||||
var dataGasUsed uint64
|
||||
if st.evm.ChainRules().IsCancun {
|
||||
dataGasUsed = st.dataGasUsed()
|
||||
if st.evm.Context().ExcessDataGas == nil {
|
||||
return fmt.Errorf("%w: sharding is active but ExcessDataGas is nil", ErrInternalFailure)
|
||||
}
|
||||
dataGasPrice, err := misc.GetDataGasPrice(st.evm.Context().ExcessDataGas)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, overflow = dgval.MulOverflow(dataGasPrice, new(uint256.Int).SetUint64(dataGasUsed))
|
||||
if overflow {
|
||||
return fmt.Errorf("%w: overflow converting datagas: %v", ErrInsufficientFunds, dgval)
|
||||
}
|
||||
}
|
||||
|
||||
balanceCheck := mgval
|
||||
if st.gasFeeCap != nil {
|
||||
balanceCheck = st.sharedBuyGasBalance.SetUint64(st.msg.Gas())
|
||||
@ -212,6 +231,10 @@ func (st *StateTransition) buyGas(gasBailout bool) error {
|
||||
if overflow {
|
||||
return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex())
|
||||
}
|
||||
balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, dgval)
|
||||
if overflow {
|
||||
return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex())
|
||||
}
|
||||
}
|
||||
var subBalance = false
|
||||
if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 {
|
||||
@ -227,10 +250,15 @@ func (st *StateTransition) buyGas(gasBailout bool) error {
|
||||
}
|
||||
}
|
||||
st.gas += st.msg.Gas()
|
||||
|
||||
st.initialGas = st.msg.Gas()
|
||||
|
||||
if err := st.gp.SubDataGas(dataGasUsed); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if subBalance {
|
||||
st.state.SubBalance(st.msg.From(), mgval)
|
||||
st.state.SubBalance(st.msg.From(), dgval)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -282,6 +310,19 @@ func (st *StateTransition) preCheck(gasBailout bool) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
if st.dataGasUsed() > 0 && st.evm.ChainRules().IsCancun {
|
||||
dataGasPrice, err := misc.GetDataGasPrice(st.evm.Context().ExcessDataGas)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
maxFeePerDataGas := st.msg.MaxFeePerDataGas()
|
||||
if dataGasPrice.Cmp(maxFeePerDataGas) > 0 {
|
||||
return fmt.Errorf("%w: address %v, maxFeePerDataGas: %v dataGasPrice: %v, excessDataGas: %v",
|
||||
ErrMaxFeePerDataGas,
|
||||
st.msg.From().Hex(), st.msg.MaxFeePerDataGas(), dataGasPrice, st.evm.Context().ExcessDataGas)
|
||||
}
|
||||
}
|
||||
|
||||
return st.buyGas(gasBailout)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user