From 128bb7ca570a0afa5fbb7ef1e156b4815260ec8f Mon Sep 17 00:00:00 2001 From: Jordan Schalm Date: Fri, 14 Jun 2024 09:22:30 -0700 Subject: [PATCH] avoid reading the sealing segment in the scaffold This change is to support nodes which bootstrapped with an invalid root snapshot (too-short sealing segment) during the course of a v0.33 network. The software has been updated to again reject these invalid snapshots for new nodes, but we need a temporary measure for nodes which: - bootstrapped using an invalid snapshot - are unable or unwilling to re-bootstrap In other words, we want a software version which will accomodate a database that has been bootstrapped with an invalid snapshot (only for the duration of v0.33 networks, this should not be ported to subsequent major version!) This PR: - moves the setRootSnapshot call to after the database setup in both initial and subsequent startup cases - changes the caching of root snapshot values to avoid reading the problematic root sealing segment This should allow nodes with a bad root snapshot to boot, be a no-op for nodes with a correct root snapshot, and also prevent nodes with a bad root snapshot from producing further invalid snapshots, which would propagate the underlying problem. --- cmd/scaffold.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/cmd/scaffold.go b/cmd/scaffold.go index 26795ba5e98..39d206bbf09 100644 --- a/cmd/scaffold.go +++ b/cmd/scaffold.go @@ -1337,10 +1337,6 @@ func (fnb *FlowNodeBuilder) initState() error { return fmt.Errorf("failed validate root snapshot from disk: %w", err) } } - // set root snapshot fields - if err := fnb.setRootSnapshot(rootSnapshot); err != nil { - return err - } // generate bootstrap config options as per NodeConfig var options []badgerState.BootstrapConfigOptions @@ -1360,13 +1356,18 @@ func (fnb *FlowNodeBuilder) initState() error { fnb.Storage.EpochCommits, fnb.Storage.Statuses, fnb.Storage.VersionBeacons, - fnb.RootSnapshot, + rootSnapshot, options..., ) if err != nil { return fmt.Errorf("could not bootstrap protocol state: %w", err) } + // set root snapshot fields + if err := fnb.setRootSnapshot(rootSnapshot); err != nil { + return err + } + fnb.Logger.Info(). Hex("root_result_id", logging.Entity(fnb.RootResult)). Hex("root_state_commitment", fnb.RootSeal.FinalState[:]). @@ -1426,13 +1427,20 @@ func (fnb *FlowNodeBuilder) setRootSnapshot(rootSnapshot protocol.Snapshot) erro return fmt.Errorf("failed to read root sealed result: %w", err) } - sealingSegment, err := fnb.RootSnapshot.SealingSegment() + rootHeader, err := fnb.RootSnapshot.Head() + if err != nil { + return fmt.Errorf("could not read root header: %w", err) + } + rootBlockID := rootHeader.ID() + fnb.FinalizedRootBlock, err = fnb.Storage.Blocks.ByID(rootBlockID) + if err != nil { + return fmt.Errorf("could not read finalized root block (id=%x): %w", rootBlockID, err) + } + fnb.SealedRootBlock, err = fnb.Storage.Blocks.ByID(fnb.RootSeal.BlockID) if err != nil { - return fmt.Errorf("failed to read root sealing segment: %w", err) + return fmt.Errorf("could not read sealed root block (id=%x): %w", fnb.RootSeal.BlockID, err) } - fnb.FinalizedRootBlock = sealingSegment.Highest() - fnb.SealedRootBlock = sealingSegment.Sealed() fnb.RootQC, err = fnb.RootSnapshot.QuorumCertificate() if err != nil { return fmt.Errorf("failed to read root QC: %w", err)