From f4dc820bfabf6d20670dcc2522e6ebe4b27b197c Mon Sep 17 00:00:00 2001 From: Sahil Sojitra Date: Sat, 25 Apr 2026 14:03:05 +0530 Subject: [PATCH 1/3] types: remove heap allocations from GetEffectiveGasTip --- execution/execmodule/block_building.go | 9 +++++--- execution/protocol/aa/aa_gas.go | 6 ++++-- execution/tests/blockchain_test.go | 3 ++- .../internal/tracetest/calltrace_test.go | 2 +- execution/types/aa_transaction.go | 2 +- execution/types/blob_tx_wrapper.go | 2 +- execution/types/dynamic_fee_tx.go | 2 +- execution/types/ethutils/receipt.go | 4 +++- execution/types/legacy_tx.go | 2 +- execution/types/transaction.go | 16 +++++++------- rpc/gasprice/gasprice.go | 7 ++++--- rpc/jsonrpc/otterscan_api.go | 21 +++++++++---------- 12 files changed, 43 insertions(+), 33 deletions(-) diff --git a/execution/execmodule/block_building.go b/execution/execmodule/block_building.go index 42187640cae..c7a0ae89cab 100644 --- a/execution/execmodule/block_building.go +++ b/execution/execmodule/block_building.go @@ -84,11 +84,14 @@ func (e *ExecModule) AssembleBlock(ctx context.Context, params *builder.Paramete func blockValue(br *types.BlockWithReceipts, baseFee *uint256.Int) *uint256.Int { blockValue := uint256.NewInt(0) txs := br.Block.Transactions() + var gas, txValue uint256.Int for i := range txs { - gas := new(uint256.Int).SetUint64(br.Receipts[i].GasUsed) + gas.SetUint64(br.Receipts[i].GasUsed) + effectiveTip := txs[i].GetEffectiveGasTip(baseFee) - txValue := new(uint256.Int).Mul(gas, effectiveTip) - blockValue.Add(blockValue, txValue) + + txValue.Mul(&gas, &effectiveTip) + blockValue.Add(blockValue, &txValue) } return blockValue } diff --git a/execution/protocol/aa/aa_gas.go b/execution/protocol/aa/aa_gas.go index f73acd041a1..6f053abc1e4 100644 --- a/execution/protocol/aa/aa_gas.go +++ b/execution/protocol/aa/aa_gas.go @@ -23,7 +23,8 @@ func chargeGas( preTxCost uint64, ) error { baseFee := header.BaseFee - effectiveGasPrice := new(uint256.Int).Add(baseFee, tx.GetEffectiveGasTip(baseFee)) + effectiveGasTip := tx.GetEffectiveGasTip(baseFee) + effectiveGasPrice := new(uint256.Int).Add(baseFee, &effectiveGasTip) totalGasLimit := preTxCost + tx.ValidationGasLimit + tx.PaymasterValidationGasLimit + tx.GasLimit + tx.PostOpGasLimit preCharge := new(uint256.Int).SetUint64(totalGasLimit) @@ -57,7 +58,8 @@ func refundGas( gasUsed uint64, ) error { baseFee := header.BaseFee - effectiveGasPrice := new(uint256.Int).Add(baseFee, tx.GetEffectiveGasTip(baseFee)) + effectiveGasTip := tx.GetEffectiveGasTip(baseFee) + effectiveGasPrice := new(uint256.Int).Add(baseFee, &effectiveGasTip) actualGasCost := new(uint256.Int).Mul(effectiveGasPrice, new(uint256.Int).SetUint64(gasUsed)) totalGasLimit := params.TxAAGas + tx.ValidationGasLimit + tx.PaymasterValidationGasLimit + tx.GasLimit + tx.PostOpGasLimit diff --git a/execution/tests/blockchain_test.go b/execution/tests/blockchain_test.go index 79f7bae5bcf..e29035968cc 100644 --- a/execution/tests/blockchain_test.go +++ b/execution/tests/blockchain_test.go @@ -2326,7 +2326,8 @@ func TestEIP1559Transition(t *testing.T) { err = m.DB.ViewTemporal(m.Ctx, func(tx kv.TemporalTx) error { statedb := state.New(m.NewHistoryStateReader(1, tx)) baseFee := block.BaseFee() - effectiveTip := block.Transactions()[0].GetEffectiveGasTip(baseFee).Uint64() + tip := block.Transactions()[0].GetEffectiveGasTip(baseFee) + effectiveTip := tip.Uint64() // 6+5: Ensure that miner received only the tx's effective tip. actual, err := statedb.GetBalance(accounts.InternAddress(block.Coinbase())) diff --git a/execution/tracing/tracers/internal/tracetest/calltrace_test.go b/execution/tracing/tracers/internal/tracetest/calltrace_test.go index 86541054187..442339c654b 100644 --- a/execution/tracing/tracers/internal/tracetest/calltrace_test.go +++ b/execution/tracing/tracers/internal/tracetest/calltrace_test.go @@ -279,7 +279,7 @@ func benchTracer(b *testing.B, tracerName string, test *callTracerTest) { baseFee := test.Context.BaseFee txContext := evmtypes.TxContext{ Origin: origin, - GasPrice: *tx.GetEffectiveGasTip(baseFee), + GasPrice: tx.GetEffectiveGasTip(baseFee), } m := execmoduletester.New(b) dbTx, err := m.DB.BeginTemporalRw(m.Ctx) diff --git a/execution/types/aa_transaction.go b/execution/types/aa_transaction.go index 137a9a689ba..2658a1989c5 100644 --- a/execution/types/aa_transaction.go +++ b/execution/types/aa_transaction.go @@ -106,7 +106,7 @@ func (tx *AccountAbstractionTransaction) GetPrice() *uint256.Int { return tx.Tip } -func (tx *AccountAbstractionTransaction) GetEffectiveGasTip(baseFee *uint256.Int) *uint256.Int { +func (tx *AccountAbstractionTransaction) GetEffectiveGasTip(baseFee *uint256.Int) uint256.Int { return CalcEffectiveGasTip(baseFee, tx.GetTipCap, tx.GetFeeCap) } diff --git a/execution/types/blob_tx_wrapper.go b/execution/types/blob_tx_wrapper.go index 90fb0f4edcd..5a85e399a4a 100644 --- a/execution/types/blob_tx_wrapper.go +++ b/execution/types/blob_tx_wrapper.go @@ -276,7 +276,7 @@ func (txw *BlobTxWrapper) Type() byte { return txw.Tx.Type() } func (txw *BlobTxWrapper) GetChainID() *uint256.Int { return txw.Tx.GetChainID() } func (txw *BlobTxWrapper) GetNonce() uint64 { return txw.Tx.GetNonce() } func (txw *BlobTxWrapper) GetTipCap() *uint256.Int { return txw.Tx.GetTipCap() } -func (txw *BlobTxWrapper) GetEffectiveGasTip(baseFee *uint256.Int) *uint256.Int { +func (txw *BlobTxWrapper) GetEffectiveGasTip(baseFee *uint256.Int) uint256.Int { return txw.Tx.GetEffectiveGasTip(baseFee) } func (txw *BlobTxWrapper) GetFeeCap() *uint256.Int { return txw.Tx.GetFeeCap() } diff --git a/execution/types/dynamic_fee_tx.go b/execution/types/dynamic_fee_tx.go index 68437a61207..2b508b8992d 100644 --- a/execution/types/dynamic_fee_tx.go +++ b/execution/types/dynamic_fee_tx.go @@ -42,7 +42,7 @@ type DynamicFeeTransaction struct { func (tx *DynamicFeeTransaction) GetFeeCap() *uint256.Int { return &tx.FeeCap } func (tx *DynamicFeeTransaction) GetTipCap() *uint256.Int { return &tx.TipCap } -func (tx *DynamicFeeTransaction) GetEffectiveGasTip(baseFee *uint256.Int) *uint256.Int { +func (tx *DynamicFeeTransaction) GetEffectiveGasTip(baseFee *uint256.Int) uint256.Int { return CalcEffectiveGasTip(baseFee, tx.GetTipCap, tx.GetFeeCap) } diff --git a/execution/types/ethutils/receipt.go b/execution/types/ethutils/receipt.go index a1050e0e1e4..55563caba60 100644 --- a/execution/types/ethutils/receipt.go +++ b/execution/types/ethutils/receipt.go @@ -97,7 +97,9 @@ func MarshalReceipt( fields["effectiveGasPrice"] = (*hexutil.Big)(txn.GetTipCap().ToBig()) } else { baseFee := header.BaseFee - gasPrice := new(uint256.Int).Add(baseFee, txn.GetEffectiveGasTip(baseFee)) + effectiveTip := txn.GetEffectiveGasTip(baseFee) + var gasPrice uint256.Int + gasPrice.Add(baseFee, &effectiveTip) fields["effectiveGasPrice"] = (*hexutil.Big)(gasPrice.ToBig()) } diff --git a/execution/types/legacy_tx.go b/execution/types/legacy_tx.go index b4ed1a987df..ce72b24aec4 100644 --- a/execution/types/legacy_tx.go +++ b/execution/types/legacy_tx.go @@ -116,7 +116,7 @@ type LegacyTx struct { func (tx *LegacyTx) GetTipCap() *uint256.Int { return &tx.GasPrice } func (tx *LegacyTx) GetFeeCap() *uint256.Int { return &tx.GasPrice } -func (tx *LegacyTx) GetEffectiveGasTip(baseFee *uint256.Int) *uint256.Int { +func (tx *LegacyTx) GetEffectiveGasTip(baseFee *uint256.Int) uint256.Int { return CalcEffectiveGasTip(baseFee, tx.GetTipCap, tx.GetFeeCap) } diff --git a/execution/types/transaction.go b/execution/types/transaction.go index 2431fcbbb7d..495966c738b 100644 --- a/execution/types/transaction.go +++ b/execution/types/transaction.go @@ -63,7 +63,7 @@ type Transaction interface { GetChainID() *uint256.Int GetNonce() uint64 GetTipCap() *uint256.Int // max_priority_fee_per_gas in EIP-1559 - GetEffectiveGasTip(baseFee *uint256.Int) *uint256.Int // effective_gas_price in EIP-1559 + GetEffectiveGasTip(baseFee *uint256.Int) uint256.Int // effective_gas_price in EIP-1559 GetFeeCap() *uint256.Int // max_fee_per_gas in EIP-1559 GetBlobHashes() []common.Hash GetGasLimit() uint64 @@ -108,17 +108,19 @@ type TransactionMisc struct { // CalcEffectiveGasTip computes the effective gas tip given a transaction's tip/fee caps and a base fee. // Shared logic used by all transaction types that implement GetEffectiveGasTip. -func CalcEffectiveGasTip(baseFee *uint256.Int, getTipCap func() *uint256.Int, getFeeCap func() *uint256.Int) *uint256.Int { +func CalcEffectiveGasTip(baseFee *uint256.Int, getTipCap func() *uint256.Int, getFeeCap func() *uint256.Int) uint256.Int { if baseFee == nil { - return getTipCap() + return *getTipCap() } gasFeeCap := getFeeCap() if gasFeeCap.Lt(baseFee) { - return uint256.NewInt(0) + var zero uint256.Int + return zero } - effectiveFee := new(uint256.Int).Sub(gasFeeCap, baseFee) - if getTipCap().Lt(effectiveFee) { - return getTipCap() + var effectiveFee uint256.Int + effectiveFee.Sub(gasFeeCap, baseFee) + if getTipCap().Lt(&effectiveFee) { + return *getTipCap() } return effectiveFee } diff --git a/rpc/gasprice/gasprice.go b/rpc/gasprice/gasprice.go index 34711f6a035..08cc53dc45b 100644 --- a/rpc/gasprice/gasprice.go +++ b/rpc/gasprice/gasprice.go @@ -294,7 +294,7 @@ func (oracle *Oracle) getBlockPricesFromBackend(ctx context.Context, backend Ora // Pre-compute effective tip for every transaction exactly once. type txWithTip struct { tx types.Transaction - tip *uint256.Int + tip uint256.Int } items := make([]txWithTip, len(block.Transactions())) for i, tx := range block.Transactions() { @@ -302,7 +302,7 @@ func (oracle *Oracle) getBlockPricesFromBackend(ctx context.Context, backend Ora } // Sort ascending by effective tip; slices.SortFunc uses pdqsort (no reflection). - slices.SortFunc(items, func(a, b txWithTip) int { return a.tip.Cmp(b.tip) }) + slices.SortFunc(items, func(a, b txWithTip) int { return a.tip.Cmp(&b.tip) }) // Since items are sorted ascending, all tips below ignoreUnder form a // contiguous prefix that we can skip with a single pass. @@ -320,7 +320,8 @@ func (oracle *Oracle) getBlockPricesFromBackend(ctx context.Context, backend Ora } sender, _ := item.tx.GetSender() if sender.Value() != coinbase { - *out = append(*out, item.tip) + tipCopy := new(uint256.Int).Set(&item.tip) + *out = append(*out, tipCopy) count++ } } diff --git a/rpc/jsonrpc/otterscan_api.go b/rpc/jsonrpc/otterscan_api.go index 8c55626296e..5f02b9619fd 100644 --- a/rpc/jsonrpc/otterscan_api.go +++ b/rpc/jsonrpc/otterscan_api.go @@ -309,27 +309,26 @@ func delegateIssuance(tx kv.Tx, block *types.Block, chainConfig *chain.Config, e } func delegateBlockFees(ctx context.Context, tx kv.Tx, block *types.Block, senders []common.Address, chainConfig *chain.Config, receipts types.Receipts) (*big.Int, error) { - fee := big.NewInt(0) - gasUsed := big.NewInt(0) + var fee, gasUsed, totalFees uint256.Int + isLondon := chainConfig.IsLondon(block.NumberU64()) + baseFee := block.BaseFee() - totalFees := big.NewInt(0) for _, receipt := range receipts { txn := block.Transactions()[receipt.TransactionIndex] - if !chainConfig.IsLondon(block.NumberU64()) { - fee.Set(txn.GetTipCap().ToBig()) + if !isLondon { + fee.Set(txn.GetTipCap()) } else { - baseFee := block.BaseFee() - gasPrice := new(uint256.Int).Add(baseFee, txn.GetEffectiveGasTip(baseFee)) - fee.Set(gasPrice.ToBig()) + effectiveTip := txn.GetEffectiveGasTip(baseFee) + fee.Add(baseFee, &effectiveTip) } gasUsed.SetUint64(receipt.GasUsed) - fee.Mul(fee, gasUsed) + fee.Mul(&fee, &gasUsed) - totalFees.Add(totalFees, fee) + totalFees.Add(&totalFees, &fee) } - return totalFees, nil + return totalFees.ToBig(), nil } func (api *OtterscanAPIImpl) getBlockWithSenders(ctx context.Context, number rpc.BlockNumber, tx kv.Tx) (*types.Block, []common.Address, error) { From 52483c8df258943219be4d0b25234d12c24c2ec1 Mon Sep 17 00:00:00 2001 From: Sahil Sojitra Date: Sat, 25 Apr 2026 14:40:00 +0530 Subject: [PATCH 2/3] fix lint --- execution/execmodule/block_building.go | 2 +- execution/types/transaction.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/execution/execmodule/block_building.go b/execution/execmodule/block_building.go index c7a0ae89cab..40d6d00601c 100644 --- a/execution/execmodule/block_building.go +++ b/execution/execmodule/block_building.go @@ -87,7 +87,7 @@ func blockValue(br *types.BlockWithReceipts, baseFee *uint256.Int) *uint256.Int var gas, txValue uint256.Int for i := range txs { gas.SetUint64(br.Receipts[i].GasUsed) - + effectiveTip := txs[i].GetEffectiveGasTip(baseFee) txValue.Mul(&gas, &effectiveTip) diff --git a/execution/types/transaction.go b/execution/types/transaction.go index 495966c738b..1b1a049b126 100644 --- a/execution/types/transaction.go +++ b/execution/types/transaction.go @@ -62,9 +62,9 @@ type Transaction interface { Type() byte GetChainID() *uint256.Int GetNonce() uint64 - GetTipCap() *uint256.Int // max_priority_fee_per_gas in EIP-1559 + GetTipCap() *uint256.Int // max_priority_fee_per_gas in EIP-1559 GetEffectiveGasTip(baseFee *uint256.Int) uint256.Int // effective_gas_price in EIP-1559 - GetFeeCap() *uint256.Int // max_fee_per_gas in EIP-1559 + GetFeeCap() *uint256.Int // max_fee_per_gas in EIP-1559 GetBlobHashes() []common.Hash GetGasLimit() uint64 GetBlobGas() uint64 From 6e3186b07425624dc6dc54a9b8d13b76d2daee76 Mon Sep 17 00:00:00 2001 From: yperbasis Date: Thu, 30 Apr 2026 09:32:43 +0200 Subject: [PATCH 3/3] types: fix EIP-1559 reference in GetEffectiveGasTip comment GetEffectiveGasTip returns min(tipCap, feeCap-baseFee), i.e. priority_fee_per_gas in EIP-1559 terminology, not effective_gas_price (which is baseFee+tip). Co-Authored-By: Claude Opus 4.7 (1M context) --- execution/types/transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/execution/types/transaction.go b/execution/types/transaction.go index 1b1a049b126..7f452124b59 100644 --- a/execution/types/transaction.go +++ b/execution/types/transaction.go @@ -63,7 +63,7 @@ type Transaction interface { GetChainID() *uint256.Int GetNonce() uint64 GetTipCap() *uint256.Int // max_priority_fee_per_gas in EIP-1559 - GetEffectiveGasTip(baseFee *uint256.Int) uint256.Int // effective_gas_price in EIP-1559 + GetEffectiveGasTip(baseFee *uint256.Int) uint256.Int // priority_fee_per_gas in EIP-1559 GetFeeCap() *uint256.Int // max_fee_per_gas in EIP-1559 GetBlobHashes() []common.Hash GetGasLimit() uint64