From ab200018586150fac1fa38ef4e7b265f7cf0349a Mon Sep 17 00:00:00 2001 From: axelKingsley Date: Wed, 21 Aug 2024 11:24:55 -0500 Subject: [PATCH] Add Routine to run Maintenence --- op-supervisor/supervisor/backend/backend.go | 3 ++ op-supervisor/supervisor/backend/db/db.go | 34 ++++++++++++++++++- .../supervisor/backend/db/db_test.go | 4 +++ .../supervisor/backend/db/safety_checkers.go | 14 ++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/op-supervisor/supervisor/backend/backend.go b/op-supervisor/supervisor/backend/backend.go index 2f01ba8b36a9..6556b5a35c33 100644 --- a/op-supervisor/supervisor/backend/backend.go +++ b/op-supervisor/supervisor/backend/backend.go @@ -101,11 +101,14 @@ func (su *SupervisorBackend) Start(ctx context.Context) error { if !su.started.CompareAndSwap(false, true) { return errors.New("already started") } + // start chain monitors for _, monitor := range su.chainMonitors { if err := monitor.Start(); err != nil { return fmt.Errorf("failed to start chain monitor: %w", err) } } + // start db maintenance loop + su.db.StartCrossHeadMaintenance(ctx) return nil } diff --git a/op-supervisor/supervisor/backend/db/db.go b/op-supervisor/supervisor/backend/db/db.go index 3dfeaab23801..e6cd77ba33e8 100644 --- a/op-supervisor/supervisor/backend/db/db.go +++ b/op-supervisor/supervisor/backend/db/db.go @@ -1,9 +1,11 @@ package db import ( + "context" "errors" "fmt" "io" + "time" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/entrydb" @@ -11,6 +13,7 @@ import ( "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/logs" backendTypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/types" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" + "github.com/ethereum/go-ethereum/log" ) var ( @@ -59,6 +62,35 @@ func (db *ChainsDB) Resume() error { return nil } +// StartCrossHeadMaintenance starts a background process that maintains the cross-heads of the chains +// for now it does not prevent multiple instances of this process from running +func (db *ChainsDB) StartCrossHeadMaintenance(ctx context.Context) { + go func() { + // create three safety checkers, one for each safety level + unsafeChecker := NewSafetyChecker(Unsafe, *db) + safeChecker := NewSafetyChecker(Safe, *db) + finalizedChecker := NewSafetyChecker(Finalized, *db) + // run the maintenance loop every 10 seconds for now + ticker := time.NewTicker(time.Second * 10) + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + for _, checker := range []SafetyChecker{ + unsafeChecker, + safeChecker, + finalizedChecker} { + if err := db.UpdateCrossHeads(checker); err != nil { + log.Error("failed to update cross-heads", "err", err, "safety", checker.Name()) + // we should consider exiting if an error is encountered, as the path forward is unclear + } + } + } + } + }() +} + // UpdateCrossSafeHeads updates the cross-heads of all chains // this is an example of how to use the SafetyChecker to update the cross-heads func (db *ChainsDB) UpdateCrossSafeHeads() error { @@ -117,7 +149,7 @@ func (db *ChainsDB) UpdateCrossHeadsForChain(chainID types.ChainID, checker Safe return nil } -// UpdateCrossSafeHeads updates the cross-heads of all chains +// UpdateCrossHeads updates the cross-heads of all chains // based on the provided SafetyChecker. The SafetyChecker is used to determine // the safety of each log entry in the database, and the cross-head associated with it. func (db *ChainsDB) UpdateCrossHeads(checker SafetyChecker) error { diff --git a/op-supervisor/supervisor/backend/db/db_test.go b/op-supervisor/supervisor/backend/db/db_test.go index b1ff9cf405e5..7481ac954fae 100644 --- a/op-supervisor/supervisor/backend/db/db_test.go +++ b/op-supervisor/supervisor/backend/db/db_test.go @@ -213,6 +213,10 @@ func (s *stubChecker) LocalHeadForChain(chainID types.ChainID) entrydb.EntryIdx return s.localHeadForChain } +func (s *stubChecker) Name() string { + return "stubChecker" +} + func (s *stubChecker) CrossHeadForChain(chainID types.ChainID) entrydb.EntryIdx { return s.crossHeadForChain } diff --git a/op-supervisor/supervisor/backend/db/safety_checkers.go b/op-supervisor/supervisor/backend/db/safety_checkers.go index a28aa6797f1f..e9c664d9c192 100644 --- a/op-supervisor/supervisor/backend/db/safety_checkers.go +++ b/op-supervisor/supervisor/backend/db/safety_checkers.go @@ -20,6 +20,7 @@ type SafetyChecker interface { CrossHeadForChain(chainID types.ChainID) entrydb.EntryIdx Check(chain types.ChainID, blockNum uint64, logIdx uint32, logHash backendTypes.TruncatedHash) bool Update(chain types.ChainID, index entrydb.EntryIdx) heads.OperationFn + Name() string } // unsafeChecker is a SafetyChecker that uses the unsafe head as the view into the database @@ -57,6 +58,19 @@ func NewSafetyChecker(t string, chainsDB ChainsDB) SafetyChecker { } } +// Name returns the safety checker type, using the same strings as the constants used in construction +func (c *unsafeChecker) Name() string { + return Unsafe +} + +func (c *safeChecker) Name() string { + return Safe +} + +func (c *finalizedChecker) Name() string { + return Finalized +} + // LocalHeadForChain returns the local head for the given chain // based on the type of SafetyChecker func (c *unsafeChecker) LocalHeadForChain(chainID types.ChainID) entrydb.EntryIdx {