Skip to content

core/types: Add allocation-free EffectiveGasTipInto method #31598

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 23 additions & 16 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,44 +355,51 @@ func (tx *Transaction) GasTipCapIntCmp(other *big.Int) int {
// Note: if the effective gasTipCap is negative, this method returns both error
// the actual negative value, _and_ ErrGasFeeCapTooLow
func (tx *Transaction) EffectiveGasTip(baseFee *big.Int) (*big.Int, error) {
dst := new(big.Int)
err := tx.effectiveGasTipInto(dst, baseFee)
return dst, err
}

func (tx *Transaction) effectiveGasTipInto(dst *big.Int, baseFee *big.Int) error {
if baseFee == nil {
return tx.GasTipCap(), nil
dst.Set(tx.inner.gasTipCap())
return nil
}

var err error
gasFeeCap := tx.GasFeeCap()
gasFeeCap := tx.inner.gasFeeCap()
if gasFeeCap.Cmp(baseFee) < 0 {
err = ErrGasFeeCapTooLow
}
gasFeeCap = gasFeeCap.Sub(gasFeeCap, baseFee)

gasTipCap := tx.GasTipCap()
if gasTipCap.Cmp(gasFeeCap) < 0 {
return gasTipCap, err
dst.Sub(gasFeeCap, baseFee)
gasTipCap := tx.inner.gasTipCap()
if gasTipCap.Cmp(dst) < 0 {
dst.Set(gasTipCap)
}
return gasFeeCap, err
}

// EffectiveGasTipValue is identical to EffectiveGasTip, but does not return an
// error in case the effective gasTipCap is negative
func (tx *Transaction) EffectiveGasTipValue(baseFee *big.Int) *big.Int {
effectiveTip, _ := tx.EffectiveGasTip(baseFee)
return effectiveTip
return err
}

// EffectiveGasTipCmp compares the effective gasTipCap of two transactions assuming the given base fee.
func (tx *Transaction) EffectiveGasTipCmp(other *Transaction, baseFee *big.Int) int {
if baseFee == nil {
return tx.GasTipCapCmp(other)
}
return tx.EffectiveGasTipValue(baseFee).Cmp(other.EffectiveGasTipValue(baseFee))
txTip := new(big.Int)
otherTip := new(big.Int)
tx.effectiveGasTipInto(txTip, baseFee)
other.effectiveGasTipInto(otherTip, baseFee)
return txTip.Cmp(otherTip)
}

// EffectiveGasTipIntCmp compares the effective gasTipCap of a transaction to the given gasTipCap.
func (tx *Transaction) EffectiveGasTipIntCmp(other *big.Int, baseFee *big.Int) int {
if baseFee == nil {
return tx.GasTipCapIntCmp(other)
}
return tx.EffectiveGasTipValue(baseFee).Cmp(other)
txTip := new(big.Int)
tx.effectiveGasTipInto(txTip, baseFee)
return txTip.Cmp(other)
}

// BlobGas returns the blob gas limit of the transaction for blob transactions, 0 otherwise.
Expand Down
99 changes: 99 additions & 0 deletions core/types/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)

Expand Down Expand Up @@ -593,3 +594,101 @@ func BenchmarkHash(b *testing.B) {
signer.Hash(tx)
}
}

func BenchmarkEffectiveGasTip(b *testing.B) {
signer := LatestSigner(params.TestChainConfig)
key, _ := crypto.GenerateKey()
txdata := &DynamicFeeTx{
ChainID: big.NewInt(1),
Nonce: 0,
GasTipCap: big.NewInt(2000000000),
GasFeeCap: big.NewInt(3000000000),
Gas: 21000,
To: &common.Address{},
Value: big.NewInt(0),
Data: nil,
}
tx, _ := SignNewTx(key, signer, txdata)
baseFee := big.NewInt(1000000000) // 1 gwei

b.Run("Original", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, err := tx.EffectiveGasTip(baseFee)
if err != nil {
b.Fatal(err)
}
}
})

b.Run("IntoMethod", func(b *testing.B) {
b.ReportAllocs()
dst := new(big.Int)
for i := 0; i < b.N; i++ {
err := tx.effectiveGasTipInto(dst, baseFee)
if err != nil {
b.Fatal(err)
}
}
})
}

func TestEffectiveGasTipInto(t *testing.T) {
signer := LatestSigner(params.TestChainConfig)
key, _ := crypto.GenerateKey()

testCases := []struct {
tipCap int64
feeCap int64
baseFee *int64
}{
{tipCap: 1, feeCap: 100, baseFee: intPtr(50)},
{tipCap: 10, feeCap: 100, baseFee: intPtr(50)},
{tipCap: 50, feeCap: 100, baseFee: intPtr(50)},
{tipCap: 100, feeCap: 100, baseFee: intPtr(50)},
{tipCap: 1, feeCap: 50, baseFee: intPtr(50)},
{tipCap: 1, feeCap: 20, baseFee: intPtr(50)}, // Base fee higher than fee cap
{tipCap: 50, feeCap: 100, baseFee: intPtr(0)},
{tipCap: 50, feeCap: 100, baseFee: nil}, // nil base fee
}

for i, tc := range testCases {
txdata := &DynamicFeeTx{
ChainID: big.NewInt(1),
Nonce: 0,
GasTipCap: big.NewInt(tc.tipCap),
GasFeeCap: big.NewInt(tc.feeCap),
Gas: 21000,
To: &common.Address{},
Value: big.NewInt(0),
Data: nil,
}
tx, _ := SignNewTx(key, signer, txdata)

var baseFee *big.Int
if tc.baseFee != nil {
baseFee = big.NewInt(*tc.baseFee)
}

// Get result from original method
orig, origErr := tx.EffectiveGasTip(baseFee)

// Get result from new method
dst := new(big.Int)
newErr := tx.effectiveGasTipInto(dst, baseFee)

// Compare results
if (origErr != nil) != (newErr != nil) {
t.Fatalf("case %d: error mismatch: orig %v, new %v", i, origErr, newErr)
}

if orig.Cmp(dst) != 0 {
t.Fatalf("case %d: result mismatch: orig %v, new %v", i, orig, dst)
}
}
}

// Helper function to create integer pointer
func intPtr(i int64) *int64 {
return &i
}
3 changes: 2 additions & 1 deletion eth/tracers/js/goja.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,8 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from
t.activePrecompiles = vm.ActivePrecompiles(rules)
t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64())
t.ctx["gas"] = t.vm.ToValue(tx.Gas())
gasPriceBig, err := t.toBig(t.vm, tx.EffectiveGasTipValue(env.BaseFee).String())
gasTip, _ := tx.EffectiveGasTip(env.BaseFee)
gasPriceBig, err := t.toBig(t.vm, gasTip.String())
if err != nil {
t.err = err
return
Expand Down