Skip to content
Draft
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
15 changes: 15 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,13 @@ func New(
if err != nil {
panic(fmt.Sprintf("error reading EVM config due to %s", err))
}
if app.evmRPCConfig.TraceBakeEnabled {
traceCache, tcErr := evmkeeper.NewTraceCache(homePath)
if tcErr != nil {
panic(fmt.Sprintf("failed to open trace cache: %s", tcErr))
}
app.EvmKeeper.SetTraceCache(traceCache)
}
app.adminConfig, err = admin.ReadConfig(appOpts)
if err != nil {
panic(fmt.Sprintf("error reading admin config due to %s", err))
Expand Down Expand Up @@ -1063,6 +1070,14 @@ func (app *App) HandlePreCommit(ctx sdk.Context) error {
func (app *App) HandleClose() error {
var errs []error

// Close trace cache so its WAL is flushed; baker writes use NoSync.
if tc := app.EvmKeeper.TraceCache(); tc != nil {
if err := tc.Close(); err != nil {
logger.Error("failed to close trace cache", "err", err)
errs = append(errs, fmt.Errorf("failed to close trace cache: %w", err))
}
}

// Close receipt store
if app.receiptStore != nil {
if err := app.receiptStore.Close(); err != nil {
Expand Down
94 changes: 94 additions & 0 deletions evmrpc/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,32 @@ type Config struct {
// EnabledLegacySeiApis lists which gated sei_* and sei2_* JSON-RPC methods are allowed on the EVM HTTP endpoint.
// Set in app.toml [evm] as enabled_legacy_sei_apis (see ReadConfig and ConfigTemplate defaults).
EnabledLegacySeiApis []string `mapstructure:"enabled_legacy_sei_apis"`

// TraceBakeEnabled, when true, runs a background worker that re-executes
// each committed block with the configured tracers and stores the
// results to <home>/data/trace_cache. debug_traceTransaction serves
// from cache on hit. Default false; flip on for RPC nodes only.
TraceBakeEnabled bool `mapstructure:"trace_bake_enabled"`

// TraceBakeWorkers is the number of re-execution goroutines (default 1).
TraceBakeWorkers int `mapstructure:"trace_bake_workers"`

// TraceBakeQueueSize bounds the in-flight height queue (default 4096).
TraceBakeQueueSize int `mapstructure:"trace_bake_queue_size"`

// TraceBakeTracers is the list of tracer names to bake per block.
// Default ["callTracer"]. Only the standard named tracers are eligible.
TraceBakeTracers []string `mapstructure:"trace_bake_tracers"`

// TraceBakeWindowBlocks bounds the rolling cache window: blocks older
// than (latest - this) are pruned. 0 disables pruning.
TraceBakeWindowBlocks int64 `mapstructure:"trace_bake_window_blocks"`

// TraceBakeBlockResults additionally writes the assembled per-block
// JSON to the cache so debug_traceBlockBy* hits at one PK seek
// instead of N. ~2x storage for callers that primarily trace
// per-block; per-tx hits are unaffected. Default false.
TraceBakeBlockResults bool `mapstructure:"trace_bake_block_results"`
}

var DefaultConfig = Config{
Expand Down Expand Up @@ -178,6 +204,12 @@ var DefaultConfig = Config{
"sei_getEVMAddress",
"sei_getCosmosTx",
},
TraceBakeEnabled: false,
TraceBakeWorkers: 1,
TraceBakeQueueSize: 4096,
TraceBakeTracers: []string{"callTracer"},
TraceBakeWindowBlocks: 0,
TraceBakeBlockResults: false,
}

const (
Expand Down Expand Up @@ -211,6 +243,12 @@ const (
flagWorkerPoolSize = "evm.worker_pool_size"
flagWorkerQueueSize = "evm.worker_queue_size"
flagEVMLegacySeiApis = "evm.enabled_legacy_sei_apis"
flagTraceBakeEnabled = "evm.trace_bake_enabled"
flagTraceBakeWorkers = "evm.trace_bake_workers"
flagTraceBakeQueueSize = "evm.trace_bake_queue_size"
flagTraceBakeTracers = "evm.trace_bake_tracers"
flagTraceBakeWindowBlocks = "evm.trace_bake_window_blocks"
flagTraceBakeBlockResults = "evm.trace_bake_block_results"
)

func ReadConfig(opts servertypes.AppOptions) (Config, error) {
Expand Down Expand Up @@ -366,6 +404,36 @@ func ReadConfig(opts servertypes.AppOptions) (Config, error) {
return cfg, err
}
}
if v := opts.Get(flagTraceBakeEnabled); v != nil {
if cfg.TraceBakeEnabled, err = cast.ToBoolE(v); err != nil {
return cfg, err
}
}
if v := opts.Get(flagTraceBakeWorkers); v != nil {
if cfg.TraceBakeWorkers, err = cast.ToIntE(v); err != nil {
return cfg, err
}
}
if v := opts.Get(flagTraceBakeQueueSize); v != nil {
if cfg.TraceBakeQueueSize, err = cast.ToIntE(v); err != nil {
return cfg, err
}
}
if v := opts.Get(flagTraceBakeTracers); v != nil {
if cfg.TraceBakeTracers, err = cast.ToStringSliceE(v); err != nil {
return cfg, err
}
}
if v := opts.Get(flagTraceBakeWindowBlocks); v != nil {
if cfg.TraceBakeWindowBlocks, err = cast.ToInt64E(v); err != nil {
return cfg, err
}
}
if v := opts.Get(flagTraceBakeBlockResults); v != nil {
if cfg.TraceBakeBlockResults, err = cast.ToBoolE(v); err != nil {
return cfg, err
}
}

return cfg, nil
}
Expand Down Expand Up @@ -521,4 +589,30 @@ worker_pool_size = {{ .EVM.WorkerPoolSize }}
# WorkerQueueSize defines the size of the task queue in the worker pool.
# Default: 1000 tasks. Set to 0 to use the default.
worker_queue_size = {{ .EVM.WorkerQueueSize }}

# TraceBakeEnabled, when true, runs a background worker that re-executes
# each committed block with the configured tracers and stores the result
# to <home>/data/trace_cache. debug_traceTransaction with a bakeable
# tracer config (callTracer / prestateTracer / flatCallTracer) returns
# from cache on hit. Recommended for RPC nodes only; default false.
trace_bake_enabled = {{ .EVM.TraceBakeEnabled }}

# Number of re-execution worker goroutines (default 1).
trace_bake_workers = {{ .EVM.TraceBakeWorkers }}

# Bounded in-flight height queue. Drops on full so consensus never blocks.
trace_bake_queue_size = {{ .EVM.TraceBakeQueueSize }}

# Which tracers to bake per block; only standard named tracers are eligible.
trace_bake_tracers = [{{- range $i, $t := .EVM.TraceBakeTracers }}{{- if $i }}, {{ end }}"{{ $t }}"{{- end }}]

# Rolling cache window: prune blocks older than (latest - this).
# 0 disables pruning (cache grows forever).
trace_bake_window_blocks = {{ .EVM.TraceBakeWindowBlocks }}

# Additionally cache the assembled per-block trace result so
# debug_traceBlockBy* hits at one PK seek instead of N. ~2x storage
# in exchange for ~3x faster block-level trace; per-tx hits unaffected.
# Recommended when block-tracing is the dominant workload.
trace_bake_block_results = {{ .EVM.TraceBakeBlockResults }}
`
10 changes: 10 additions & 0 deletions evmrpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ func NewEVMHTTPServer(
ctx := ctxProvider(LatestCtxHeight)
txAPI := NewTransactionAPI(tmClient, k, ctxProvider, txConfigProvider, homeDir, ConnectionTypeHTTP, watermarks, globalBlockCache, cacheCreationMutex)
debugAPI := NewDebugAPI(tmClient, k, beginBlockKeepers, ctxProvider, txConfigProvider, simulateConfig, app, antehandler, ConnectionTypeHTTP, config, globalBlockCache, cacheCreationMutex, watermarks)
if config.TraceBakeEnabled {
StartTraceBakerForDebugAPI(debugAPI, TraceBakerConfig{
Workers: config.TraceBakeWorkers,
QueueSize: config.TraceBakeQueueSize,
Tracers: config.TraceBakeTracers,
WindowBlocks: config.TraceBakeWindowBlocks,
CacheBlockResults: config.TraceBakeBlockResults,
TipFn: func() int64 { return ctxProvider(LatestCtxHeight).BlockHeight() },
})
}
if isPanicOrSyntheticTxFunc == nil {
isPanicOrSyntheticTxFunc = func(ctx context.Context, hash common.Hash) (bool, error) {
return debugAPI.isPanicOrSyntheticTx(ctx, hash)
Expand Down
Loading
Loading