diff --git a/op-supervisor/supervisor/backend/cross/safe_update.go b/op-supervisor/supervisor/backend/cross/safe_update.go index 6d74ca8ad2ba..bcda7c9f782b 100644 --- a/op-supervisor/supervisor/backend/cross/safe_update.go +++ b/op-supervisor/supervisor/backend/cross/safe_update.go @@ -57,7 +57,7 @@ func CrossSafeUpdate(ctx context.Context, logger log.Logger, chainID types.Chain if err != nil { return fmt.Errorf("cannot find parent-block of cross-safe: %w", err) } - crossSafeRef := currentCrossSafe.WithParent(parent.ID()) + crossSafeRef := currentCrossSafe.MustWithParent(parent.ID()) logger.Debug("Bumping cross-safe scope", "scope", newScope, "crossSafe", crossSafeRef) if err := d.UpdateCrossSafe(chainID, newScope, crossSafeRef); err != nil { return fmt.Errorf("failed to update cross-safe head with L1 scope increment to %s and repeat of L2 block %s: %w", candidateScope, crossSafeRef, err) diff --git a/op-supervisor/supervisor/backend/cross/safe_update_test.go b/op-supervisor/supervisor/backend/cross/safe_update_test.go index b3361c711bd0..3fc0ebba1388 100644 --- a/op-supervisor/supervisor/backend/cross/safe_update_test.go +++ b/op-supervisor/supervisor/backend/cross/safe_update_test.go @@ -102,7 +102,7 @@ func TestCrossSafeUpdate(t *testing.T) { require.NoError(t, err) require.Equal(t, chainID, updatingChain) require.Equal(t, newScope, updatingCandidateScope) - crossSafeRef := currentCrossSafe.WithParent(parent.ID()) + crossSafeRef := currentCrossSafe.MustWithParent(parent.ID()) require.Equal(t, crossSafeRef, updatingCandidate) }) t.Run("NextDerivedFrom returns error", func(t *testing.T) { diff --git a/op-supervisor/supervisor/backend/db/query.go b/op-supervisor/supervisor/backend/db/query.go index 867e4e71955b..bc3547cd023e 100644 --- a/op-supervisor/supervisor/backend/db/query.go +++ b/op-supervisor/supervisor/backend/db/query.go @@ -157,7 +157,7 @@ func (db *ChainsDB) CrossDerivedFromBlockRef(chainID types.ChainID, derived eth. if err != nil { return eth.BlockRef{}, err } - return res.WithParent(parent.ID()), nil + return res.MustWithParent(parent.ID()), nil } // Check calls the underlying logDB to determine if the given log entry exists at the given location. @@ -238,9 +238,16 @@ func (db *ChainsDB) CandidateCrossSafe(chain types.ChainID) (derivedFromScope, c if err != nil { return eth.BlockRef{}, eth.BlockRef{}, fmt.Errorf("failed to find first local-safe block: %w", err) } - // First block has no parent - return derivedFrom.WithParent(eth.BlockID{}), - derived.WithParent(eth.BlockID{}), nil + // the first derivedFrom (L1 block) is unlikely to be the genesis block, + derivedFromRef, err := derivedFrom.WithParent(eth.BlockID{}) + if err != nil { + // if the first derivedFrom isn't the genesis block, just warn and continue anyway + db.logger.Warn("First DerivedFrom is not genesis block") + derivedFromRef = derivedFrom.ForceWithParent(eth.BlockID{}) + } + // the first derived must be the genesis block, panic otherwise + derivedRef := derived.MustWithParent(derivedFrom.ID()) + return derivedFromRef, derivedRef, nil } return eth.BlockRef{}, eth.BlockRef{}, err } @@ -256,13 +263,13 @@ func (db *ChainsDB) CandidateCrossSafe(chain types.ChainID) (derivedFromScope, c return eth.BlockRef{}, eth.BlockRef{}, err } - candidateRef := candidate.WithParent(crossDerived.ID()) + candidateRef := candidate.MustWithParent(crossDerived.ID()) parentDerivedFrom, err := lDB.PreviousDerivedFrom(candidateFrom.ID()) if err != nil { return eth.BlockRef{}, eth.BlockRef{}, fmt.Errorf("failed to find parent-block of derived-from %s: %w", candidateFrom, err) } - candidateFromRef := candidateFrom.WithParent(parentDerivedFrom.ID()) + candidateFromRef := candidateFrom.MustWithParent(parentDerivedFrom.ID()) // Allow increment of DA by 1, if we know the floor (due to local safety) is 1 ahead of the current cross-safe L1 scope. if candidateFrom.Number > crossDerivedFrom.Number+1 { @@ -273,7 +280,7 @@ func (db *ChainsDB) CandidateCrossSafe(chain types.ChainID) (derivedFromScope, c return eth.BlockRef{}, eth.BlockRef{}, fmt.Errorf("failed to find parent-block of cross-derived-from %s: %w", crossDerivedFrom, err) } - crossDerivedFromRef := crossDerivedFrom.WithParent(parent.ID()) + crossDerivedFromRef := crossDerivedFrom.MustWithParent(parent.ID()) return crossDerivedFromRef, eth.BlockRef{}, fmt.Errorf("candidate is from %s, while current scope is %s: %w", candidateFrom, crossDerivedFrom, types.ErrOutOfScope) @@ -306,7 +313,7 @@ func (db *ChainsDB) NextDerivedFrom(chain types.ChainID, derivedFrom eth.BlockID if err != nil { return eth.BlockRef{}, err } - return v.WithParent(derivedFrom), nil + return v.MustWithParent(derivedFrom), nil } // Safest returns the strongest safety level that can be guaranteed for the given log entry. diff --git a/op-supervisor/supervisor/types/types.go b/op-supervisor/supervisor/types/types.go index bac2c377bfd7..381d1fc3cbda 100644 --- a/op-supervisor/supervisor/types/types.go +++ b/op-supervisor/supervisor/types/types.go @@ -240,12 +240,29 @@ func (s BlockSeal) ID() eth.BlockID { return eth.BlockID{Hash: s.Hash, Number: s.Number} } -func (s BlockSeal) WithParent(parent eth.BlockID) eth.BlockRef { +func (s BlockSeal) MustWithParent(parent eth.BlockID) eth.BlockRef { + ref, err := s.WithParent(parent) + if err != nil { + panic(err) + } + return ref +} + +func (s BlockSeal) WithParent(parent eth.BlockID) (eth.BlockRef, error) { // prevent parent attachment if the parent is not the previous block, // and the block is not the genesis block if s.Number != parent.Number+1 && s.Number != 0 { - panic(fmt.Errorf("invalid parent block %s to combine with %s", parent, s)) + return eth.BlockRef{}, fmt.Errorf("invalid parent block %s to combine with %s", parent, s) } + return eth.BlockRef{ + Hash: s.Hash, + Number: s.Number, + ParentHash: parent.Hash, + Time: s.Timestamp, + }, nil +} + +func (s BlockSeal) ForceWithParent(parent eth.BlockID) eth.BlockRef { return eth.BlockRef{ Hash: s.Hash, Number: s.Number,