github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/consensus/participant.go (about)

     1  package consensus
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/rs/zerolog"
     7  
     8  	"github.com/onflow/flow-go/consensus/hotstuff"
     9  	"github.com/onflow/flow-go/consensus/hotstuff/blockproducer"
    10  	"github.com/onflow/flow-go/consensus/hotstuff/eventhandler"
    11  	"github.com/onflow/flow-go/consensus/hotstuff/eventloop"
    12  	"github.com/onflow/flow-go/consensus/hotstuff/forks"
    13  	"github.com/onflow/flow-go/consensus/hotstuff/model"
    14  	"github.com/onflow/flow-go/consensus/hotstuff/pacemaker"
    15  	"github.com/onflow/flow-go/consensus/hotstuff/pacemaker/timeout"
    16  	"github.com/onflow/flow-go/consensus/hotstuff/safetyrules"
    17  	"github.com/onflow/flow-go/consensus/hotstuff/signature"
    18  	validatorImpl "github.com/onflow/flow-go/consensus/hotstuff/validator"
    19  	"github.com/onflow/flow-go/consensus/hotstuff/verification"
    20  	"github.com/onflow/flow-go/consensus/recovery"
    21  	"github.com/onflow/flow-go/model/flow"
    22  	"github.com/onflow/flow-go/module"
    23  	"github.com/onflow/flow-go/storage"
    24  )
    25  
    26  // NewParticipant initialize the EventLoop instance with needed dependencies
    27  func NewParticipant(
    28  	log zerolog.Logger,
    29  	metrics module.HotstuffMetrics,
    30  	mempoolMetrics module.MempoolMetrics,
    31  	builder module.Builder,
    32  	finalized *flow.Header,
    33  	pending []*flow.Header,
    34  	modules *HotstuffModules,
    35  	options ...Option,
    36  ) (*eventloop.EventLoop, error) {
    37  
    38  	// initialize the default configuration and apply the configuration options
    39  	cfg := DefaultParticipantConfig()
    40  	for _, option := range options {
    41  		option(&cfg)
    42  	}
    43  
    44  	// prune vote aggregator to initial view
    45  	modules.VoteAggregator.PruneUpToView(finalized.View)
    46  	modules.TimeoutAggregator.PruneUpToView(finalized.View)
    47  
    48  	// recover HotStuff state from all pending blocks
    49  	qcCollector := recovery.NewCollector[*flow.QuorumCertificate]()
    50  	tcCollector := recovery.NewCollector[*flow.TimeoutCertificate]()
    51  	err := recovery.Recover(log, pending,
    52  		recovery.ForksState(modules.Forks),                   // add pending blocks to Forks
    53  		recovery.VoteAggregatorState(modules.VoteAggregator), // accept votes for all pending blocks
    54  		recovery.CollectParentQCs(qcCollector),               // collect QCs from all pending block to initialize PaceMaker (below)
    55  		recovery.CollectTCs(tcCollector),                     // collect TCs from all pending block to initialize PaceMaker (below)
    56  	)
    57  	if err != nil {
    58  		return nil, fmt.Errorf("failed to scan tree of pending blocks: %w", err)
    59  	}
    60  
    61  	// initialize dynamically updatable timeout config
    62  	timeoutConfig, err := timeout.NewConfig(cfg.TimeoutMinimum, cfg.TimeoutMaximum, cfg.TimeoutAdjustmentFactor, cfg.HappyPathMaxRoundFailures, cfg.MaxTimeoutObjectRebroadcastInterval)
    63  	if err != nil {
    64  		return nil, fmt.Errorf("could not initialize timeout config: %w", err)
    65  	}
    66  
    67  	// initialize the pacemaker
    68  	controller := timeout.NewController(timeoutConfig)
    69  	pacemaker, err := pacemaker.New(controller, cfg.ProposalDurationProvider, modules.Notifier, modules.Persist,
    70  		pacemaker.WithQCs(qcCollector.Retrieve()...),
    71  		pacemaker.WithTCs(tcCollector.Retrieve()...),
    72  	)
    73  	if err != nil {
    74  		return nil, fmt.Errorf("could not initialize flow pacemaker: %w", err)
    75  	}
    76  
    77  	// initialize block producer
    78  	producer, err := blockproducer.New(modules.Signer, modules.Committee, builder)
    79  	if err != nil {
    80  		return nil, fmt.Errorf("could not initialize block producer: %w", err)
    81  	}
    82  
    83  	// initialize the safetyRules
    84  	safetyRules, err := safetyrules.New(modules.Signer, modules.Persist, modules.Committee)
    85  	if err != nil {
    86  		return nil, fmt.Errorf("could not initialize safety rules: %w", err)
    87  	}
    88  
    89  	// initialize the event handler
    90  	eventHandler, err := eventhandler.NewEventHandler(
    91  		log,
    92  		pacemaker,
    93  		producer,
    94  		modules.Forks,
    95  		modules.Persist,
    96  		modules.Committee,
    97  		safetyRules,
    98  		modules.Notifier,
    99  	)
   100  	if err != nil {
   101  		return nil, fmt.Errorf("could not initialize event handler: %w", err)
   102  	}
   103  
   104  	// initialize and return the event loop
   105  	loop, err := eventloop.NewEventLoop(log, metrics, mempoolMetrics, eventHandler, cfg.StartupTime)
   106  	if err != nil {
   107  		return nil, fmt.Errorf("could not initialize event loop: %w", err)
   108  	}
   109  
   110  	// add observer, event loop needs to receive events from distributor
   111  	modules.VoteCollectorDistributor.AddVoteCollectorConsumer(loop)
   112  	modules.TimeoutCollectorDistributor.AddTimeoutCollectorConsumer(loop)
   113  
   114  	return loop, nil
   115  }
   116  
   117  // NewValidator creates new instance of hotstuff validator needed for votes & proposal validation
   118  func NewValidator(metrics module.HotstuffMetrics, committee hotstuff.DynamicCommittee) hotstuff.Validator {
   119  	packer := signature.NewConsensusSigDataPacker(committee)
   120  	verifier := verification.NewCombinedVerifier(committee, packer)
   121  
   122  	// initialize the Validator
   123  	validator := validatorImpl.New(committee, verifier)
   124  	return validatorImpl.NewMetricsWrapper(validator, metrics) // wrapper for measuring time spent in Validator component
   125  }
   126  
   127  // NewForks recovers trusted root and creates new forks manager
   128  func NewForks(final *flow.Header, headers storage.Headers, updater module.Finalizer, notifier hotstuff.FollowerConsumer, rootHeader *flow.Header, rootQC *flow.QuorumCertificate) (*forks.Forks, error) {
   129  	// recover the trusted root
   130  	trustedRoot, err := recoverTrustedRoot(final, headers, rootHeader, rootQC)
   131  	if err != nil {
   132  		return nil, fmt.Errorf("could not recover trusted root: %w", err)
   133  	}
   134  
   135  	// initialize the forks
   136  	forks, err := forks.New(trustedRoot, updater, notifier)
   137  	if err != nil {
   138  		return nil, fmt.Errorf("could not initialize forks: %w", err)
   139  	}
   140  
   141  	return forks, nil
   142  }
   143  
   144  // recoverTrustedRoot based on our local state returns root block and QC that can be used to initialize base state
   145  func recoverTrustedRoot(final *flow.Header, headers storage.Headers, rootHeader *flow.Header, rootQC *flow.QuorumCertificate) (*model.CertifiedBlock, error) {
   146  	if final.View < rootHeader.View {
   147  		return nil, fmt.Errorf("finalized Block has older view than trusted root")
   148  	}
   149  
   150  	// if finalized view is genesis block, then use genesis block as the trustedRoot
   151  	if final.View == rootHeader.View {
   152  		if final.ID() != rootHeader.ID() {
   153  			return nil, fmt.Errorf("finalized Block conflicts with trusted root")
   154  		}
   155  		certifiedRoot, err := makeCertifiedRootBlock(rootHeader, rootQC)
   156  		if err != nil {
   157  			return nil, fmt.Errorf("constructing certified root block failed: %w", err)
   158  		}
   159  		return &certifiedRoot, nil
   160  	}
   161  
   162  	// find a valid child of the finalized block in order to get its QC
   163  	children, err := headers.ByParentID(final.ID())
   164  	if err != nil {
   165  		// a finalized block must have a valid child, if err happens, we exit
   166  		return nil, fmt.Errorf("could not get children for finalized block (ID: %v, view: %v): %w", final.ID(), final.View, err)
   167  	}
   168  	if len(children) == 0 {
   169  		return nil, fmt.Errorf("finalized block has no children")
   170  	}
   171  
   172  	child := model.BlockFromFlow(children[0])
   173  
   174  	// create the root block to use
   175  	trustedRoot, err := model.NewCertifiedBlock(model.BlockFromFlow(final), child.QC)
   176  	if err != nil {
   177  		return nil, fmt.Errorf("constructing certified root block failed: %w", err)
   178  	}
   179  	return &trustedRoot, nil
   180  }
   181  
   182  func makeCertifiedRootBlock(header *flow.Header, qc *flow.QuorumCertificate) (model.CertifiedBlock, error) {
   183  	// By convention of Forks, the trusted root block does not need to have a qc
   184  	// (as is the case for the genesis block). For simplify of the implementation, we always omit
   185  	// the QC of the root block. Thereby, we have one algorithm which handles all cases,
   186  	// instead of having to distinguish between a genesis block without a qc
   187  	// and a later-finalized root block where we can retrieve the qc.
   188  	rootBlock := &model.Block{
   189  		View:        header.View,
   190  		BlockID:     header.ID(),
   191  		ProposerID:  header.ProposerID,
   192  		QC:          nil, // QC is omitted
   193  		PayloadHash: header.PayloadHash,
   194  		Timestamp:   header.Timestamp,
   195  	}
   196  	return model.NewCertifiedBlock(rootBlock, qc)
   197  }