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 }