From 769e7c802ba5039974cee8815272e20300353c8c Mon Sep 17 00:00:00 2001 From: bnoieh <135800952+bnoieh@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:48:28 +0800 Subject: [PATCH 1/6] feat: support combined engine api --- op-node/flags/flags.go | 7 +++ op-node/rollup/derive/engine_controller.go | 14 +++++- op-node/rollup/derive/engine_update.go | 55 ++++++++++++++++++++++ op-node/rollup/driver/config.go | 2 + op-node/rollup/driver/driver.go | 2 +- op-node/service.go | 13 ++--- op-service/eth/types.go | 6 +++ op-service/sources/engine_client.go | 33 ++++++++++++- 8 files changed, 122 insertions(+), 10 deletions(-) diff --git a/op-node/flags/flags.go b/op-node/flags/flags.go index 03c48f0f3e..811e0fba25 100644 --- a/op-node/flags/flags.go +++ b/op-node/flags/flags.go @@ -251,6 +251,12 @@ var ( EnvVars: prefixEnvVars("SEQUENCER_PRIORITY"), Category: SequencerCategory, } + SequencerCombinedEngineFlag = &cli.BoolFlag{ + Name: "sequencer.combined-engine", + Usage: "Enable sequencer select combined engine api when sealing payload.", + EnvVars: prefixEnvVars("SEQUENCER_COMBINED_ENGINE"), + Category: SequencerCategory, + } SequencerL1Confs = &cli.Uint64Flag{ Name: "sequencer.l1-confs", Usage: "Number of L1 blocks to keep distance from the L1 head as a sequencer for picking an L1 origin.", @@ -437,6 +443,7 @@ var optionalFlags = []cli.Flag{ SequencerStoppedFlag, SequencerMaxSafeLagFlag, SequencerPriorityFlag, + SequencerCombinedEngineFlag, SequencerL1Confs, L1EpochPollIntervalFlag, RuntimeConfigReloadIntervalFlag, diff --git a/op-node/rollup/derive/engine_controller.go b/op-node/rollup/derive/engine_controller.go index f53ad70658..96469ceb6d 100644 --- a/op-node/rollup/derive/engine_controller.go +++ b/op-node/rollup/derive/engine_controller.go @@ -50,6 +50,7 @@ type ExecEngine interface { GetPayload(ctx context.Context, payloadInfo eth.PayloadInfo) (*eth.ExecutionPayloadEnvelope, error) ForkchoiceUpdate(ctx context.Context, state *eth.ForkchoiceState, attr *eth.PayloadAttributes) (*eth.ForkchoiceUpdatedResult, error) NewPayload(ctx context.Context, payload *eth.ExecutionPayload, parentBeaconBlockRoot *common.Hash) (*eth.PayloadStatusV1, error) + SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState) (*eth.SealPayloadResponse, error) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L2BlockRef, error) } @@ -84,9 +85,11 @@ type EngineController struct { buildingInfo eth.PayloadInfo buildingSafe bool safeAttrs *AttributesWithParent + + combinedAPI bool } -func NewEngineController(engine ExecEngine, log log.Logger, metrics Metrics, rollupCfg *rollup.Config, syncConfig *sync.Config) *EngineController { +func NewEngineController(engine ExecEngine, log log.Logger, metrics Metrics, rollupCfg *rollup.Config, syncConfig *sync.Config, combinedAPI bool) *EngineController { syncStatus := syncStatusCL if syncConfig.SyncMode == sync.ELSync { syncStatus = syncStatusWillStartEL @@ -102,6 +105,7 @@ func NewEngineController(engine ExecEngine, log log.Logger, metrics Metrics, rol elTriggerGap: syncConfig.ELTriggerGap, syncStatus: syncStatus, clock: clock.SystemClock, + combinedAPI: combinedAPI, } } @@ -267,7 +271,13 @@ func (e *EngineController) ConfirmPayload(ctx context.Context, agossip async.Asy } // Update the safe head if the payload is built with the last attributes in the batch. updateSafe := e.buildingSafe && e.safeAttrs != nil && e.safeAttrs.IsLastInSpan - envelope, errTyp, err := confirmPayload(ctx, e.log, e.engine, fc, e.buildingInfo, updateSafe, agossip, sequencerConductor, e.metrics) + + var envelope *eth.ExecutionPayloadEnvelope + if e.combinedAPI { + envelope, errTyp, err = confirmPayloadCombined(ctx, e.log, e.engine, fc, e.buildingInfo, updateSafe, agossip, sequencerConductor, e.metrics) + } else { + envelope, errTyp, err = confirmPayload(ctx, e.log, e.engine, fc, e.buildingInfo, updateSafe, agossip, sequencerConductor, e.metrics) + } if err != nil { return nil, errTyp, fmt.Errorf("failed to complete building on top of L2 chain %s, id: %s, error (%d): %w", e.buildingOnto, e.buildingInfo.ID, errTyp, err) } diff --git a/op-node/rollup/derive/engine_update.go b/op-node/rollup/derive/engine_update.go index d3e3c8bf19..21373013b8 100644 --- a/op-node/rollup/derive/engine_update.go +++ b/op-node/rollup/derive/engine_update.go @@ -208,3 +208,58 @@ func confirmPayload( "txs", len(payload.Transactions), "update_safe", updateSafe) return envelope, BlockInsertOK, nil } + +func confirmPayloadCombined( + ctx context.Context, + log log.Logger, + eng ExecEngine, + fc eth.ForkchoiceState, + payloadInfo eth.PayloadInfo, + updateSafe bool, + agossip async.AsyncGossiper, + sequencerConductor conductor.SequencerConductor, + metrics Metrics, +) (out *eth.ExecutionPayloadEnvelope, errTyp BlockInsertionErrType, err error) { + start := time.Now() + sealRes, err := eng.SealPayload(ctx, payloadInfo, &fc) + + if err != nil { + var inputErr eth.InputError + if errors.As(err, &inputErr) { + switch inputErr.Code { + case eth.InvalidForkchoiceState: + return nil, BlockInsertPayloadErr, fmt.Errorf("post-block-creation forkchoice update was inconsistent with engine, need reset to resolve: %w", inputErr.Unwrap()) + default: + return nil, BlockInsertPrestateErr, fmt.Errorf("unexpected error code in forkchoice-updated response: %w", err) + } + } else { + return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to make the new L2 block canonical via forkchoice: %w", err) + } + } + + if sealRes.PayloadStatus.Status != eth.ExecutionValid { + switch sealRes.Stage { + case "newPayload": + if sealRes.PayloadStatus.Status == eth.ExecutionInvalid || sealRes.PayloadStatus.Status == eth.ExecutionInvalidBlockHash { + return nil, BlockInsertPayloadErr, fmt.Errorf("new payload BlockInsertPayloadErr %v", sealRes.PayloadStatus.ValidationError) + } + return nil, BlockInsertTemporaryErr, fmt.Errorf("new payload BlockInsertTemporaryErr %v", sealRes.PayloadStatus.ValidationError) + case "forkchoiceUpdate": + return nil, BlockInsertPayloadErr, fmt.Errorf("forkchoiceUpdate BlockInsertPayloadErr %v", sealRes.PayloadStatus.ValidationError) + } + } + + if err := sequencerConductor.CommitUnsafePayload(ctx, sealRes.Payload); err != nil { + return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to commit unsafe payload to conductor: %w", err) + } + agossip.Gossip(sealRes.Payload) + agossip.Clear() + + payload := sealRes.Payload.ExecutionPayload + metrics.RecordSequencerStepTime("sealPayload", time.Since(start)) + log.Info("inserted block", "hash", payload.BlockHash, "number", uint64(payload.BlockNumber), + "state_root", payload.StateRoot, "timestamp", uint64(payload.Timestamp), "parent", payload.ParentHash, + "prev_randao", payload.PrevRandao, "fee_recipient", payload.FeeRecipient, + "txs", len(payload.Transactions), "update_safe", updateSafe) + return sealRes.Payload, BlockInsertOK, nil +} diff --git a/op-node/rollup/driver/config.go b/op-node/rollup/driver/config.go index fa0d6932ca..42ebe6f635 100644 --- a/op-node/rollup/driver/config.go +++ b/op-node/rollup/driver/config.go @@ -23,4 +23,6 @@ type Config struct { // SequencerPriority is true when sequencer step takes precedence over other steps. SequencerPriority bool `json:"sequencer_priority"` + + SequencerCombinedEngine bool `json:"sequencer_combined_engine"` } diff --git a/op-node/rollup/driver/driver.go b/op-node/rollup/driver/driver.go index f7f610f4fa..7b127eccb5 100644 --- a/op-node/rollup/driver/driver.go +++ b/op-node/rollup/driver/driver.go @@ -157,7 +157,7 @@ func NewDriver( sequencerConfDepth := NewConfDepth(driverCfg.SequencerConfDepth, l1State.L1Head, l1) findL1Origin := NewL1OriginSelector(log, cfg, sequencerConfDepth) verifConfDepth := NewConfDepth(driverCfg.VerifierConfDepth, l1State.L1Head, l1) - engine := derive.NewEngineController(l2, log, metrics, cfg, syncCfg) + engine := derive.NewEngineController(l2, log, metrics, cfg, syncCfg, driverCfg.SequencerCombinedEngine) clSync := clsync.NewCLSync(log, cfg, metrics, engine) var finalizer Finalizer diff --git a/op-node/service.go b/op-node/service.go index c1fd6f8abf..134a916ee0 100644 --- a/op-node/service.go +++ b/op-node/service.go @@ -204,12 +204,13 @@ func NewConfigPersistence(ctx *cli.Context) node.ConfigPersistence { func NewDriverConfig(ctx *cli.Context) *driver.Config { return &driver.Config{ - VerifierConfDepth: ctx.Uint64(flags.VerifierL1Confs.Name), - SequencerConfDepth: ctx.Uint64(flags.SequencerL1Confs.Name), - SequencerEnabled: ctx.Bool(flags.SequencerEnabledFlag.Name), - SequencerStopped: ctx.Bool(flags.SequencerStoppedFlag.Name), - SequencerMaxSafeLag: ctx.Uint64(flags.SequencerMaxSafeLagFlag.Name), - SequencerPriority: ctx.Bool(flags.SequencerPriorityFlag.Name), + VerifierConfDepth: ctx.Uint64(flags.VerifierL1Confs.Name), + SequencerConfDepth: ctx.Uint64(flags.SequencerL1Confs.Name), + SequencerEnabled: ctx.Bool(flags.SequencerEnabledFlag.Name), + SequencerStopped: ctx.Bool(flags.SequencerStoppedFlag.Name), + SequencerMaxSafeLag: ctx.Uint64(flags.SequencerMaxSafeLagFlag.Name), + SequencerPriority: ctx.Bool(flags.SequencerPriorityFlag.Name), + SequencerCombinedEngine: ctx.Bool(flags.SequencerCombinedEngineFlag.Name), } } diff --git a/op-service/eth/types.go b/op-service/eth/types.go index 605c10ffce..5dde9d656f 100644 --- a/op-service/eth/types.go +++ b/op-service/eth/types.go @@ -367,6 +367,12 @@ type ForkchoiceUpdatedResult struct { PayloadID *PayloadID `json:"payloadId"` } +type SealPayloadResponse struct { + Stage string `json:"stage"` + PayloadStatus PayloadStatusV1 `json:"payloadStatus"` + Payload *ExecutionPayloadEnvelope `json:"payload"` +} + // SystemConfig represents the rollup system configuration that carries over in every L2 block, // and may be changed through L1 system config events. // The initial SystemConfig at rollup genesis is embedded in the rollup configuration. diff --git a/op-service/sources/engine_client.go b/op-service/sources/engine_client.go index 9490df78f9..68fc6d67cc 100644 --- a/op-service/sources/engine_client.go +++ b/op-service/sources/engine_client.go @@ -139,7 +139,7 @@ func (s *EngineAPIClient) NewPayload(ctx context.Context, payload *eth.Execution e.Trace("Received payload execution result", "status", result.Status, "latestValidHash", result.LatestValidHash, "message", result.ValidationError) if err != nil { if strings.Contains(err.Error(), derive.ErrELSyncTriggerUnexpected.Error()) { - result.Status = eth.ExecutionSyncing + result.Status = eth.ExecutionSyncing // why? return &result, err } e.Error("Payload execution failed", "err", err) @@ -178,6 +178,37 @@ func (s *EngineAPIClient) GetPayload(ctx context.Context, payloadInfo eth.Payloa return &result, nil } +func (s *EngineAPIClient) SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState) (*eth.SealPayloadResponse, error) { + e := s.log.New("payload_id", payloadInfo.ID) + e.Trace("sealing payload") + var result eth.SealPayloadResponse + method := "engine_opSealPayload" + err := s.RPC.CallContext(ctx, &result, string(method), payloadInfo.ID, fc) + if err != nil { + e.Warn("Failed to seal payload", "payload_id", payloadInfo.ID, "err", err) + if rpcErr, ok := err.(rpc.Error); ok { + code := eth.ErrorCode(rpcErr.ErrorCode()) + switch code { + case eth.UnknownPayload: + return nil, eth.InputError{ + Inner: err, + Code: code, + } + case eth.InvalidForkchoiceState, eth.InvalidPayloadAttributes: + return nil, eth.InputError{ + Inner: err, + Code: code, + } + default: + return nil, fmt.Errorf("unrecognized rpc error: %w", err) + } + } + return nil, err + } + e.Trace("Received payload") + return &result, nil +} + func (s *EngineAPIClient) SignalSuperchainV1(ctx context.Context, recommended, required params.ProtocolVersion) (params.ProtocolVersion, error) { var result params.ProtocolVersion err := s.RPC.CallContext(ctx, &result, "engine_signalSuperchainV1", &catalyst.SuperchainSignal{ From a3610c46907953fa7ee1a408a38270858f014682 Mon Sep 17 00:00:00 2001 From: bnoieh <135800952+bnoieh@users.noreply.github.com> Date: Sat, 12 Oct 2024 10:25:38 +0800 Subject: [PATCH 2/6] perf: concurrently call engine_getPayload when engine_sealPayload --- op-node/rollup/derive/engine_controller.go | 2 +- op-node/rollup/derive/engine_update.go | 43 +++++++++++++++++++--- op-service/sources/engine_client.go | 6 ++- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/op-node/rollup/derive/engine_controller.go b/op-node/rollup/derive/engine_controller.go index 96469ceb6d..727c3c3ec3 100644 --- a/op-node/rollup/derive/engine_controller.go +++ b/op-node/rollup/derive/engine_controller.go @@ -50,7 +50,7 @@ type ExecEngine interface { GetPayload(ctx context.Context, payloadInfo eth.PayloadInfo) (*eth.ExecutionPayloadEnvelope, error) ForkchoiceUpdate(ctx context.Context, state *eth.ForkchoiceState, attr *eth.PayloadAttributes) (*eth.ForkchoiceUpdatedResult, error) NewPayload(ctx context.Context, payload *eth.ExecutionPayload, parentBeaconBlockRoot *common.Hash) (*eth.PayloadStatusV1, error) - SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState) (*eth.SealPayloadResponse, error) + SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState, needPayload bool) (*eth.SealPayloadResponse, error) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L2BlockRef, error) } diff --git a/op-node/rollup/derive/engine_update.go b/op-node/rollup/derive/engine_update.go index 21373013b8..b67b3540c6 100644 --- a/op-node/rollup/derive/engine_update.go +++ b/op-node/rollup/derive/engine_update.go @@ -221,8 +221,30 @@ func confirmPayloadCombined( metrics Metrics, ) (out *eth.ExecutionPayloadEnvelope, errTyp BlockInsertionErrType, err error) { start := time.Now() - sealRes, err := eng.SealPayload(ctx, payloadInfo, &fc) + type SealPayloadRet struct { + res *eth.SealPayloadResponse + err error + } + sealPayloadRetCh := make(chan SealPayloadRet) + go func() { + res, err := eng.SealPayload(ctx, payloadInfo, &fc, false) + sealPayloadRetCh <- SealPayloadRet{res, err} + }() + + type GetPayloadRet struct { + res *eth.ExecutionPayloadEnvelope + err error + } + getPayloadRetCh := make(chan GetPayloadRet) + go func() { + res, err := eng.GetPayload(ctx, payloadInfo) + getPayloadRetCh <- GetPayloadRet{res, err} + }() + + sealPayloadRet := <-sealPayloadRetCh + sealRes := sealPayloadRet.res + err = sealPayloadRet.err if err != nil { var inputErr eth.InputError if errors.As(err, &inputErr) { @@ -249,17 +271,26 @@ func confirmPayloadCombined( } } - if err := sequencerConductor.CommitUnsafePayload(ctx, sealRes.Payload); err != nil { + getPayloadRet := <-getPayloadRetCh + envelope := getPayloadRet.res + err = getPayloadRet.err + if err != nil { + return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to get sealed payload: %w", err) + } + payload := envelope.ExecutionPayload + if err := sanityCheckPayload(payload); err != nil { + return nil, BlockInsertPayloadErr, err + } + if err := sequencerConductor.CommitUnsafePayload(ctx, envelope); err != nil { return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to commit unsafe payload to conductor: %w", err) } - agossip.Gossip(sealRes.Payload) + agossip.Gossip(envelope) agossip.Clear() - payload := sealRes.Payload.ExecutionPayload metrics.RecordSequencerStepTime("sealPayload", time.Since(start)) - log.Info("inserted block", "hash", payload.BlockHash, "number", uint64(payload.BlockNumber), + log.Info("perf-trace inserted block", "hash", payload.BlockHash, "number", uint64(payload.BlockNumber), "duration", time.Since(start), "state_root", payload.StateRoot, "timestamp", uint64(payload.Timestamp), "parent", payload.ParentHash, "prev_randao", payload.PrevRandao, "fee_recipient", payload.FeeRecipient, "txs", len(payload.Transactions), "update_safe", updateSafe) - return sealRes.Payload, BlockInsertOK, nil + return envelope, BlockInsertOK, nil } diff --git a/op-service/sources/engine_client.go b/op-service/sources/engine_client.go index 68fc6d67cc..7c8ac2f1d8 100644 --- a/op-service/sources/engine_client.go +++ b/op-service/sources/engine_client.go @@ -178,12 +178,14 @@ func (s *EngineAPIClient) GetPayload(ctx context.Context, payloadInfo eth.Payloa return &result, nil } -func (s *EngineAPIClient) SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState) (*eth.SealPayloadResponse, error) { +func (s *EngineAPIClient) SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState, needPayload bool) (*eth.SealPayloadResponse, error) { e := s.log.New("payload_id", payloadInfo.ID) e.Trace("sealing payload") var result eth.SealPayloadResponse method := "engine_opSealPayload" - err := s.RPC.CallContext(ctx, &result, string(method), payloadInfo.ID, fc) + start := time.Now() + err := s.RPC.CallContext(ctx, &result, string(method), payloadInfo.ID, fc, needPayload) + e.Info("perf-trace eng.SealPayload", "duration", time.Since(start), "payload", payloadInfo.ID) if err != nil { e.Warn("Failed to seal payload", "payload_id", payloadInfo.ID, "err", err) if rpcErr, ok := err.(rpc.Error); ok { From 38c842518cdaa79258550b1712bbb6b0bf7005ca Mon Sep 17 00:00:00 2001 From: bnoieh <135800952+bnoieh@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:13:20 +0800 Subject: [PATCH 3/6] perf: add new api engine_opSealPayload --- op-node/rollup/derive/engine_controller.go | 4 +- op-node/rollup/derive/engine_update.go | 112 +++++++++++++-------- op-node/rollup/types.go | 10 ++ op-service/eth/types.go | 11 +- op-service/sources/engine_client.go | 66 ++++++++---- 5 files changed, 140 insertions(+), 63 deletions(-) diff --git a/op-node/rollup/derive/engine_controller.go b/op-node/rollup/derive/engine_controller.go index 727c3c3ec3..e0e8d25487 100644 --- a/op-node/rollup/derive/engine_controller.go +++ b/op-node/rollup/derive/engine_controller.go @@ -50,7 +50,7 @@ type ExecEngine interface { GetPayload(ctx context.Context, payloadInfo eth.PayloadInfo) (*eth.ExecutionPayloadEnvelope, error) ForkchoiceUpdate(ctx context.Context, state *eth.ForkchoiceState, attr *eth.PayloadAttributes) (*eth.ForkchoiceUpdatedResult, error) NewPayload(ctx context.Context, payload *eth.ExecutionPayload, parentBeaconBlockRoot *common.Hash) (*eth.PayloadStatusV1, error) - SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState, needPayload bool) (*eth.SealPayloadResponse, error) + SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState, needPayload bool) (*eth.SealPayloadResponse, string, error) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L2BlockRef, error) } @@ -273,7 +273,7 @@ func (e *EngineController) ConfirmPayload(ctx context.Context, agossip async.Asy updateSafe := e.buildingSafe && e.safeAttrs != nil && e.safeAttrs.IsLastInSpan var envelope *eth.ExecutionPayloadEnvelope - if e.combinedAPI { + if e.combinedAPI && !e.buildingSafe { envelope, errTyp, err = confirmPayloadCombined(ctx, e.log, e.engine, fc, e.buildingInfo, updateSafe, agossip, sequencerConductor, e.metrics) } else { envelope, errTyp, err = confirmPayload(ctx, e.log, e.engine, fc, e.buildingInfo, updateSafe, agossip, sequencerConductor, e.metrics) diff --git a/op-node/rollup/derive/engine_update.go b/op-node/rollup/derive/engine_update.go index b67b3540c6..f7ce54b438 100644 --- a/op-node/rollup/derive/engine_update.go +++ b/op-node/rollup/derive/engine_update.go @@ -209,6 +209,7 @@ func confirmPayload( return envelope, BlockInsertOK, nil } +// confirmPayloadCombined is equal to confirmPayload but using engine_opSealPayload API to combine GetPayload, NewPayload, ForckchoiceUpdated calls func confirmPayloadCombined( ctx context.Context, log log.Logger, @@ -221,15 +222,15 @@ func confirmPayloadCombined( metrics Metrics, ) (out *eth.ExecutionPayloadEnvelope, errTyp BlockInsertionErrType, err error) { start := time.Now() - type SealPayloadRet struct { - res *eth.SealPayloadResponse - err error + res *eth.SealPayloadResponse + errStage string + err error } sealPayloadRetCh := make(chan SealPayloadRet) go func() { - res, err := eng.SealPayload(ctx, payloadInfo, &fc, false) - sealPayloadRetCh <- SealPayloadRet{res, err} + res, errStage, err := eng.SealPayload(ctx, payloadInfo, &fc, false) + sealPayloadRetCh <- SealPayloadRet{res, errStage, err} }() type GetPayloadRet struct { @@ -242,53 +243,84 @@ func confirmPayloadCombined( getPayloadRetCh <- GetPayloadRet{res, err} }() - sealPayloadRet := <-sealPayloadRetCh - sealRes := sealPayloadRet.res - err = sealPayloadRet.err - if err != nil { - var inputErr eth.InputError - if errors.As(err, &inputErr) { - switch inputErr.Code { - case eth.InvalidForkchoiceState: - return nil, BlockInsertPayloadErr, fmt.Errorf("post-block-creation forkchoice update was inconsistent with engine, need reset to resolve: %w", inputErr.Unwrap()) - default: - return nil, BlockInsertPrestateErr, fmt.Errorf("unexpected error code in forkchoice-updated response: %w", err) + getPayloadRet := <-getPayloadRetCh + envelope := getPayloadRet.res + getPayloadErr := getPayloadRet.err + validatePayloadErr := error(nil) + if getPayloadErr == nil { + payload := envelope.ExecutionPayload + validatePayloadErr = sanityCheckPayload(payload) + if validatePayloadErr == nil { + // TODO handle sequencerConductor component + if err := sequencerConductor.CommitUnsafePayload(ctx, envelope); err != nil { + log.Error("failed to commit unsafe payload to conductor", "payloadID", payloadInfo.ID, "err", err) } - } else { - return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to make the new L2 block canonical via forkchoice: %w", err) + agossip.Gossip(envelope) } } - if sealRes.PayloadStatus.Status != eth.ExecutionValid { - switch sealRes.Stage { - case "newPayload": - if sealRes.PayloadStatus.Status == eth.ExecutionInvalid || sealRes.PayloadStatus.Status == eth.ExecutionInvalidBlockHash { - return nil, BlockInsertPayloadErr, fmt.Errorf("new payload BlockInsertPayloadErr %v", sealRes.PayloadStatus.ValidationError) + sealPayloadRet := <-sealPayloadRetCh + sealRes := sealPayloadRet.res + errStage := sealPayloadRet.errStage + sealPayloadErr := sealPayloadRet.err + switch errStage { + case eth.GetPayloadStage: + return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to get execution payload: %w", sealPayloadErr) + case eth.NewPayloadStage: + if sealPayloadErr != nil { + return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to insert execution payload: %w", sealPayloadErr) + } + if sealRes.PayloadStatus.Status == eth.ExecutionInvalid || sealRes.PayloadStatus.Status == eth.ExecutionInvalidBlockHash { + agossip.Clear() + log.Error("Seal payload failed to new payload", "payloadID", payloadInfo.ID, "status", sealRes.PayloadStatus) + return nil, BlockInsertPayloadErr, fmt.Errorf("failed to new payload, status: %s, validationError: %v", sealRes.PayloadStatus.Status, sealRes.PayloadStatus.ValidationError) + } + if sealRes.PayloadStatus.Status != eth.ExecutionValid { + return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to new payload, status: %s, validationError: %v", sealRes.PayloadStatus.Status, sealRes.PayloadStatus.ValidationError) + } + case eth.ForkchoiceUpdatedStage: + if sealPayloadErr != nil { + var inputErr eth.InputError + if errors.As(sealPayloadErr, &inputErr) { + switch inputErr.Code { + case eth.InvalidForkchoiceState: + // if we succeed to update the forkchoice pre-payload, but fail post-payload, then it is a payload error + agossip.Clear() + return nil, BlockInsertPayloadErr, fmt.Errorf("post-block-creation forkchoice update was inconsistent with engine, need reset to resolve: %w", inputErr.Unwrap()) + default: + agossip.Clear() + return nil, BlockInsertPrestateErr, fmt.Errorf("unexpected error code in forkchoice-updated response: %w", sealPayloadErr) + } + } else { + agossip.Clear() + return nil, BlockInsertTemporaryErr, NewTemporaryError(fmt.Errorf("failed to make the new L2 block canonical via forkchoice: %w", sealPayloadErr)) } - return nil, BlockInsertTemporaryErr, fmt.Errorf("new payload BlockInsertTemporaryErr %v", sealRes.PayloadStatus.ValidationError) - case "forkchoiceUpdate": - return nil, BlockInsertPayloadErr, fmt.Errorf("forkchoiceUpdate BlockInsertPayloadErr %v", sealRes.PayloadStatus.ValidationError) + } + if sealRes.PayloadStatus.Status != eth.ExecutionValid { + agossip.Clear() + return nil, BlockInsertPayloadErr, fmt.Errorf("failed to forkchoice update, status: %s, validationError: %v", sealRes.PayloadStatus.Status, sealRes.PayloadStatus.ValidationError) + } + default: + if sealPayloadErr != nil { + return nil, BlockInsertTemporaryErr, NewTemporaryError(fmt.Errorf("failed to seal payload: %w", sealPayloadErr)) + } + if sealRes.PayloadStatus.Status != eth.ExecutionValid { + agossip.Clear() + return nil, BlockInsertPayloadErr, fmt.Errorf("failed to seal payload, status: %s, validationError: %v", sealRes.PayloadStatus.Status, sealRes.PayloadStatus.ValidationError) } } - getPayloadRet := <-getPayloadRetCh - envelope := getPayloadRet.res - err = getPayloadRet.err - if err != nil { - return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to get sealed payload: %w", err) + if getPayloadErr != nil { + return nil, BlockInsertTemporaryErr, NewTemporaryError(fmt.Errorf("failed to get payload: %w", getPayloadErr)) } - payload := envelope.ExecutionPayload - if err := sanityCheckPayload(payload); err != nil { - return nil, BlockInsertPayloadErr, err - } - if err := sequencerConductor.CommitUnsafePayload(ctx, envelope); err != nil { - return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to commit unsafe payload to conductor: %w", err) + if validatePayloadErr != nil { + return nil, BlockInsertPayloadErr, NewCriticalError(fmt.Errorf("failed to validate payload but seal succeed: %w", validatePayloadErr)) } - agossip.Gossip(envelope) - agossip.Clear() + agossip.Clear() + payload := envelope.ExecutionPayload metrics.RecordSequencerStepTime("sealPayload", time.Since(start)) - log.Info("perf-trace inserted block", "hash", payload.BlockHash, "number", uint64(payload.BlockNumber), "duration", time.Since(start), + log.Info("perf-trace sealed block", "hash", payload.BlockHash, "number", uint64(payload.BlockNumber), "duration", time.Since(start), "state_root", payload.StateRoot, "timestamp", uint64(payload.Timestamp), "parent", payload.ParentHash, "prev_randao", payload.PrevRandao, "fee_recipient", payload.FeeRecipient, "txs", len(payload.Transactions), "update_safe", updateSafe) diff --git a/op-node/rollup/types.go b/op-node/rollup/types.go index 6b1449949c..3d3aa20759 100644 --- a/op-node/rollup/types.go +++ b/op-node/rollup/types.go @@ -508,6 +508,16 @@ func (c *Config) GetPayloadVersion(timestamp uint64) eth.EngineAPIMethod { } } +// SealPayloadVersion returns the EngineAPIMethod suitable for the chain hard fork version. +func (c *Config) SealPayloadVersion(timestamp uint64) eth.EngineAPIMethod { + if c.IsEcotone(timestamp) { + // Cancun + return eth.SealPayloadV3 + } else { + return eth.SealPayloadV2 + } +} + // GetOPPlasmaConfig validates and returns the plasma config from the rollup config. func (c *Config) GetOPPlasmaConfig() (plasma.Config, error) { if c.PlasmaConfig == nil { diff --git a/op-service/eth/types.go b/op-service/eth/types.go index 5dde9d656f..b191ceb0b0 100644 --- a/op-service/eth/types.go +++ b/op-service/eth/types.go @@ -26,6 +26,12 @@ const ( InvalidPayloadAttributes ErrorCode = -38003 // Payload attributes are invalid / inconsistent. ) +const ( + GetPayloadStage = "getPayload" + NewPayloadStage = "newPayload" + ForkchoiceUpdatedStage = "forkchoiceUpdated" +) + var ErrBedrockScalarPaddingNotEmpty = errors.New("version 0 scalar value has non-empty padding") // InputError distinguishes an user-input error from regular rpc errors, @@ -368,7 +374,7 @@ type ForkchoiceUpdatedResult struct { } type SealPayloadResponse struct { - Stage string `json:"stage"` + ErrStage string `json:"errStage"` PayloadStatus PayloadStatusV1 `json:"payloadStatus"` Payload *ExecutionPayloadEnvelope `json:"payload"` } @@ -518,4 +524,7 @@ const ( GetPayloadV2 EngineAPIMethod = "engine_getPayloadV2" GetPayloadV3 EngineAPIMethod = "engine_getPayloadV3" + + SealPayloadV2 EngineAPIMethod = "engine_opSealPayloadV2" + SealPayloadV3 EngineAPIMethod = "engine_opSealPayloadV3" ) diff --git a/op-service/sources/engine_client.go b/op-service/sources/engine_client.go index 7c8ac2f1d8..6265fef5b6 100644 --- a/op-service/sources/engine_client.go +++ b/op-service/sources/engine_client.go @@ -61,6 +61,7 @@ type EngineVersionProvider interface { ForkchoiceUpdatedVersion(attr *eth.PayloadAttributes) eth.EngineAPIMethod NewPayloadVersion(timestamp uint64) eth.EngineAPIMethod GetPayloadVersion(timestamp uint64) eth.EngineAPIMethod + SealPayloadVersion(timestamp uint64) eth.EngineAPIMethod } func NewEngineAPIClient(rpc client.RPC, l log.Logger, evp EngineVersionProvider) *EngineAPIClient { @@ -178,37 +179,62 @@ func (s *EngineAPIClient) GetPayload(ctx context.Context, payloadInfo eth.Payloa return &result, nil } -func (s *EngineAPIClient) SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState, needPayload bool) (*eth.SealPayloadResponse, error) { +// SealPayload is a combined call of GetPayload, NewPayload, ForkchoiceUpdated via engine_opSealPayload API +func (s *EngineAPIClient) SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState, needPayload bool) (*eth.SealPayloadResponse, string, error) { e := s.log.New("payload_id", payloadInfo.ID) e.Trace("sealing payload") + sCtx, sCancel := context.WithTimeout(ctx, time.Second*10) + defer sCancel() var result eth.SealPayloadResponse - method := "engine_opSealPayload" + method := s.evp.SealPayloadVersion(payloadInfo.Timestamp) start := time.Now() - err := s.RPC.CallContext(ctx, &result, string(method), payloadInfo.ID, fc, needPayload) + err := s.RPC.CallContext(sCtx, &result, string(method), payloadInfo.ID, fc, needPayload) e.Info("perf-trace eng.SealPayload", "duration", time.Since(start), "payload", payloadInfo.ID) if err != nil { - e.Warn("Failed to seal payload", "payload_id", payloadInfo.ID, "err", err) - if rpcErr, ok := err.(rpc.Error); ok { - code := eth.ErrorCode(rpcErr.ErrorCode()) - switch code { - case eth.UnknownPayload: - return nil, eth.InputError{ - Inner: err, - Code: code, + e.Error("Failed to seal payload", "payload_id", payloadInfo.ID, "err", err) + switch result.ErrStage { + case eth.GetPayloadStage: + if rpcErr, ok := err.(rpc.Error); ok { + code := eth.ErrorCode(rpcErr.ErrorCode()) + switch code { + case eth.UnknownPayload: + return nil, result.ErrStage, eth.InputError{ + Inner: err, + Code: code, + } + default: + return nil, result.ErrStage, fmt.Errorf("seal payload unrecognized rpc error: %w", err) } - case eth.InvalidForkchoiceState, eth.InvalidPayloadAttributes: - return nil, eth.InputError{ - Inner: err, - Code: code, + } + return nil, result.ErrStage, err + case eth.NewPayloadStage: + e.Error("Seal payload execution failed", "err", err) + if strings.Contains(err.Error(), derive.ErrELSyncTriggerUnexpected.Error()) { + result.PayloadStatus.Status = eth.ExecutionSyncing // why? + return &result, result.ErrStage, err + } + return nil, result.ErrStage, fmt.Errorf("seal payload failed to execute payload: %w", err) + case eth.ForkchoiceUpdatedStage: + e.Error("Seal payload failed to share forkchoice-updated signal", "err", err) + if rpcErr, ok := err.(rpc.Error); ok { + code := eth.ErrorCode(rpcErr.ErrorCode()) + switch code { + case eth.InvalidForkchoiceState, eth.InvalidPayloadAttributes: + return nil, result.ErrStage, eth.InputError{ + Inner: err, + Code: code, + } + default: + return nil, result.ErrStage, fmt.Errorf("seal payload unrecognized rpc error: %w", err) } - default: - return nil, fmt.Errorf("unrecognized rpc error: %w", err) } + return nil, result.ErrStage, err + default: + return nil, result.ErrStage, err } - return nil, err } - e.Trace("Received payload") - return &result, nil + e.Trace("Sealed payload") + return &result, result.ErrStage, nil } func (s *EngineAPIClient) SignalSuperchainV1(ctx context.Context, recommended, required params.ProtocolVersion) (params.ProtocolVersion, error) { From 9d61cafb790eb6ea629c9609e51dd2498d3f1c7f Mon Sep 17 00:00:00 2001 From: bnoieh <135800952+bnoieh@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:29:05 +0800 Subject: [PATCH 4/6] chore: optimize code --- op-node/rollup/derive/engine_update.go | 14 +++++--------- op-service/sources/engine_client.go | 6 ++---- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/op-node/rollup/derive/engine_update.go b/op-node/rollup/derive/engine_update.go index f7ce54b438..682945482e 100644 --- a/op-node/rollup/derive/engine_update.go +++ b/op-node/rollup/derive/engine_update.go @@ -227,7 +227,7 @@ func confirmPayloadCombined( errStage string err error } - sealPayloadRetCh := make(chan SealPayloadRet) + sealPayloadRetCh := make(chan SealPayloadRet, 1) go func() { res, errStage, err := eng.SealPayload(ctx, payloadInfo, &fc, false) sealPayloadRetCh <- SealPayloadRet{res, errStage, err} @@ -237,7 +237,7 @@ func confirmPayloadCombined( res *eth.ExecutionPayloadEnvelope err error } - getPayloadRetCh := make(chan GetPayloadRet) + getPayloadRetCh := make(chan GetPayloadRet, 1) go func() { res, err := eng.GetPayload(ctx, payloadInfo) getPayloadRetCh <- GetPayloadRet{res, err} @@ -301,12 +301,8 @@ func confirmPayloadCombined( return nil, BlockInsertPayloadErr, fmt.Errorf("failed to forkchoice update, status: %s, validationError: %v", sealRes.PayloadStatus.Status, sealRes.PayloadStatus.ValidationError) } default: - if sealPayloadErr != nil { - return nil, BlockInsertTemporaryErr, NewTemporaryError(fmt.Errorf("failed to seal payload: %w", sealPayloadErr)) - } - if sealRes.PayloadStatus.Status != eth.ExecutionValid { - agossip.Clear() - return nil, BlockInsertPayloadErr, fmt.Errorf("failed to seal payload, status: %s, validationError: %v", sealRes.PayloadStatus.Status, sealRes.PayloadStatus.ValidationError) + if sealPayloadErr != nil || sealRes.PayloadStatus.Status != eth.ExecutionValid { + return nil, BlockInsertTemporaryErr, NewTemporaryError(fmt.Errorf("failed to seal payload, status: %s, err: %w", sealRes.PayloadStatus.Status, sealPayloadErr)) } } @@ -320,7 +316,7 @@ func confirmPayloadCombined( agossip.Clear() payload := envelope.ExecutionPayload metrics.RecordSequencerStepTime("sealPayload", time.Since(start)) - log.Info("perf-trace sealed block", "hash", payload.BlockHash, "number", uint64(payload.BlockNumber), "duration", time.Since(start), + log.Info("Sealed block succeed", "hash", payload.BlockHash, "number", uint64(payload.BlockNumber), "state_root", payload.StateRoot, "timestamp", uint64(payload.Timestamp), "parent", payload.ParentHash, "prev_randao", payload.PrevRandao, "fee_recipient", payload.FeeRecipient, "txs", len(payload.Transactions), "update_safe", updateSafe) diff --git a/op-service/sources/engine_client.go b/op-service/sources/engine_client.go index 6265fef5b6..68610ab26b 100644 --- a/op-service/sources/engine_client.go +++ b/op-service/sources/engine_client.go @@ -140,7 +140,7 @@ func (s *EngineAPIClient) NewPayload(ctx context.Context, payload *eth.Execution e.Trace("Received payload execution result", "status", result.Status, "latestValidHash", result.LatestValidHash, "message", result.ValidationError) if err != nil { if strings.Contains(err.Error(), derive.ErrELSyncTriggerUnexpected.Error()) { - result.Status = eth.ExecutionSyncing // why? + result.Status = eth.ExecutionSyncing return &result, err } e.Error("Payload execution failed", "err", err) @@ -187,9 +187,7 @@ func (s *EngineAPIClient) SealPayload(ctx context.Context, payloadInfo eth.Paylo defer sCancel() var result eth.SealPayloadResponse method := s.evp.SealPayloadVersion(payloadInfo.Timestamp) - start := time.Now() err := s.RPC.CallContext(sCtx, &result, string(method), payloadInfo.ID, fc, needPayload) - e.Info("perf-trace eng.SealPayload", "duration", time.Since(start), "payload", payloadInfo.ID) if err != nil { e.Error("Failed to seal payload", "payload_id", payloadInfo.ID, "err", err) switch result.ErrStage { @@ -210,7 +208,7 @@ func (s *EngineAPIClient) SealPayload(ctx context.Context, payloadInfo eth.Paylo case eth.NewPayloadStage: e.Error("Seal payload execution failed", "err", err) if strings.Contains(err.Error(), derive.ErrELSyncTriggerUnexpected.Error()) { - result.PayloadStatus.Status = eth.ExecutionSyncing // why? + result.PayloadStatus.Status = eth.ExecutionSyncing return &result, result.ErrStage, err } return nil, result.ErrStage, fmt.Errorf("seal payload failed to execute payload: %w", err) From 644cc5c7aa450ee611995581b870d9477e73807b Mon Sep 17 00:00:00 2001 From: bnoieh <135800952+bnoieh@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:49:58 +0800 Subject: [PATCH 5/6] chore: fix ci --- op-node/rollup/attributes/attributes_test.go | 14 +++++++------- op-node/rollup/derive/engine_queue_test.go | 8 ++++---- op-service/testutils/mock_engine.go | 9 +++++++++ 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/op-node/rollup/attributes/attributes_test.go b/op-node/rollup/attributes/attributes_test.go index 4f66b93fd2..99510c4854 100644 --- a/op-node/rollup/attributes/attributes_test.go +++ b/op-node/rollup/attributes/attributes_test.go @@ -181,7 +181,7 @@ func TestAttributesHandler(t *testing.T) { t.Run("drop stale attributes", func(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) eng := &testutils.MockEngine{} - ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}) + ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}, false) ah := NewAttributesHandler(logger, cfg, ec, eng) defer eng.AssertExpectations(t) @@ -195,7 +195,7 @@ func TestAttributesHandler(t *testing.T) { t.Run("pending gets reorged", func(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) eng := &testutils.MockEngine{} - ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}) + ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}, false) ah := NewAttributesHandler(logger, cfg, ec, eng) defer eng.AssertExpectations(t) @@ -210,7 +210,7 @@ func TestAttributesHandler(t *testing.T) { t.Run("consolidation fails", func(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) eng := &testutils.MockEngine{} - ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}) + ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}, false) ah := NewAttributesHandler(logger, cfg, ec, eng) ec.SetUnsafeHead(refA1) @@ -264,7 +264,7 @@ func TestAttributesHandler(t *testing.T) { fn := func(t *testing.T, lastInSpan bool) { logger := testlog.Logger(t, log.LevelInfo) eng := &testutils.MockEngine{} - ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}) + ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}, false) ah := NewAttributesHandler(logger, cfg, ec, eng) ec.SetUnsafeHead(refA1) @@ -323,7 +323,7 @@ func TestAttributesHandler(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) eng := &testutils.MockEngine{} - ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}) + ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}, false) ah := NewAttributesHandler(logger, cfg, ec, eng) ec.SetUnsafeHead(refA0) @@ -374,7 +374,7 @@ func TestAttributesHandler(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) eng := &testutils.MockEngine{} - ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}) + ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}, false) ah := NewAttributesHandler(logger, cfg, ec, eng) ec.SetUnsafeHead(refA0) @@ -398,7 +398,7 @@ func TestAttributesHandler(t *testing.T) { t.Run("no attributes", func(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) eng := &testutils.MockEngine{} - ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}) + ec := derive.NewEngineController(eng, logger, metrics.NoopMetrics, cfg, &sync.Config{SyncMode: sync.CLSync}, false) ah := NewAttributesHandler(logger, cfg, ec, eng) defer eng.AssertExpectations(t) diff --git a/op-node/rollup/derive/engine_queue_test.go b/op-node/rollup/derive/engine_queue_test.go index 80e755aac8..9b92e795e7 100644 --- a/op-node/rollup/derive/engine_queue_test.go +++ b/op-node/rollup/derive/engine_queue_test.go @@ -291,7 +291,7 @@ func TestEngineQueue_ResetWhenUnsafeOriginNotCanonical(t *testing.T) { SyncMode: sync.CLSync, SkipSyncStartCheck: false, ELTriggerGap: 0, - }) + }, false) eq := NewEngineQueue(logger, cfg, eng, ec, metrics, prev, l1F, &sync.Config{}, safedb.Disabled, noopFinality{}, &fakeAttributesHandler{}) require.ErrorIs(t, eq.Reset(context.Background(), eth.L1BlockRef{}, eth.SystemConfig{}), io.EOF) @@ -634,7 +634,7 @@ func TestVerifyNewL1Origin(t *testing.T) { SyncMode: sync.CLSync, SkipSyncStartCheck: false, ELTriggerGap: 0, - }) + }, false) eq := NewEngineQueue(logger, cfg, eng, ec, metrics, prev, l1F, &sync.Config{}, safedb.Disabled, noopFinality{}, &fakeAttributesHandler{}) require.ErrorIs(t, eq.Reset(context.Background(), eth.L1BlockRef{}, eth.SystemConfig{}), io.EOF) @@ -738,7 +738,7 @@ func TestBlockBuildingRace(t *testing.T) { SyncMode: sync.CLSync, SkipSyncStartCheck: false, ELTriggerGap: 0, - }) + }, false) attribHandler := &fakeAttributesHandler{} eq := NewEngineQueue(logger, cfg, eng, ec, metrics, prev, l1F, &sync.Config{}, safedb.Disabled, noopFinality{}, attribHandler) require.ErrorIs(t, eq.Reset(context.Background(), eth.L1BlockRef{}, eth.SystemConfig{}), io.EOF) @@ -858,7 +858,7 @@ func TestResetLoop(t *testing.T) { SyncMode: sync.CLSync, SkipSyncStartCheck: false, ELTriggerGap: 0, - }) + }, false) eq := NewEngineQueue(logger, cfg, eng, ec, metrics.NoopMetrics, prev, l1F, &sync.Config{}, safedb.Disabled, noopFinality{}, &fakeAttributesHandler{}) eq.ec.SetUnsafeHead(refA2) eq.ec.SetSafeHead(refA1) diff --git a/op-service/testutils/mock_engine.go b/op-service/testutils/mock_engine.go index fa1f716d1c..7d33518963 100644 --- a/op-service/testutils/mock_engine.go +++ b/op-service/testutils/mock_engine.go @@ -40,6 +40,15 @@ func (m *MockEngine) ExpectNewPayload(payload *eth.ExecutionPayload, parentBeaco m.Mock.On("NewPayload", mustJson(payload), mustJson(parentBeaconBlockRoot)).Once().Return(result, err) } +func (m *MockEngine) SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState, needPayload bool) (*eth.SealPayloadResponse, string, error) { + out := m.Mock.Called(payloadInfo.ID, fc, needPayload) + return out.Get(0).(*eth.SealPayloadResponse), out.Get(1).(string), out.Error(1) +} + +func (m *MockEngine) ExpectSealPayload(payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState, needPayload bool, result *eth.SealPayloadResponse, errStage string, err error) { + m.Mock.On("SealPayload", payloadInfo, fc, needPayload).Once().Return(result, errStage, err) +} + func (m *MockEngine) CachePayloadByHash(payload *eth.ExecutionPayloadEnvelope) bool { return true } From bafaca8884319d63c7403afb22d65807410885e1 Mon Sep 17 00:00:00 2001 From: bnoieh <135800952+bnoieh@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:12:19 +0800 Subject: [PATCH 6/6] chore: fix ci --- op-e2e/actions/l2_verifier.go | 2 +- op-program/client/driver/driver.go | 2 +- op-program/client/l2/engine.go | 4 ++++ op-wheel/engine/version_provider.go | 11 +++++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/op-e2e/actions/l2_verifier.go b/op-e2e/actions/l2_verifier.go index 4fd2607790..7130f943b6 100644 --- a/op-e2e/actions/l2_verifier.go +++ b/op-e2e/actions/l2_verifier.go @@ -71,7 +71,7 @@ type safeDB interface { func NewL2Verifier(t Testing, log log.Logger, l1 derive.L1Fetcher, blobsSrc derive.L1BlobsFetcher, plasmaSrc driver.PlasmaIface, eng L2API, cfg *rollup.Config, syncCfg *sync.Config, safeHeadListener safeDB) *L2Verifier { metrics := &testutils.TestDerivationMetrics{} - engine := derive.NewEngineController(eng, log, metrics, cfg, syncCfg) + engine := derive.NewEngineController(eng, log, metrics, cfg, syncCfg, false) clSync := clsync.NewCLSync(log, cfg, metrics, engine) diff --git a/op-program/client/driver/driver.go b/op-program/client/driver/driver.go index 46fcade40d..eab8a41de0 100644 --- a/op-program/client/driver/driver.go +++ b/op-program/client/driver/driver.go @@ -58,7 +58,7 @@ func NewDriver(logger log.Logger, cfg *rollup.Config, l1Source derive.L1Fetcher, SyncMode: sync.CLSync, SkipSyncStartCheck: false, ELTriggerGap: 0, - }) + }, false) attributesHandler := attributes.NewAttributesHandler(logger, cfg, engine, l2Source) pipeline := derive.NewDerivationPipeline(logger, cfg, l1Source, l1BlobsSource, plasma.Disabled, l2Source, engine, metrics.NoopMetrics, &sync.Config{}, safedb.Disabled, NoopFinalizer{}, attributesHandler) pipeline.Reset() diff --git a/op-program/client/l2/engine.go b/op-program/client/l2/engine.go index 34b8a5115d..9dac9a7825 100644 --- a/op-program/client/l2/engine.go +++ b/op-program/client/l2/engine.go @@ -89,6 +89,10 @@ func (o *OracleEngine) NewPayload(ctx context.Context, payload *eth.ExecutionPay } } +func (o *OracleEngine) SealPayload(ctx context.Context, payloadInfo eth.PayloadInfo, fc *eth.ForkchoiceState, needPayload bool) (*eth.SealPayloadResponse, string, error) { + return nil, "", nil +} + func (o *OracleEngine) PayloadByHash(ctx context.Context, hash common.Hash) (*eth.ExecutionPayloadEnvelope, error) { block := o.backend.GetBlockByHash(hash) if block == nil { diff --git a/op-wheel/engine/version_provider.go b/op-wheel/engine/version_provider.go index d3aaa377e1..ae39d949c7 100644 --- a/op-wheel/engine/version_provider.go +++ b/op-wheel/engine/version_provider.go @@ -42,3 +42,14 @@ func (v StaticVersionProvider) GetPayloadVersion(uint64) eth.EngineAPIMethod { panic("invalid Engine API version: " + strconv.Itoa(int(v))) } } + +func (v StaticVersionProvider) SealPayloadVersion(uint64) eth.EngineAPIMethod { + switch int(v) { + case 1, 2: + return eth.SealPayloadV2 + case 3: + return eth.SealPayloadV3 + default: + panic("invalid Engine API version: " + strconv.Itoa(int(v))) + } +}