• Evan Richard's avatar
    Ecotone/Dencun implementation changes (#8707) · 705db877
    Evan Richard authored
    * op-node: L2 Dencun implementation updates
    
    init branch
    
    Update reference to Eclipse/Ecotone in specs.
    
    Pull in Danyal's deposit source and add additional tests.
    
    Add notion of ParentBeaconRoot and build a contract deploy tx in attributes.go.
    
    Add a test for activating dencun l2 fork after genesis.
    
    Add draft ecotone setup.
    
    Add first pass of Eclipse upgrade txns
    
    Fix tests/compile
    
    Code review feedback
    
    Obey linter.
    
    Move ecotone setup to helpers.go; get the ParentBeaconBlockRoot from the l1Info in attributes.go.
    
    chore(op-node): Add tests for Ecotone deposit transactions (#8746)
    
    * Source hash teEvanJRichard <evan@oplabs.co>
    
    dencun review fixes
    
    derive: ecotone upgradeTo abi encoding
    
    op-e2e: test L2 exclusion of blob-txs in Ecotone
    
    op-node/rollup: deduplicate ecotone activation helper func, fix rollup config var name
    
    op-chain-ops: clarify 4788 contract nonce
    
    op-node/rollup: add setEcotone to ecotone upgrade txs
    
    dencun review fixes
    
    Dencun: P2P / EngineAPI / ExecutionPayloadEnvelope changes
    
    Includes:
    - Pass through execution payload (Envelope type everywhere) by Danyal,
      extended by Proto
    - Fix ecotone upgrade txns, by Danyal
    - ci fixes by Danyal
    - P2P Req/Resp (version based encoding/decoding) by Danyal
    - EngineAPI v3 usage by Danyl, rebased by Proto on EngineController (from
      trianglesphere)
    - Block v3 Gossip validation, by Danyal
    - Block v3 Gossip publishing, by Proto
    
    Rebased on updated Ecotone / Dencun base branch
    
    op-e2e: fix upgrade-txs count in test
    
    op-node: fix l1 info scalar migration, implement dencun review suggestions
    
    op-node: more dencun review nit fixes
    
    op-node: rabbit suggestions, but fixed
    
    Fix nil pointer in p2p sync for Ecotone blocks
    
    dencun: fix more nits
    
    op-e2e: fix lint
    Co-authored-by: default avatarDanyal Prout <me@dany.al>
    Co-authored-by: default avatarprotolambda <proto@protolambda.com>
    Co-authored-by: default avatarEvanJRichard <evan@oplabs.co>
    
    * Add tests for attribute matching
    
    * Provide a no-op blob fetcher to prevent derivation error
    
    Fail tests when there is an unknown error
    
    Fix typo / empty array to nil
    
    Update L2 tests to ecotone / add additional checks
    
    * op-e2e: dencun action-test setup fixes
    
    * op-node: op-conductor dencun todo
    
    * dencun: fix review nit about parent beacon block root gossip check style
    
    ---------
    Co-authored-by: default avatarDanyal Prout <me@dany.al>
    Co-authored-by: default avatarprotolambda <proto@protolambda.com>
    705db877
api.go 5.04 KB
package node

import (
	"context"
	"fmt"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/log"

	"github.com/ethereum-optimism/optimism/op-node/rollup"
	"github.com/ethereum-optimism/optimism/op-node/version"
	"github.com/ethereum-optimism/optimism/op-service/eth"
	"github.com/ethereum-optimism/optimism/op-service/metrics"
	"github.com/ethereum-optimism/optimism/op-service/rpc"
)

type l2EthClient interface {
	InfoByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, error)
	// GetProof returns a proof of the account, it may return a nil result without error if the address was not found.
	// Optionally keys of the account storage trie can be specified to include with corresponding values in the proof.
	GetProof(ctx context.Context, address common.Address, storage []common.Hash, blockTag string) (*eth.AccountResult, error)
	OutputV0AtBlock(ctx context.Context, blockHash common.Hash) (*eth.OutputV0, error)
}

type driverClient interface {
	SyncStatus(ctx context.Context) (*eth.SyncStatus, error)
	BlockRefWithStatus(ctx context.Context, num uint64) (eth.L2BlockRef, *eth.SyncStatus, error)
	ResetDerivationPipeline(context.Context) error
	StartSequencer(ctx context.Context, blockHash common.Hash) error
	StopSequencer(context.Context) (common.Hash, error)
	SequencerActive(context.Context) (bool, error)
	OnUnsafeL2Payload(ctx context.Context, payload *eth.ExecutionPayloadEnvelope) error
}

type adminAPI struct {
	*rpc.CommonAdminAPI
	dr driverClient
}

func NewAdminAPI(dr driverClient, m metrics.RPCMetricer, log log.Logger) *adminAPI {
	return &adminAPI{
		CommonAdminAPI: rpc.NewCommonAdminAPI(m, log),
		dr:             dr,
	}
}

func (n *adminAPI) ResetDerivationPipeline(ctx context.Context) error {
	recordDur := n.M.RecordRPCServerRequest("admin_resetDerivationPipeline")
	defer recordDur()
	return n.dr.ResetDerivationPipeline(ctx)
}

func (n *adminAPI) StartSequencer(ctx context.Context, blockHash common.Hash) error {
	recordDur := n.M.RecordRPCServerRequest("admin_startSequencer")
	defer recordDur()
	return n.dr.StartSequencer(ctx, blockHash)
}

func (n *adminAPI) StopSequencer(ctx context.Context) (common.Hash, error) {
	recordDur := n.M.RecordRPCServerRequest("admin_stopSequencer")
	defer recordDur()
	return n.dr.StopSequencer(ctx)
}

func (n *adminAPI) SequencerActive(ctx context.Context) (bool, error) {
	recordDur := n.M.RecordRPCServerRequest("admin_sequencerActive")
	defer recordDur()
	return n.dr.SequencerActive(ctx)
}

// PostUnsafePayload is a special API that allow posting an unsafe payload to the L2 derivation pipeline.
// It should only be used by op-conductor for sequencer failover scenarios.
// TODO(ethereum-optimism/optimism#9064): op-conductor Dencun changes.
func (n *adminAPI) PostUnsafePayload(ctx context.Context, envelope *eth.ExecutionPayloadEnvelope) error {
	recordDur := n.M.RecordRPCServerRequest("admin_postUnsafePayload")
	defer recordDur()

	payload := envelope.ExecutionPayload
	if actual, ok := envelope.CheckBlockHash(); !ok {
		log.Error("payload has bad block hash", "bad_hash", payload.BlockHash.String(), "actual", actual.String())
		return fmt.Errorf("payload has bad block hash: %s, actual block hash is: %s", payload.BlockHash.String(), actual.String())
	}

	return n.dr.OnUnsafeL2Payload(ctx, envelope)
}

type nodeAPI struct {
	config *rollup.Config
	client l2EthClient
	dr     driverClient
	log    log.Logger
	m      metrics.RPCMetricer
}

func NewNodeAPI(config *rollup.Config, l2Client l2EthClient, dr driverClient, log log.Logger, m metrics.RPCMetricer) *nodeAPI {
	return &nodeAPI{
		config: config,
		client: l2Client,
		dr:     dr,
		log:    log,
		m:      m,
	}
}

func (n *nodeAPI) OutputAtBlock(ctx context.Context, number hexutil.Uint64) (*eth.OutputResponse, error) {
	recordDur := n.m.RecordRPCServerRequest("optimism_outputAtBlock")
	defer recordDur()

	ref, status, err := n.dr.BlockRefWithStatus(ctx, uint64(number))
	if err != nil {
		return nil, fmt.Errorf("failed to get L2 block ref with sync status: %w", err)
	}

	output, err := n.client.OutputV0AtBlock(ctx, ref.Hash)
	if err != nil {
		return nil, fmt.Errorf("failed to get L2 output at block %s: %w", ref, err)
	}
	return &eth.OutputResponse{
		Version:               output.Version(),
		OutputRoot:            eth.OutputRoot(output),
		BlockRef:              ref,
		WithdrawalStorageRoot: common.Hash(output.MessagePasserStorageRoot),
		StateRoot:             common.Hash(output.StateRoot),
		Status:                status,
	}, nil
}

func (n *nodeAPI) SyncStatus(ctx context.Context) (*eth.SyncStatus, error) {
	recordDur := n.m.RecordRPCServerRequest("optimism_syncStatus")
	defer recordDur()
	return n.dr.SyncStatus(ctx)
}

func (n *nodeAPI) RollupConfig(_ context.Context) (*rollup.Config, error) {
	recordDur := n.m.RecordRPCServerRequest("optimism_rollupConfig")
	defer recordDur()
	return n.config, nil
}

func (n *nodeAPI) Version(ctx context.Context) (string, error) {
	recordDur := n.m.RecordRPCServerRequest("optimism_version")
	defer recordDur()
	return version.Version + "-" + version.Meta, nil
}