github.com/koko1123/flow-go-1@v0.29.6/consensus/hotstuff/follower/follower.go (about) 1 package follower 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/forks" 11 "github.com/koko1123/flow-go-1/consensus/hotstuff/model" 12 "github.com/koko1123/flow-go-1/utils/logging" 13 ) 14 15 // FollowerLogic runs in non-consensus nodes. It informs other components within the node 16 // about finalization of blocks. The consensus Follower consumes all block proposals 17 // broadcasts by the consensus node, verifies the block header and locally evaluates 18 // the finalization rules. 19 // 20 // CAUTION: Follower is NOT CONCURRENCY safe 21 type FollowerLogic struct { 22 log zerolog.Logger 23 validator hotstuff.Validator 24 finalizationLogic forks.Finalizer 25 } 26 27 // New creates a new FollowerLogic instance 28 func New( 29 log zerolog.Logger, 30 validator hotstuff.Validator, 31 finalizationLogic forks.Finalizer, 32 ) (*FollowerLogic, error) { 33 return &FollowerLogic{ 34 log: log.With().Str("hotstuff", "follower").Logger(), 35 validator: validator, 36 finalizationLogic: finalizationLogic, 37 }, nil 38 } 39 40 // FinalizedBlock returns the latest finalized block 41 func (f *FollowerLogic) FinalizedBlock() *model.Block { 42 return f.finalizationLogic.FinalizedBlock() 43 } 44 45 // AddBlock processes the given block proposal 46 func (f *FollowerLogic) AddBlock(blockProposal *model.Proposal) error { 47 // validate the block. skip if the proposal is invalid 48 err := f.validator.ValidateProposal(blockProposal) 49 if model.IsInvalidBlockError(err) { 50 f.log.Warn().Err(err).Hex("block_id", logging.ID(blockProposal.Block.BlockID)). 51 Msg("invalid proposal") 52 return nil 53 } 54 if errors.Is(err, model.ErrUnverifiableBlock) { 55 f.log.Warn(). 56 Hex("block_id", logging.ID(blockProposal.Block.BlockID)). 57 Hex("qc_block_id", logging.ID(blockProposal.Block.QC.BlockID)). 58 Msg("unverifiable proposal") 59 60 // even if the block is unverifiable because the QC has been 61 // pruned, it still needs to be added to the forks, otherwise, 62 // a new block with a QC to this block will fail to be added 63 // to forks and crash the event loop. 64 } else if err != nil { 65 return fmt.Errorf("cannot validate block proposal %x: %w", blockProposal.Block.BlockID, err) 66 } 67 68 // as a sanity check, we run the finalization logic's internal validation on the block 69 if err := f.finalizationLogic.VerifyBlock(blockProposal.Block); err != nil { 70 // this should never happen: the block was found to be valid by the validator 71 // if the finalization logic's internal validation errors, we have a bug 72 return fmt.Errorf("invaid block passed validation: %w", err) 73 } 74 err = f.finalizationLogic.AddBlock(blockProposal.Block) 75 if err != nil { 76 return fmt.Errorf("finalization logic cannot process block proposal %x: %w", blockProposal.Block.BlockID, err) 77 } 78 79 return nil 80 }