github.com/koko1123/flow-go-1@v0.29.6/consensus/recovery/recover.go (about) 1 package recovery 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/rs/zerolog" 8 9 "github.com/koko1123/flow-go-1/consensus/hotstuff" 10 "github.com/koko1123/flow-go-1/consensus/hotstuff/model" 11 "github.com/koko1123/flow-go-1/model/flow" 12 "github.com/koko1123/flow-go-1/utils/logging" 13 ) 14 15 // Recover implements the core logic for recovering HotStuff state after a restart. 16 // It accepts the finalized block and a list of pending blocks that have been 17 // received but not finalized, and that share the latest finalized block as a common 18 // ancestor. 19 func Recover(log zerolog.Logger, finalized *flow.Header, pending []*flow.Header, validator hotstuff.Validator, onProposal func(*model.Proposal) error) error { 20 blocks := make(map[flow.Identifier]*flow.Header, len(pending)+1) 21 22 // finalized is the root 23 blocks[finalized.ID()] = finalized 24 25 log.Info().Int("total", len(pending)).Msgf("recovery started") 26 27 // add all pending blocks to forks 28 for _, header := range pending { 29 blocks[header.ID()] = header 30 31 // parent must exist in storage, because the index has the parent ID 32 parent, ok := blocks[header.ParentID] 33 if !ok { 34 return fmt.Errorf("could not find the parent block %x for header %x", header.ParentID, header.ID()) 35 } 36 37 // convert the header into a proposal 38 proposal := model.ProposalFromFlow(header, parent.View) 39 40 // verify the proposal 41 err := validator.ValidateProposal(proposal) 42 if model.IsInvalidBlockError(err) { 43 log.Warn(). 44 Hex("block_id", logging.ID(proposal.Block.BlockID)). 45 Err(err). 46 Msg("invalid proposal") 47 continue 48 } 49 if errors.Is(err, model.ErrUnverifiableBlock) { 50 log.Warn(). 51 Hex("block_id", logging.ID(proposal.Block.BlockID)). 52 Hex("qc_block_id", logging.ID(proposal.Block.QC.BlockID)). 53 Msg("unverifiable proposal") 54 55 // even if the block is unverifiable because the QC has been 56 // pruned, it still needs to be added to the forks, otherwise, 57 // a new block with a QC to this block will fail to be added 58 // to forks and crash the event loop. 59 } else if err != nil { 60 return fmt.Errorf("cannot validate proposal (%x): %w", proposal.Block.BlockID, err) 61 } 62 63 err = onProposal(proposal) 64 if err != nil { 65 return fmt.Errorf("cannot recover proposal: %w", err) 66 } 67 } 68 69 log.Info().Msgf("recovery completed") 70 71 return nil 72 }