Skip to content
Merged
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
6 changes: 5 additions & 1 deletion pkg/ethereum/execution/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ type Receipt interface {
// TxHash returns the transaction hash.
TxHash() Hash

// GasUsed returns the gas used by the transaction.
// GasUsed returns the post-refund gas used by the transaction (what the user pays).
//
// EIP-7778 context: This remains post-refund. The EIP-7778 split between receipt gas
// and block gas only affects ExecutionResult at the EVM layer; the Receipt's GasUsed
// field and its derivation from CumulativeGasUsed are unchanged.
GasUsed() uint64
}
9 changes: 9 additions & 0 deletions pkg/ethereum/execution/structlog.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
package execution

// TraceTransaction holds the result of a debug_traceTransaction call.
type TraceTransaction struct {
// Gas is the post-refund gas used by this transaction (what the user pays).
// Set by the data source from the execution result or receipt's GasUsed.
//
// EIP-7778 context: After EIP-7778, Ethereum splits gas accounting into:
// - ReceiptGasUsed (post-refund): what the user pays, stored in receipts
// - BlockGasUsed (pre-refund): used for block gas limit accounting
// This field carries the receipt (post-refund) value. The computeIntrinsicGas()
// formula in structlog_agg depends on this being post-refund.
Gas uint64 `json:"gas"`
Failed bool `json:"failed"`
ReturnValue *string `json:"returnValue"`
Expand Down
15 changes: 10 additions & 5 deletions pkg/processor/transaction/structlog_agg/aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,12 +356,17 @@ func mapOpcodeToCallType(op string) string {
// computeIntrinsicGas computes the intrinsic gas for a transaction.
// This is the gas consumed before EVM execution begins (21000 base + calldata costs).
//
// Formula from int_transaction_call_frame.sql:
// The receiptGas parameter MUST be the post-refund value (what the user pays).
// This is the value from Receipt.GasUsed / ExecutionResult.ReceiptGasUsed.
//
// IF gas_refund >= receipt_gas / 4 THEN
// intrinsic = receipt_gas * 5 / 4 - gas_cumulative (refund was capped)
// ELSE
// intrinsic = receipt_gas - gas_cumulative + gas_refund (uncapped)
// EIP-7778 context: This formula remains correct after EIP-7778. The EIP splits
// ExecutionResult into ReceiptGasUsed (post-refund) and BlockGasUsed (pre-refund),
// but the receipt gas semantics that this formula depends on are unchanged.
//
// The computed intrinsic gas value does not encode whether the EVM refund cap
// (EIP-3529: max refund = gasUsed/5) was applied. It is up to the consumer of
// this data to determine whether the cap was hit, using the gas_refund and
// gas_used columns.
func computeIntrinsicGas(gasCumulative, gasRefund, receiptGas uint64) uint64 {
if receiptGas == 0 {
return 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func (p *Processor) ProcessTransaction(ctx context.Context, block execution.Bloc

// For simple transfers (no EVM execution), all gas is intrinsic.
// This is true for both successful and failed transactions.
// trace.Gas is the post-refund receipt gas — see TraceTransaction.Gas doc.
intrinsicGas := trace.Gas
rootFrame.IntrinsicGas = &intrinsicGas

Expand Down Expand Up @@ -158,8 +159,14 @@ func (p *Processor) ProcessTransaction(ctx context.Context, block execution.Bloc
aggregator.SetRootTargetAddress(&addr)
}

// Get receipt gas for intrinsic gas calculation
// For now, we use trace.Gas as a proxy (TODO: get actual receipt gas from block receipts)
// Get receipt gas for intrinsic gas calculation.
// trace.Gas is the post-refund receipt gas set by the data source (erigone/xatu sets
// this from ExecutionResult.ReceiptGasUsed; RPC mode gets it from receipt.GasUsed).
//
// EIP-7778 context: computeIntrinsicGas() requires the post-refund value because its
// formula accounts for refunds: intrinsic = receiptGas - gasCumulative + gasRefund.
// This is correct both pre- and post-EIP-7778 since ReceiptGasUsed preserves the
// same post-refund semantics that GasUsed had before the split.
receiptGas := trace.Gas

// Finalize aggregation and get call frame rows
Expand Down