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
21 changes: 1 addition & 20 deletions giga/evmonly/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"math/big"
"sync"
"sync/atomic"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
Expand All @@ -30,7 +29,6 @@ type Executor struct {
cfg Config
resultSink ResultSink
occPool *occWorkerPool
parseSizer *parseSizer
resultPool *blockResultPool
stateDBPool sync.Pool
storeMu sync.Mutex
Expand Down Expand Up @@ -112,7 +110,6 @@ func NewExecutor(cfg Config, opts ...Option) *Executor {
blockPhases: seidbmetrics.NewPhaseTimer(otel.Meter(executorMeterName), "evmonly_block"),
pipelinePhases: seidbmetrics.NewPhaseTimer(otel.Meter(executorMeterName), "evmonly_pipeline"),
}
e.parseSizer = newParseSizer(e.cfg.ParseWorkers)
if e.cfg.OCCWorkers > 1 {
e.occPool = newOCCWorkerPool(e.cfg.OCCWorkers)
}
Expand Down Expand Up @@ -187,18 +184,7 @@ func (e *Executor) ExecuteBlock(ctx context.Context, req BlockRequest) (*BlockRe
return result, nil
}

// PrepareBlock decodes the block's transactions and recovers their senders on
// every parse worker.
func (e *Executor) PrepareBlock(ctx context.Context, req BlockRequest) (PreparedBlock, error) {
return e.PrepareBlockWithin(ctx, req, 0)
}

// PrepareBlockWithin decodes the block's transactions and recovers their senders
// on as few parse workers as the decode is expected to fit in budget on, leaving
// the rest of the processors to whatever runs alongside. A budget of 0 uses every
// parse worker and does not inform the expectation, which comes from the budgeted
// decodes before this one; the first of those is decoded on every worker.
func (e *Executor) PrepareBlockWithin(ctx context.Context, req BlockRequest, budget time.Duration) (PreparedBlock, error) {
chainConfig := e.chainConfig(req.Context)
if err := validateBlockContext(chainConfig, req.Context); err != nil {
return PreparedBlock{}, err
Expand All @@ -207,15 +193,10 @@ func (e *Executor) PrepareBlockWithin(ctx context.Context, req BlockRequest, bud
if len(req.Senders) != 0 && len(req.Senders) != len(req.Txs) {
return PreparedBlock{}, fmt.Errorf("block request has %d senders for %d txs", len(req.Senders), len(req.Txs))
}
workers := e.parseSizer.workers(len(req.Txs), budget)
start := time.Now()
parsed, err := parseBlockTxs(ctx, req.Txs, signer, req.Senders, workers)
parsed, err := parseBlockTxs(ctx, req.Txs, signer, req.Senders, e.cfg.ParseWorkers)
if err != nil {
return PreparedBlock{}, err
}
if budget > 0 {
e.parseSizer.observe(len(req.Txs), workers, time.Since(start))
}
return PreparedBlock{
Context: req.Context,
Txs: parsed,
Expand Down
65 changes: 0 additions & 65 deletions giga/evmonly/parse_sizer.go

This file was deleted.

55 changes: 0 additions & 55 deletions giga/evmonly/parse_sizer_test.go

This file was deleted.

42 changes: 2 additions & 40 deletions sei-tendermint/internal/evmonlyapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"slices"
"sync"
"sync/atomic"
"time"

"go.opentelemetry.io/otel/attribute"
otelmetric "go.opentelemetry.io/otel/metric"
Expand Down Expand Up @@ -56,36 +55,6 @@ const checkedSendersCap = 1 << 18
// minTxsPerHashWorker is the minimum transaction count assigned to a hash worker.
const minTxsPerHashWorker = 64

// prepareBudgetShare is the fraction of the typical block execution time
// PrepareBlock is given to decode the next block in. Decoding runs alongside the
// current block's OCC speculation, which holds a worker per processor, so it is
// sized to finish within that block on as few processors as it can rather than
// contending for all of them; the share leaves room for the block being shorter
// than typical.
const prepareBudgetShare = 2

// executeEstimateDecay is the denominator of the exponential moving average of
// block execution time; each block moves the estimate 1/executeEstimateDecay of
// the way to what it took, so a single short block does not hand the next decode
// every processor.
const executeEstimateDecay = 8

// prepareBudget returns how long PrepareBlock has to decode the next block given
// the typical block execution time. 0 when no block has executed yet, which
// decodes on every worker.
func prepareBudget(executeEstimate time.Duration) time.Duration {
return executeEstimate / prepareBudgetShare
}

// nextExecuteEstimate folds the execution time of a block into the estimate of the
// typical one.
func nextExecuteEstimate(current, executed time.Duration) time.Duration {
if current <= 0 {
return executed
}
return current + (executed-current)/executeEstimateDecay
}

type evmOnlyApplication struct {
abci.BaseApplication

Expand Down Expand Up @@ -123,11 +92,6 @@ type evmOnlyApplication struct {
// preparePhases times PrepareBlock's decode of the next block. PrepareBlock is
// called from the single block fetcher, so one timer serves the app.
preparePhases *seidbmetrics.PhaseTimer
// executeEstimate is the typical time a prepared FinalizeBlock spends executing,
// in nanoseconds, averaged over the recent ones; PrepareBlock's decode budget is
// derived from it. Only prepared blocks contribute: an unprepared one includes
// its own decode.
executeEstimate atomic.Int64
}

// preparedBlock is the stateless part of a FinalizeBlock request, computed before the
Expand Down Expand Up @@ -689,7 +653,7 @@ func (a *evmOnlyApplication) PrepareBlock(ctx context.Context, req *abci.Request
// Only Number and Time reach the decoded transactions (through the signer); the
// parent-derived fields are filled in by FinalizeBlock.
a.preparePhases.SetPhase("parse")
prepared, err := executor.PrepareBlockWithin(ctx, evmonly.BlockRequest{
prepared, err := executor.PrepareBlock(ctx, evmonly.BlockRequest{
Context: evmonly.BlockContext{
Number: block.number,
Time: block.timestamp,
Expand All @@ -700,7 +664,7 @@ func (a *evmOnlyApplication) PrepareBlock(ctx context.Context, req *abci.Request
},
Txs: req.Txs,
Senders: a.peekSenders(req.Txs),
}, prepareBudget(time.Duration(a.executeEstimate.Load())))
})
a.preparePhases.Reset()
if err != nil {
return ctx.Err()
Expand Down Expand Up @@ -776,9 +740,7 @@ func (a *evmOnlyApplication) finalizeBlockLocked(
a.finalizePhases.SetPhase("take_senders")
a.forgetSenders(req.Txs)
a.finalizePhases.SetPhase("execute")
start := time.Now()
result, err = executor.ExecutePreparedBlock(ctx, evmonly.PreparedBlock{Context: blockCtx, Txs: prepared})
a.executeEstimate.Store(int64(nextExecuteEstimate(time.Duration(a.executeEstimate.Load()), time.Since(start))))
} else {
a.finalizePhases.SetPhase("take_senders")
senders := a.takeSenders(req.Txs)
Expand Down
17 changes: 0 additions & 17 deletions sei-tendermint/internal/evmonlyapp/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -865,23 +865,6 @@ func TestEVMOnlyApplicationReportsAnUndecodableBlockFromFinalizeBlock(t *testing
require.Error(t, unpreparedErr)
}

func TestPrepareBudgetIsAShareOfTheTypicalExecution(t *testing.T) {
require.Equal(t, time.Duration(0), prepareBudget(0))
require.Equal(t, 10*time.Millisecond, prepareBudget(20*time.Millisecond))
}

func TestExecuteEstimateSmoothsOverBlocks(t *testing.T) {
// The first block sets the estimate; later ones move it a step.
estimate := nextExecuteEstimate(0, 20*time.Millisecond)
require.Equal(t, 20*time.Millisecond, estimate)
// A single short block barely dents the budget rather than zeroing it.
estimate = nextExecuteEstimate(estimate, time.Millisecond)
require.Equal(t, 17625*time.Microsecond, estimate)
require.Equal(t, 8812500*time.Nanosecond, prepareBudget(estimate))
estimate = nextExecuteEstimate(estimate, 40*time.Millisecond)
require.Equal(t, 20421875*time.Nanosecond, estimate)
}

// Preparing before InitChain is a no-op rather than a failure.
func TestEVMOnlyApplicationPrepareBlockBeforeInitChainIsANoOp(t *testing.T) {
app := newEVMOnlyTestApp(t, nil)
Expand Down
Loading