Skip to content

Commit dd37e61

Browse files
authored
op-supervisor: return typed pairs of L1/L2 blocks, and support invalidation of fromda entries (#13840)
* op-supervisor: return typed pairs of L1/L2 blocks, and support invalidation of fromda entries * op-supervisor: support DA db block-invalidation and replacement * op-supervisor: fix and cover edge-case of replacing a block at later L1 scope
1 parent 6db0c9d commit dd37e61

File tree

13 files changed

+578
-265
lines changed

13 files changed

+578
-265
lines changed

op-supervisor/supervisor/backend/db/db.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ type LogStorage interface {
2626

2727
SealBlock(parentHash common.Hash, block eth.BlockID, timestamp uint64) error
2828

29-
Rewind(newHeadBlockNum uint64) error
29+
Rewind(newHead eth.BlockID) error
3030

31-
LatestSealedBlockNum() (n uint64, ok bool)
31+
LatestSealedBlock() (id eth.BlockID, ok bool)
3232

3333
// FindSealedBlock finds the requested block by number, to check if it exists,
3434
// returning the block seal if it was found.
@@ -51,14 +51,14 @@ type LogStorage interface {
5151
}
5252

5353
type LocalDerivedFromStorage interface {
54-
First() (derivedFrom types.BlockSeal, derived types.BlockSeal, err error)
55-
Latest() (derivedFrom types.BlockSeal, derived types.BlockSeal, err error)
54+
First() (pair types.DerivedBlockSealPair, err error)
55+
Latest() (pair types.DerivedBlockSealPair, err error)
5656
AddDerived(derivedFrom eth.BlockRef, derived eth.BlockRef) error
5757
LastDerivedAt(derivedFrom eth.BlockID) (derived types.BlockSeal, err error)
5858
DerivedFrom(derived eth.BlockID) (derivedFrom types.BlockSeal, err error)
59-
FirstAfter(derivedFrom, derived eth.BlockID) (nextDerivedFrom, nextDerived types.BlockSeal, err error)
59+
FirstAfter(derivedFrom, derived eth.BlockID) (next types.DerivedBlockSealPair, err error)
6060
NextDerivedFrom(derivedFrom eth.BlockID) (nextDerivedFrom types.BlockSeal, err error)
61-
NextDerived(derived eth.BlockID) (derivedFrom types.BlockSeal, nextDerived types.BlockSeal, err error)
61+
NextDerived(derived eth.BlockID) (next types.DerivedBlockSealPair, err error)
6262
PreviousDerivedFrom(derivedFrom eth.BlockID) (prevDerivedFrom types.BlockSeal, err error)
6363
PreviousDerived(derived eth.BlockID) (prevDerived types.BlockSeal, err error)
6464
}
@@ -168,15 +168,15 @@ func (db *ChainsDB) AddCrossUnsafeTracker(chainID eth.ChainID) {
168168
func (db *ChainsDB) ResumeFromLastSealedBlock() error {
169169
var result error
170170
db.logDBs.Range(func(chain eth.ChainID, logStore LogStorage) bool {
171-
headNum, ok := logStore.LatestSealedBlockNum()
171+
head, ok := logStore.LatestSealedBlock()
172172
if !ok {
173173
// db must be empty, nothing to rewind to
174174
db.logger.Info("Resuming, but found no DB contents", "chain", chain)
175175
return true
176176
}
177-
db.logger.Info("Resuming, starting from last sealed block", "head", headNum)
178-
if err := logStore.Rewind(headNum); err != nil {
179-
result = fmt.Errorf("failed to rewind chain %s to sealed block %d", chain, headNum)
177+
db.logger.Info("Resuming, starting from last sealed block", "head", head)
178+
if err := logStore.Rewind(head); err != nil {
179+
result = fmt.Errorf("failed to rewind chain %s to sealed block %d", chain, head)
180180
return false
181181
}
182182
return true

op-supervisor/supervisor/backend/db/fromda/db.go

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ func NewFromEntryStore(logger log.Logger, m Metrics, store EntryStore) (*DB, err
5353

5454
// Rewind to the last entry that was derived from a L1 block with the given block number.
5555
func (db *DB) Rewind(derivedFrom uint64) error {
56+
db.rwLock.Lock()
57+
defer db.rwLock.Unlock()
5658
index, _, err := db.lastDerivedAt(derivedFrom)
5759
if err != nil {
5860
return fmt.Errorf("failed to find point to rewind to: %w", err)
@@ -66,29 +68,36 @@ func (db *DB) Rewind(derivedFrom uint64) error {
6668
}
6769

6870
// First returns the first known values, alike to Latest.
69-
func (db *DB) First() (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) {
71+
func (db *DB) First() (pair types.DerivedBlockSealPair, err error) {
7072
db.rwLock.RLock()
7173
defer db.rwLock.RUnlock()
7274
lastIndex := db.store.LastEntryIdx()
7375
if lastIndex < 0 {
74-
return types.BlockSeal{}, types.BlockSeal{}, types.ErrFuture
76+
return types.DerivedBlockSealPair{}, types.ErrFuture
7577
}
7678
last, err := db.readAt(0)
7779
if err != nil {
78-
return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("failed to read first derivation data: %w", err)
80+
return types.DerivedBlockSealPair{}, fmt.Errorf("failed to read first derivation data: %w", err)
7981
}
80-
return last.derivedFrom, last.derived, nil
82+
return last.sealOrErr()
8183
}
8284

8385
func (db *DB) PreviousDerived(derived eth.BlockID) (prevDerived types.BlockSeal, err error) {
8486
db.rwLock.RLock()
8587
defer db.rwLock.RUnlock()
86-
// get the last time this L2 block was seen.
88+
// last
89+
_, lastCanonical, err := db.lastDerivedFrom(derived.Number)
90+
if err != nil {
91+
return types.BlockSeal{}, fmt.Errorf("failed to find last derived %d: %w", derived.Number, err)
92+
}
93+
// get the first time this L2 block was seen.
8794
selfIndex, self, err := db.firstDerivedFrom(derived.Number)
8895
if err != nil {
89-
return types.BlockSeal{}, fmt.Errorf("failed to find derived %d: %w", derived.Number, err)
96+
return types.BlockSeal{}, fmt.Errorf("failed to find first derived %d: %w", derived.Number, err)
9097
}
91-
if self.derived.ID() != derived {
98+
// The first entry might not match, since it may have been invalidated with a later L1 scope.
99+
// But the last entry should always match.
100+
if lastCanonical.derived.ID() != derived {
92101
return types.BlockSeal{}, fmt.Errorf("found %s, but expected %s: %w", self.derived, derived, types.ErrConflict)
93102
}
94103
if selfIndex == 0 { // genesis block has a zeroed block as parent block
@@ -104,26 +113,48 @@ func (db *DB) PreviousDerived(derived eth.BlockID) (prevDerived types.BlockSeal,
104113
// Latest returns the last known values:
105114
// derivedFrom: the L1 block that the L2 block is safe for (not necessarily the first, multiple L2 blocks may be derived from the same L1 block).
106115
// derived: the L2 block that was derived (not necessarily the first, the L1 block may have been empty and repeated the last safe L2 block).
107-
func (db *DB) Latest() (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) {
116+
// If the last entry is invalidated, this returns a types.ErrAwaitReplacementBlock error.
117+
func (db *DB) Latest() (pair types.DerivedBlockSealPair, err error) {
118+
db.rwLock.RLock()
119+
defer db.rwLock.RUnlock()
120+
link, err := db.latest()
121+
if err != nil {
122+
return types.DerivedBlockSealPair{}, err
123+
}
124+
return link.sealOrErr()
125+
}
126+
127+
func (db *DB) Invalidated() (pair types.DerivedBlockSealPair, err error) {
108128
db.rwLock.RLock()
109129
defer db.rwLock.RUnlock()
110-
return db.latest()
130+
link, err := db.latest()
131+
if err != nil {
132+
return types.DerivedBlockSealPair{}, err
133+
}
134+
if !link.invalidated {
135+
return types.DerivedBlockSealPair{}, fmt.Errorf("last entry %s is not invalidated: %w", link, types.ErrConflict)
136+
}
137+
return types.DerivedBlockSealPair{
138+
DerivedFrom: link.derivedFrom,
139+
Derived: link.derived,
140+
}, nil
111141
}
112142

113143
// latest is like Latest, but without lock, for internal use.
114-
func (db *DB) latest() (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) {
144+
func (db *DB) latest() (link LinkEntry, err error) {
115145
lastIndex := db.store.LastEntryIdx()
116146
if lastIndex < 0 {
117-
return types.BlockSeal{}, types.BlockSeal{}, types.ErrFuture
147+
return LinkEntry{}, types.ErrFuture
118148
}
119149
last, err := db.readAt(lastIndex)
120150
if err != nil {
121-
return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("failed to read last derivation data: %w", err)
151+
return LinkEntry{}, fmt.Errorf("failed to read last derivation data: %w", err)
122152
}
123-
return last.derivedFrom, last.derived, nil
153+
return last, nil
124154
}
125155

126156
// LastDerivedAt returns the last L2 block derived from the given L1 block.
157+
// This may return types.ErrAwaitReplacementBlock if the entry was invalidated and needs replacement.
127158
func (db *DB) LastDerivedAt(derivedFrom eth.BlockID) (derived types.BlockSeal, err error) {
128159
db.rwLock.RLock()
129160
defer db.rwLock.RUnlock()
@@ -135,26 +166,30 @@ func (db *DB) LastDerivedAt(derivedFrom eth.BlockID) (derived types.BlockSeal, e
135166
return types.BlockSeal{}, fmt.Errorf("searched for last derived-from %s but found %s: %w",
136167
derivedFrom, link.derivedFrom, types.ErrConflict)
137168
}
169+
if link.invalidated {
170+
return types.BlockSeal{}, types.ErrAwaitReplacementBlock
171+
}
138172
return link.derived, nil
139173
}
140174

141-
// NextDerived finds the next L2 block after derived, and what it was derived from
142-
func (db *DB) NextDerived(derived eth.BlockID) (derivedFrom types.BlockSeal, nextDerived types.BlockSeal, err error) {
175+
// NextDerived finds the next L2 block after derived, and what it was derived from.
176+
// This may return types.ErrAwaitReplacementBlock if the entry was invalidated and needs replacement.
177+
func (db *DB) NextDerived(derived eth.BlockID) (pair types.DerivedBlockSealPair, err error) {
143178
db.rwLock.RLock()
144179
defer db.rwLock.RUnlock()
145180
// get the last time this L2 block was seen.
146181
selfIndex, self, err := db.lastDerivedFrom(derived.Number)
147182
if err != nil {
148-
return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("failed to find derived %d: %w", derived.Number, err)
183+
return types.DerivedBlockSealPair{}, fmt.Errorf("failed to find derived %d: %w", derived.Number, err)
149184
}
150185
if self.derived.ID() != derived {
151-
return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("found %s, but expected %s: %w", self.derived, derived, types.ErrConflict)
186+
return types.DerivedBlockSealPair{}, fmt.Errorf("found %s, but expected %s: %w", self.derived, derived, types.ErrConflict)
152187
}
153188
next, err := db.readAt(selfIndex + 1)
154189
if err != nil {
155-
return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("cannot find next derived after %s: %w", derived, err)
190+
return types.DerivedBlockSealPair{}, fmt.Errorf("cannot find next derived after %s: %w", derived, err)
156191
}
157-
return next.derivedFrom, next.derived, nil
192+
return next.sealOrErr()
158193
}
159194

160195
// DerivedFrom determines where a L2 block was first derived from.
@@ -176,6 +211,10 @@ func (db *DB) DerivedFrom(derived eth.BlockID) (derivedFrom types.BlockSeal, err
176211
func (db *DB) PreviousDerivedFrom(derivedFrom eth.BlockID) (prevDerivedFrom types.BlockSeal, err error) {
177212
db.rwLock.RLock()
178213
defer db.rwLock.RUnlock()
214+
return db.previousDerivedFrom(derivedFrom)
215+
}
216+
217+
func (db *DB) previousDerivedFrom(derivedFrom eth.BlockID) (prevDerivedFrom types.BlockSeal, err error) {
179218
// get the last time this L1 block was seen.
180219
selfIndex, self, err := db.firstDerivedAt(derivedFrom.Number)
181220
if err != nil {
@@ -219,25 +258,26 @@ func (db *DB) NextDerivedFrom(derivedFrom eth.BlockID) (nextDerivedFrom types.Bl
219258
}
220259

221260
// FirstAfter determines the next entry after the given pair of derivedFrom, derived.
222-
// Either one or both of the two entries will be an increment by 1
223-
func (db *DB) FirstAfter(derivedFrom, derived eth.BlockID) (nextDerivedFrom, nextDerived types.BlockSeal, err error) {
261+
// Either one or both of the two entries will be an increment by 1.
262+
// This may return types.ErrAwaitReplacementBlock if the entry was invalidated and needs replacement.
263+
func (db *DB) FirstAfter(derivedFrom, derived eth.BlockID) (pair types.DerivedBlockSealPair, err error) {
224264
db.rwLock.RLock()
225265
defer db.rwLock.RUnlock()
226266
selfIndex, selfLink, err := db.lookup(derivedFrom.Number, derived.Number)
227267
if err != nil {
228-
return types.BlockSeal{}, types.BlockSeal{}, err
268+
return types.DerivedBlockSealPair{}, err
229269
}
230270
if selfLink.derivedFrom.ID() != derivedFrom {
231-
return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("DB has derived-from %s but expected %s: %w", selfLink.derivedFrom, derivedFrom, types.ErrConflict)
271+
return types.DerivedBlockSealPair{}, fmt.Errorf("DB has derived-from %s but expected %s: %w", selfLink.derivedFrom, derivedFrom, types.ErrConflict)
232272
}
233273
if selfLink.derived.ID() != derived {
234-
return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("DB has derived %s but expected %s: %w", selfLink.derived, derived, types.ErrConflict)
274+
return types.DerivedBlockSealPair{}, fmt.Errorf("DB has derived %s but expected %s: %w", selfLink.derived, derived, types.ErrConflict)
235275
}
236276
next, err := db.readAt(selfIndex + 1)
237277
if err != nil {
238-
return types.BlockSeal{}, types.BlockSeal{}, err
278+
return types.DerivedBlockSealPair{}, err
239279
}
240-
return next.derivedFrom, next.derived, nil
280+
return next.sealOrErr()
241281
}
242282

243283
func (db *DB) lastDerivedFrom(derived uint64) (entrydb.EntryIdx, LinkEntry, error) {

0 commit comments

Comments
 (0)