github.com/ethereum-optimism/optimism@v1.7.2/op-node/rollup/driver/l1_state.go (about)

     1  package driver
     2  
     3  import (
     4  	"github.com/ethereum/go-ethereum/log"
     5  
     6  	"github.com/ethereum-optimism/optimism/op-service/eth"
     7  )
     8  
     9  type L1Metrics interface {
    10  	RecordL1ReorgDepth(d uint64)
    11  	RecordL1Ref(name string, ref eth.L1BlockRef)
    12  }
    13  
    14  // L1State tracks L1 head, safe and finalized blocks. It is not safe to write and read concurrently.
    15  type L1State struct {
    16  	log     log.Logger
    17  	metrics L1Metrics
    18  
    19  	// Latest recorded head, safe block and finalized block of the L1 Chain, independent of derivation work
    20  	l1Head      eth.L1BlockRef
    21  	l1Safe      eth.L1BlockRef
    22  	l1Finalized eth.L1BlockRef
    23  }
    24  
    25  func NewL1State(log log.Logger, metrics L1Metrics) *L1State {
    26  	return &L1State{
    27  		log:     log,
    28  		metrics: metrics,
    29  	}
    30  }
    31  
    32  func (s *L1State) HandleNewL1HeadBlock(head eth.L1BlockRef) {
    33  	// We don't need to do anything if the head hasn't changed.
    34  	if s.l1Head == (eth.L1BlockRef{}) {
    35  		s.log.Info("Received first L1 head signal", "l1_head", head)
    36  	} else if s.l1Head.Hash == head.Hash {
    37  		s.log.Trace("Received L1 head signal that is the same as the current head", "l1_head", head)
    38  	} else if s.l1Head.Hash == head.ParentHash {
    39  		// We got a new L1 block whose parent hash is the same as the current L1 head. Means we're
    40  		// dealing with a linear extension (new block is the immediate child of the old one).
    41  		s.log.Debug("L1 head moved forward", "l1_head", head)
    42  	} else {
    43  		if s.l1Head.Number >= head.Number {
    44  			s.metrics.RecordL1ReorgDepth(s.l1Head.Number - head.Number)
    45  		}
    46  		// New L1 block is not the same as the current head or a single step linear extension.
    47  		// This could either be a long L1 extension, or a reorg, or we simply missed a head update.
    48  		s.log.Warn("L1 head signal indicates a possible L1 re-org", "old_l1_head", s.l1Head, "new_l1_head_parent", head.ParentHash, "new_l1_head", head)
    49  	}
    50  	s.metrics.RecordL1Ref("l1_head", head)
    51  	s.l1Head = head
    52  }
    53  
    54  func (s *L1State) HandleNewL1SafeBlock(safe eth.L1BlockRef) {
    55  	s.log.Info("New L1 safe block", "l1_safe", safe)
    56  	s.metrics.RecordL1Ref("l1_safe", safe)
    57  	s.l1Safe = safe
    58  }
    59  
    60  func (s *L1State) HandleNewL1FinalizedBlock(finalized eth.L1BlockRef) {
    61  	s.log.Info("New L1 finalized block", "l1_finalized", finalized)
    62  	s.metrics.RecordL1Ref("l1_finalized", finalized)
    63  	s.l1Finalized = finalized
    64  }
    65  
    66  // L1Head returns either the stored L1 head or an empty block reference
    67  // if the L1 Head has not been initialized yet.
    68  func (s *L1State) L1Head() eth.L1BlockRef {
    69  	return s.l1Head
    70  }
    71  
    72  // L1Safe returns either the stored L1 safe block or an empty block reference
    73  // if the L1 safe block has not been initialized yet.
    74  func (s *L1State) L1Safe() eth.L1BlockRef {
    75  	return s.l1Safe
    76  }
    77  
    78  // L1Finalized returns either the stored L1 finalized block or an empty block reference
    79  // if the L1 finalized block has not been initialized yet.
    80  func (s *L1State) L1Finalized() eth.L1BlockRef {
    81  	return s.l1Finalized
    82  }