Skip to content

feat: Add Gas dimension tracers #459

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 41 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
8bd2145
gas dimension tracing: initial work.
relyt29 Apr 4, 2025
836806c
gas dimension tracing: support for EXTCODECOPY. Tested by hand:
relyt29 Apr 4, 2025
5efc143
gas dimension tracing: Stop tracking previous opcode state
relyt29 Apr 4, 2025
0fad984
gas dimension tracing: dimensions for SLOAD. Tested by hand with:
relyt29 Apr 4, 2025
2e2f895
gas dimension tracing: gas emission for LOG0-4, tested by hand:
relyt29 Apr 4, 2025
b45fba8
gas dimension tracing: SELFDESTRUCT opcode implementation, needs testing
relyt29 Apr 4, 2025
a733c78
gas dimension tracing: gas emission for selfdestruct, tested by hand:
relyt29 Apr 7, 2025
fd3d6a6
gas dimension tracing: gas emission for staticcall, tested by hand
relyt29 Apr 9, 2025
9d92feb
gas dimension tracing: squash bugs, implement staticcall tested by hand:
relyt29 Apr 9, 2025
e2adfb4
gas dimension tracing: size=0 memExpansion bug, DelegateCall tests:
relyt29 Apr 9, 2025
d0c573f
gas dimension tracing: CALL opcode (untested: CALLCODE also)
relyt29 Apr 9, 2025
8e5ebc6
gas dimension tracing: CREATE and CREATE2
relyt29 Apr 9, 2025
1f0de58
gas dimension tracing: SSTORE tested, with+without refunds
relyt29 Apr 10, 2025
e2bb4a3
gas dimension tracing: live tracer use native trace, write txs to folder
relyt29 Apr 10, 2025
c95fd24
gas dimension tracing: wrap OnTxStart and OnOpcode for live tracer
relyt29 Apr 10, 2025
c1fb217
gas dimension tracing: rebase offchainlabs/go-ethereum
relyt29 Apr 10, 2025
717df87
gas dimension tracing: Rename file, tx gas dimension by opcode tracer
relyt29 Apr 10, 2025
2af6135
gas dimension tracing: by Block live tracer
relyt29 Apr 10, 2025
8ef545f
gas dimension tracing: Add live tracer: gas dimension by opcode for tx
relyt29 Apr 12, 2025
1f02a21
gas dimension tracing: save tx data to protobuf serialized format
relyt29 Apr 12, 2025
3ae51d5
gas dimension tracing: handle out of gas errors correctly
relyt29 Apr 16, 2025
990513a
gas dimension tracing: protobuf opcodes as uint32 instead of string
relyt29 Apr 16, 2025
2cdba40
gas dimension tracing: error handling on calls with out of gas
relyt29 Apr 16, 2025
376a246
gas dimension tracing: refactor shared duplicate code
relyt29 Apr 21, 2025
7b7d5d7
gas dimension tracing: small tweaks while debugging
relyt29 Apr 21, 2025
d52bcdc
gas dimension tracing: Expose accessList to tracers. Tested:
relyt29 Apr 22, 2025
e0be9a8
gas dimension tracing: directly calc access list gas for:
relyt29 Apr 23, 2025
040c007
gas dimension tracing: debug string
relyt29 Apr 30, 2025
55e0ec3
gas dimension tracing: simplify gas dimensions for SSTORE
relyt29 Apr 30, 2025
687f324
gas dimension tracing: bugfix sign error on subtraction of gas refund
relyt29 Apr 30, 2025
8759d88
gas dimension tracing: bugfix create opcode missing pass-through values
relyt29 May 5, 2025
c58481c
gas dimension tracing: Expose L1GasUsed, CallExecutionGas explicitly
relyt29 May 6, 2025
7b3188b
gas dimension tracing: handle gas refund cap adjustment
relyt29 May 7, 2025
900ffd6
gas dimension tracing: linter issues, exhaustruct on gas dimension work
relyt29 May 8, 2025
6ed73c8
gas dimension tracing: use descriptive names for tracer output
relyt29 May 9, 2025
ef1242e
gas dimension tracing: remove Println debugging statements
relyt29 May 13, 2025
9a72c37
gas dimension tracing: live trace collect insert time on per block basis
relyt29 May 13, 2025
091be2e
gas dimension tracing: handle reverts and invalid opcodes
relyt29 May 19, 2025
ca0e5ca
gas dimension tracing: improve live tracer error handling
relyt29 May 21, 2025
f116416
gas dimension tracing: fix lint
relyt29 Jun 2, 2025
23597ca
Merge branch 'master' into gas-dimension-tracing
eljobe Jun 7, 2025
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 core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2125,7 +2125,11 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them

blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
blockInsertTimer.UpdateSince(start)
insertDuration := time.Since(start)
blockInsertTimer.Update(insertDuration)
if bc.logger != nil && bc.logger.OnBlockEndMetrics != nil {
bc.logger.OnBlockEndMetrics(block.NumberU64(), insertDuration)
}

return &blockProcessingResult{usedGas: res.GasUsed, procTime: proctime, status: status}, nil
}
Expand Down
9 changes: 9 additions & 0 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -1555,6 +1555,15 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre
return s.accessList.Contains(addr, slot)
}

// GetAccessList returns the data of the access list directly for tracers to consume
// this is necessary because the accessList is not exported from the state package
func (s *StateDB) GetAccessList() (addresses map[common.Address]int, slots []map[common.Hash]struct{}) {
accessListCopy := s.accessList.Copy()
addresses = accessListCopy.addresses
slots = accessListCopy.slots
return
}

// markDelete is invoked when an account is deleted but the deletion is
// not yet committed. The pending mutation is cached and will be applied
// all together
Expand Down
4 changes: 4 additions & 0 deletions core/state/statedb_hooked.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,7 @@ func (s *hookedStateDB) GetSelfDestructs() []common.Address {
func (s *hookedStateDB) GetCurrentTxLogs() []*types.Log {
return s.inner.GetCurrentTxLogs()
}

func (s *hookedStateDB) GetAccessList() (addresses map[common.Address]int, slots []map[common.Hash]struct{}) {
return s.inner.GetAccessList()
}
6 changes: 6 additions & 0 deletions core/tracing/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ package tracing

import (
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -55,6 +56,7 @@ type StateDB interface {
GetTransientState(common.Address, common.Hash) common.Hash
Exist(common.Address) bool
GetRefund() uint64
GetAccessList() (addresses map[common.Address]int, slots []map[common.Hash]struct{})
}

// VMContext provides the context for the EVM execution.
Expand Down Expand Up @@ -136,6 +138,9 @@ type (
// BlockEndHook is called after executing a block.
BlockEndHook = func(err error)

// BlockEndMetricsHook is called after executing a block and calculating the metrics timers
BlockEndMetricsHook = func(blockNumber uint64, blockInsertDuration time.Duration)

// SkippedBlockHook indicates a block was skipped during processing
// due to it being known previously. This can happen e.g. when recovering
// from a crash.
Expand Down Expand Up @@ -210,6 +215,7 @@ type Hooks struct {
OnClose CloseHook
OnBlockStart BlockStartHook
OnBlockEnd BlockEndHook
OnBlockEndMetrics BlockEndMetricsHook
OnSkippedBlock SkippedBlockHook
OnGenesisBlock GenesisBlockHook
OnSystemCallStart OnSystemCallStartHook
Expand Down
2 changes: 2 additions & 0 deletions core/vm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ type StateDB interface {
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
// even if the feature/fork is not active yet
AddSlotToAccessList(addr common.Address, slot common.Hash)
// GetAccessList returns the access list
GetAccessList() (addresses map[common.Address]int, slots []map[common.Hash]struct{})

// PointCache returns the point cache used in computations
PointCache() *utils.PointCache
Expand Down
63 changes: 63 additions & 0 deletions eth/tracers/live/block_insert_times.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package live

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"time"

"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/eth/tracers"
)

type blockInsertTimes struct {
Path string `json:"path"`
}

func init() {
tracers.LiveDirectory.Register("blockInsertTimes", newBlockInsertTimes)
}

type blockInsertTimesConfig struct {
Path string `json:"path"` // Path to directory for output
}

func newBlockInsertTimes(cfg json.RawMessage) (*tracing.Hooks, error) {
var config blockInsertTimesConfig
if err := json.Unmarshal(cfg, &config); err != nil {
return nil, err
}

if config.Path == "" {
return nil, fmt.Errorf("gas dimension live tracer path for output is required: %v", config)
}

t := &blockInsertTimes{
Path: config.Path,
}

return &tracing.Hooks{
OnBlockEndMetrics: t.OnBlockEndMetrics,
}, nil
}

func (t *blockInsertTimes) OnBlockEndMetrics(blockNumber uint64, blockInsertDuration time.Duration) {
filename := fmt.Sprintf("%d.json", blockNumber)
filepath := filepath.Join(t.Path, filename)

// Ensure the directory exists
if err := os.MkdirAll(t.Path, 0755); err != nil {
fmt.Printf("Failed to create directory %s: %v\n", t.Path, err)
return
}

// the output is the duration in nanoseconds
var outData int64 = blockInsertDuration.Nanoseconds()

// Write the file
if err := os.WriteFile(filepath, []byte(fmt.Sprintf("%d", outData)), 0644); err != nil {
fmt.Printf("Failed to write file %s: %v\n", filepath, err)
return
}
}
Loading
Loading