github.com/ethereum-optimism/optimism@v1.7.2/op-node/rollup/driver/origin_selector.go (about) 1 package driver 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 8 "github.com/ethereum/go-ethereum" 9 "github.com/ethereum/go-ethereum/log" 10 11 "github.com/ethereum-optimism/optimism/op-node/rollup" 12 "github.com/ethereum-optimism/optimism/op-node/rollup/derive" 13 "github.com/ethereum-optimism/optimism/op-service/eth" 14 ) 15 16 type L1Blocks interface { 17 derive.L1BlockRefByHashFetcher 18 derive.L1BlockRefByNumberFetcher 19 } 20 21 type L1OriginSelector struct { 22 log log.Logger 23 cfg *rollup.Config 24 25 l1 L1Blocks 26 } 27 28 func NewL1OriginSelector(log log.Logger, cfg *rollup.Config, l1 L1Blocks) *L1OriginSelector { 29 return &L1OriginSelector{ 30 log: log, 31 cfg: cfg, 32 l1: l1, 33 } 34 } 35 36 // FindL1Origin determines what the next L1 Origin should be. 37 // The L1 Origin is either the L2 Head's Origin, or the following L1 block 38 // if the next L2 block's time is greater than or equal to the L2 Head's Origin. 39 func (los *L1OriginSelector) FindL1Origin(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) { 40 // Grab a reference to the current L1 origin block. This call is by hash and thus easily cached. 41 currentOrigin, err := los.l1.L1BlockRefByHash(ctx, l2Head.L1Origin.Hash) 42 if err != nil { 43 return eth.L1BlockRef{}, err 44 } 45 log := los.log.New("current", currentOrigin, "current_time", currentOrigin.Time, 46 "l2_head", l2Head, "l2_head_time", l2Head.Time) 47 48 // If we are past the sequencer depth, we may want to advance the origin, but need to still 49 // check the time of the next origin. 50 pastSeqDrift := l2Head.Time+los.cfg.BlockTime > currentOrigin.Time+los.cfg.MaxSequencerDrift 51 if pastSeqDrift { 52 log.Warn("Next L2 block time is past the sequencer drift + current origin time") 53 } 54 55 // Attempt to find the next L1 origin block, where the next origin is the immediate child of 56 // the current origin block. 57 // The L1 source can be shimmed to hide new L1 blocks and enforce a sequencer confirmation distance. 58 nextOrigin, err := los.l1.L1BlockRefByNumber(ctx, currentOrigin.Number+1) 59 if err != nil { 60 if pastSeqDrift { 61 return eth.L1BlockRef{}, fmt.Errorf("cannot build next L2 block past current L1 origin %s by more than sequencer time drift, and failed to find next L1 origin: %w", currentOrigin, err) 62 } 63 if errors.Is(err, ethereum.NotFound) { 64 log.Debug("No next L1 block found, repeating current origin") 65 } else { 66 log.Error("Failed to get next origin. Falling back to current origin", "err", err) 67 } 68 return currentOrigin, nil 69 } 70 71 // If the next L2 block time is greater than the next origin block's time, we can choose to 72 // start building on top of the next origin. Sequencer implementation has some leeway here and 73 // could decide to continue to build on top of the previous origin until the Sequencer runs out 74 // of slack. For simplicity, we implement our Sequencer to always start building on the latest 75 // L1 block when we can. 76 if l2Head.Time+los.cfg.BlockTime >= nextOrigin.Time { 77 return nextOrigin, nil 78 } 79 80 return currentOrigin, nil 81 }