l1_retrieval.go 2.35 KB
Newer Older
protolambda's avatar
protolambda committed
1 2 3 4
package derive

import (
	"context"
5
	"fmt"
protolambda's avatar
protolambda committed
6 7
	"io"

8
	"github.com/ethereum/go-ethereum/common"
protolambda's avatar
protolambda committed
9
	"github.com/ethereum/go-ethereum/log"
10

11
	"github.com/ethereum-optimism/optimism/op-service/eth"
protolambda's avatar
protolambda committed
12 13
)

14
type DataAvailabilitySource interface {
15
	OpenData(ctx context.Context, ref eth.L1BlockRef, batcherAddr common.Address) (DataIter, error)
16 17
}

18 19
type NextBlockProvider interface {
	NextL1Block(context.Context) (eth.L1BlockRef, error)
20
	Origin() eth.L1BlockRef
21
	SystemConfig() eth.SystemConfig
22 23
}

protolambda's avatar
protolambda committed
24 25 26
type L1Retrieval struct {
	log     log.Logger
	dataSrc DataAvailabilitySource
27
	prev    NextBlockProvider
protolambda's avatar
protolambda committed
28 29 30 31

	datas DataIter
}

pengin7384's avatar
pengin7384 committed
32
var _ ResettableStage = (*L1Retrieval)(nil)
protolambda's avatar
protolambda committed
33

34
func NewL1Retrieval(log log.Logger, dataSrc DataAvailabilitySource, prev NextBlockProvider) *L1Retrieval {
protolambda's avatar
protolambda committed
35 36 37
	return &L1Retrieval{
		log:     log,
		dataSrc: dataSrc,
38
		prev:    prev,
protolambda's avatar
protolambda committed
39 40 41
	}
}

42 43
func (l1r *L1Retrieval) Origin() eth.L1BlockRef {
	return l1r.prev.Origin()
protolambda's avatar
protolambda committed
44 45
}

46
// NextData does an action in the L1 Retrieval stage
47 48
// If there is data, it pushes it to the next stage.
// If there is no more data open ourselves if we are closed or close ourselves if we are open
49 50 51
func (l1r *L1Retrieval) NextData(ctx context.Context) ([]byte, error) {
	if l1r.datas == nil {
		next, err := l1r.prev.NextL1Block(ctx)
52
		if err == io.EOF {
53
			return nil, io.EOF
protolambda's avatar
protolambda committed
54
		} else if err != nil {
55
			return nil, err
protolambda's avatar
protolambda committed
56
		}
57 58 59
		if l1r.datas, err = l1r.dataSrc.OpenData(ctx, next, l1r.prev.SystemConfig().BatcherAddr); err != nil {
			return nil, fmt.Errorf("failed to open data source: %w", err)
		}
60 61 62 63 64 65 66 67 68 69
	}

	l1r.log.Debug("fetching next piece of data")
	data, err := l1r.datas.Next(ctx)
	if err == io.EOF {
		l1r.datas = nil
		return nil, io.EOF
	} else if err != nil {
		// CalldataSource appropriately wraps the error so avoid double wrapping errors here.
		return nil, err
70
	} else {
71
		return data, nil
protolambda's avatar
protolambda committed
72 73 74
	}
}

pengin7384's avatar
pengin7384 committed
75
// Reset re-initializes the L1 Retrieval stage to block of it's `next` progress.
76
// Note that we open up the `l1r.datas` here because it is required to maintain the
77
// internal invariants that later propagate up the derivation pipeline.
78
func (l1r *L1Retrieval) Reset(ctx context.Context, base eth.L1BlockRef, sysCfg eth.SystemConfig) error {
79 80 81 82
	var err error
	if l1r.datas, err = l1r.dataSrc.OpenData(ctx, base, sysCfg.BatcherAddr); err != nil {
		return fmt.Errorf("failed to open data source: %w", err)
	}
83
	l1r.log.Info("Reset of L1Retrieval done", "origin", base)
protolambda's avatar
protolambda committed
84 85
	return io.EOF
}