Skip to content

Commit d25b158

Browse files
committed
gas dimension tracing: write disk in sync batches, access list tracer
This commit deletes the async vibe coded solution for writing transactions to disk in favor of writing them to disk synchronously in batches of 1000 instead. It also replaces calls out to the statedb in favor of using the logger.AccessListTracer which maintains a duplicate parallel copy of the access list but also stores it in a map for faster lookup. Hopefully these efforts help performance of the live tracer to stay synced to the tip of the chain :(
1 parent 0e86b86 commit d25b158

9 files changed

+370
-363
lines changed

eth/tracers/live/tx_gas_dimension.go

Lines changed: 170 additions & 162 deletions
Large diffs are not rendered by default.

eth/tracers/live/tx_gas_dimension_test.go

Lines changed: 0 additions & 136 deletions
This file was deleted.

eth/tracers/logger/access_list_tracer.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ func (al accessList) addAddress(address common.Address) {
4646
}
4747
}
4848

49+
// hasAddress checks if an address is in the accesslist.
50+
func (al accessList) hasAddress(address common.Address) bool {
51+
_, ok := al[address]
52+
return ok
53+
}
54+
4955
// addSlot adds a storage slot to the accesslist.
5056
func (al accessList) addSlot(address common.Address, slot common.Hash) {
5157
// Set address if not previously present
@@ -55,6 +61,12 @@ func (al accessList) addSlot(address common.Address, slot common.Hash) {
5561
al[address][slot] = struct{}{}
5662
}
5763

64+
// hasSlot checks if a storage slot is in the accesslist.
65+
func (al accessList) hasSlot(address common.Address, slot common.Hash) bool {
66+
_, ok := al[address][slot]
67+
return ok
68+
}
69+
5870
// equal checks if the content of the current access list is the same as the
5971
// content of the other one.
6072
func (al accessList) equal(other accessList) bool {
@@ -157,3 +169,13 @@ func (a *AccessListTracer) AccessList() types.AccessList {
157169
func (a *AccessListTracer) Equal(other *AccessListTracer) bool {
158170
return a.list.equal(other.list)
159171
}
172+
173+
// HasAddress checks if an address is in the accesslist.
174+
func (a *AccessListTracer) HasAddress(address common.Address) bool {
175+
return a.list.hasAddress(address)
176+
}
177+
178+
// HasSlot checks if a storage slot is in the accesslist.
179+
func (a *AccessListTracer) HasSlot(address common.Address, slot common.Hash) bool {
180+
return a.list.hasSlot(address, slot)
181+
}

eth/tracers/native/base_gas_dimension_tracer.go

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/ethereum/go-ethereum/core/tracing"
1313
"github.com/ethereum/go-ethereum/core/types"
1414
"github.com/ethereum/go-ethereum/core/vm"
15+
"github.com/ethereum/go-ethereum/eth/tracers/logger"
1516
"github.com/ethereum/go-ethereum/params"
1617
)
1718

@@ -46,8 +47,7 @@ type BaseGasDimensionTracer struct {
4647
// if the root is a stylus contract
4748
rootIsStylusAdjustment uint64
4849
// maintain an access list tracer to check previous access list statuses.
49-
prevAccessListAddresses map[common.Address]int
50-
prevAccessListSlots []map[common.Hash]struct{}
50+
accessListTracer *logger.AccessListTracer
5151
// the amount of refund accumulated at the current step of execution
5252
refundAccumulated uint64
5353
// in order to calculate the refund adjusted, we need to know the total execution gas
@@ -85,13 +85,13 @@ func NewBaseGasDimensionTracer(cfg json.RawMessage, chainConfig *params.ChainCon
8585
}
8686
debug = config.Debug
8787
}
88+
accessListTracer := logger.NewAccessListTracer(types.AccessList{}, map[common.Address]struct{}{})
8889
return &BaseGasDimensionTracer{
8990
debug: debug,
9091
chainConfig: chainConfig,
9192
depth: 1,
9293
refundAccumulated: 0,
93-
prevAccessListAddresses: map[common.Address]int{},
94-
prevAccessListSlots: []map[common.Hash]struct{}{},
94+
accessListTracer: accessListTracer,
9595
env: nil,
9696
txHash: common.Hash{},
9797
gasUsed: 0,
@@ -277,18 +277,6 @@ func (t *BaseGasDimensionTracer) updateCallChildExecutionCost(cost uint64) {
277277
}
278278
}
279279

280-
// at the end of each OnOpcode, update the previous access list, so that we can
281-
// use it should the next opcode need to check if an address is in the access list
282-
func (t *BaseGasDimensionTracer) updatePrevAccessList(addresses map[common.Address]int, slots []map[common.Hash]struct{}) {
283-
if addresses == nil {
284-
t.prevAccessListAddresses = map[common.Address]int{}
285-
t.prevAccessListSlots = []map[common.Hash]struct{}{}
286-
return
287-
}
288-
t.prevAccessListAddresses = addresses
289-
t.prevAccessListSlots = slots
290-
}
291-
292280
// OnTxStart handles transaction start
293281
func (t *BaseGasDimensionTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
294282
t.env = env
@@ -396,9 +384,9 @@ func (t *BaseGasDimensionTracer) GetRootIsStylus() bool {
396384
return t.rootIsStylus
397385
}
398386

399-
// GetPrevAccessList returns the previous access list
400-
func (t *BaseGasDimensionTracer) GetPrevAccessList() (addresses map[common.Address]int, slots []map[common.Hash]struct{}) {
401-
return t.prevAccessListAddresses, t.prevAccessListSlots
387+
// GetAccessListTracer returns the access list tracer
388+
func (t *BaseGasDimensionTracer) GetAccessListTracer() *logger.AccessListTracer {
389+
return t.accessListTracer
402390
}
403391

404392
// GetPrecompileAddressList returns the list of precompile addresses

eth/tracers/native/gas_dimension_calc.go

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/ethereum/go-ethereum/core/state"
99
"github.com/ethereum/go-ethereum/core/tracing"
1010
"github.com/ethereum/go-ethereum/core/vm"
11+
"github.com/ethereum/go-ethereum/eth/tracers/logger"
1112
"github.com/ethereum/go-ethereum/params"
1213
)
1314

@@ -100,7 +101,7 @@ type DimensionTracer interface {
100101
GetOpRefund() uint64
101102
GetRefundAccumulated() uint64
102103
SetRefundAccumulated(uint64)
103-
GetPrevAccessList() (addresses map[common.Address]int, slots []map[common.Hash]struct{})
104+
GetAccessListTracer() *logger.AccessListTracer
104105
GetPrecompileAddressList() []common.Address
105106
GetStateDB() tracing.StateDB
106107
GetCallStack() CallGasDimensionStack
@@ -1209,9 +1210,8 @@ func memoryGasCost(mem []byte, lastGasCost uint64, newMemSize uint64) (fee uint6
12091210

12101211
// helper function that calculates the gas dimensions for an access list access for an address
12111212
func addressAccessListCost(t DimensionTracer, address common.Address) (computationGasCost uint64, stateAccessGasCost uint64) {
1212-
accessListAddresses, _ := t.GetPrevAccessList()
1213-
_, addressInAccessList := accessListAddresses[address]
1214-
if !addressInAccessList {
1213+
accessListTracer := t.GetAccessListTracer()
1214+
if !accessListTracer.HasAddress(address) {
12151215
computationGasCost = params.WarmStorageReadCostEIP2929
12161216
stateAccessGasCost = params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
12171217
} else {
@@ -1222,22 +1222,17 @@ func addressAccessListCost(t DimensionTracer, address common.Address) (computati
12221222
}
12231223

12241224
// helper function that calculates the gas dimensions for an access list access for a storage slot
1225-
func storageSlotAccessListCost(t DimensionTracer, address common.Address, slot common.Hash) (computationGasCost uint64, stateAccessGasCost uint64) {
1226-
accessListAddresses, accessListSlots := t.GetPrevAccessList()
1227-
idx, ok := accessListAddresses[address]
1228-
if !ok {
1229-
// no such address (and hence zero slots)
1230-
return params.WarmStorageReadCostEIP2929, params.ColdSloadCostEIP2929 - params.WarmStorageReadCostEIP2929
1231-
}
1232-
if idx == -1 {
1233-
// address yes, but no slots
1234-
return params.WarmStorageReadCostEIP2929, params.ColdSloadCostEIP2929 - params.WarmStorageReadCostEIP2929
1235-
}
1236-
_, slotPresent := accessListSlots[idx][slot]
1237-
if !slotPresent {
1238-
return params.WarmStorageReadCostEIP2929, params.ColdSloadCostEIP2929 - params.WarmStorageReadCostEIP2929
1225+
func storageSlotAccessListCost(t DimensionTracer, address common.Address, slot common.Hash) (
1226+
computationGasCost uint64, stateAccessGasCost uint64) {
1227+
accessListTracer := t.GetAccessListTracer()
1228+
if !accessListTracer.HasSlot(address, slot) {
1229+
computationGasCost = params.WarmStorageReadCostEIP2929
1230+
stateAccessGasCost = params.ColdSloadCostEIP2929 - params.WarmStorageReadCostEIP2929
1231+
} else {
1232+
computationGasCost = params.WarmStorageReadCostEIP2929
1233+
stateAccessGasCost = 0
12391234
}
1240-
return params.WarmStorageReadCostEIP2929, 0
1235+
return computationGasCost, stateAccessGasCost
12411236
}
12421237

12431238
// wherever it's possible, check that the gas dimensions are sane

0 commit comments

Comments
 (0)