derive.go 2.42 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
package tasks

import (
	"fmt"

	"github.com/ethereum-optimism/optimism/op-node/rollup"
	cldr "github.com/ethereum-optimism/optimism/op-program/client/driver"
	"github.com/ethereum-optimism/optimism/op-program/client/l1"
	"github.com/ethereum-optimism/optimism/op-program/client/l2"
	"github.com/ethereum-optimism/optimism/op-service/eth"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/log"
	"github.com/ethereum/go-ethereum/params"
)

type L2Source interface {
17 18 19 20
	L2OutputRoot(uint64) (common.Hash, eth.Bytes32, error)
}

type DerivationResult struct {
21
	Head       eth.L2BlockRef
22 23
	BlockHash  common.Hash
	OutputRoot eth.Bytes32
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
}

// RunDerivation executes the L2 state transition, given a minimal interface to retrieve data.
// Returns the L2BlockRef of the safe head reached and the output root at l2ClaimBlockNum or
// the final safe head when l1Head is reached if l2ClaimBlockNum is not reached.
// Derivation may stop prior to l1Head if the l2ClaimBlockNum has already been reached though
// this is not guaranteed.
func RunDerivation(
	logger log.Logger,
	cfg *rollup.Config,
	l2Cfg *params.ChainConfig,
	l1Head common.Hash,
	l2OutputRoot common.Hash,
	l2ClaimBlockNum uint64,
	l1Oracle l1.Oracle,
39
	l2Oracle l2.Oracle) (DerivationResult, error) {
40 41 42 43
	l1Source := l1.NewOracleL1Client(logger, l1Oracle, l1Head)
	l1BlobsSource := l1.NewBlobFetcher(logger, l1Oracle)
	engineBackend, err := l2.NewOracleBackedL2Chain(logger, l2Oracle, l1Oracle /* kzg oracle */, l2Cfg, l2OutputRoot)
	if err != nil {
44
		return DerivationResult{}, fmt.Errorf("failed to create oracle-backed L2 chain: %w", err)
45 46 47
	}
	l2Source := l2.NewOracleEngine(cfg, logger, engineBackend)

48
	logger.Info("Starting derivation", "chainID", cfg.L2ChainID)
49
	d := cldr.NewDriver(logger, cfg, l1Source, l1BlobsSource, l2Source, l2ClaimBlockNum)
50 51
	result, err := d.RunComplete()
	if err != nil {
52
		return DerivationResult{}, fmt.Errorf("failed to run program to completion: %w", err)
53
	}
54
	logger.Info("Derivation complete", "head", result)
55
	return loadOutputRoot(l2ClaimBlockNum, result, l2Source)
56 57
}

58 59
func loadOutputRoot(l2ClaimBlockNum uint64, head eth.L2BlockRef, src L2Source) (DerivationResult, error) {
	blockHash, outputRoot, err := src.L2OutputRoot(min(l2ClaimBlockNum, head.Number))
60
	if err != nil {
61
		return DerivationResult{}, fmt.Errorf("calculate L2 output root: %w", err)
62
	}
63
	return DerivationResult{
64
		Head:       head,
65 66 67
		BlockHash:  blockHash,
		OutputRoot: outputRoot,
	}, nil
68
}