github.com/koko1123/flow-go-1@v0.29.6/consensus/participant.go (about)

     1  package consensus
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/rs/zerolog"
     7  
     8  	"github.com/koko1123/flow-go-1/consensus/hotstuff"
     9  	"github.com/koko1123/flow-go-1/consensus/hotstuff/blockproducer"
    10  	"github.com/koko1123/flow-go-1/consensus/hotstuff/eventhandler"
    11  	"github.com/koko1123/flow-go-1/consensus/hotstuff/eventloop"
    12  	"github.com/koko1123/flow-go-1/consensus/hotstuff/forks"
    13  	"github.com/koko1123/flow-go-1/consensus/hotstuff/forks/finalizer"
    14  	"github.com/koko1123/flow-go-1/consensus/hotstuff/forks/forkchoice"
    15  	"github.com/koko1123/flow-go-1/consensus/hotstuff/model"
    16  	"github.com/koko1123/flow-go-1/consensus/hotstuff/pacemaker"
    17  	"github.com/koko1123/flow-go-1/consensus/hotstuff/pacemaker/timeout"
    18  	"github.com/koko1123/flow-go-1/consensus/hotstuff/signature"
    19  	validatorImpl "github.com/koko1123/flow-go-1/consensus/hotstuff/validator"
    20  	"github.com/koko1123/flow-go-1/consensus/hotstuff/verification"
    21  	"github.com/koko1123/flow-go-1/consensus/hotstuff/voter"
    22  	"github.com/koko1123/flow-go-1/consensus/recovery"
    23  	"github.com/koko1123/flow-go-1/model/flow"
    24  	"github.com/koko1123/flow-go-1/module"
    25  	"github.com/koko1123/flow-go-1/storage"
    26  )
    27  
    28  // NewParticipant initialize the EventLoop instance with needed dependencies
    29  func NewParticipant(
    30  	log zerolog.Logger,
    31  	metrics module.HotstuffMetrics,
    32  	builder module.Builder,
    33  	communicator hotstuff.Communicator,
    34  	finalized *flow.Header,
    35  	pending []*flow.Header,
    36  	modules *HotstuffModules,
    37  	options ...Option,
    38  ) (*eventloop.EventLoop, error) {
    39  
    40  	// initialize the default configuration
    41  	cfg := DefaultParticipantConfig()
    42  
    43  	// apply the configuration options
    44  	for _, option := range options {
    45  		option(&cfg)
    46  	}
    47  
    48  	// get the last view we started
    49  	started, err := modules.Persist.GetStarted()
    50  	if err != nil {
    51  		return nil, fmt.Errorf("could not recover last started: %w", err)
    52  	}
    53  
    54  	// get the last view we voted
    55  	voted, err := modules.Persist.GetVoted()
    56  	if err != nil {
    57  		return nil, fmt.Errorf("could not recover last voted: %w", err)
    58  	}
    59  
    60  	// prune vote aggregator to initial view
    61  	modules.Aggregator.PruneUpToView(finalized.View)
    62  
    63  	// recover the hotstuff state, mainly to recover all pending blocks in Forks
    64  	err = recovery.Participant(log, modules.Forks, modules.Aggregator, modules.Validator, finalized, pending)
    65  	if err != nil {
    66  		return nil, fmt.Errorf("could not recover hotstuff state: %w", err)
    67  	}
    68  
    69  	// initialize the timeout config
    70  	timeoutConfig, err := timeout.NewConfig(
    71  		cfg.TimeoutInitial,
    72  		cfg.TimeoutMinimum,
    73  		cfg.TimeoutAggregationFraction,
    74  		cfg.TimeoutIncreaseFactor,
    75  		cfg.TimeoutDecreaseFactor,
    76  		cfg.BlockRateDelay,
    77  	)
    78  	if err != nil {
    79  		return nil, fmt.Errorf("could not initialize timeout config: %w", err)
    80  	}
    81  
    82  	// initialize the pacemaker
    83  	controller := timeout.NewController(timeoutConfig)
    84  	pacemaker, err := pacemaker.New(started+1, controller, modules.Notifier)
    85  	if err != nil {
    86  		return nil, fmt.Errorf("could not initialize flow pacemaker: %w", err)
    87  	}
    88  
    89  	// initialize block producer
    90  	producer, err := blockproducer.New(modules.Signer, modules.Committee, builder)
    91  	if err != nil {
    92  		return nil, fmt.Errorf("could not initialize block producer: %w", err)
    93  	}
    94  
    95  	// initialize the voter
    96  	voter := voter.New(modules.Signer, modules.Forks, modules.Persist, modules.Committee, voted)
    97  
    98  	// initialize the event handler
    99  	eventHandler, err := eventhandler.NewEventHandler(
   100  		log,
   101  		pacemaker,
   102  		producer,
   103  		modules.Forks,
   104  		modules.Persist,
   105  		communicator,
   106  		modules.Committee,
   107  		modules.Aggregator,
   108  		voter,
   109  		modules.Validator,
   110  		modules.Notifier,
   111  	)
   112  	if err != nil {
   113  		return nil, fmt.Errorf("could not initialize event handler: %w", err)
   114  	}
   115  
   116  	// initialize and return the event loop
   117  	loop, err := eventloop.NewEventLoop(log, metrics, eventHandler, cfg.StartupTime)
   118  	if err != nil {
   119  		return nil, fmt.Errorf("could not initialize event loop: %w", err)
   120  	}
   121  
   122  	// add observer, event loop needs to receive events from distributor
   123  	modules.QCCreatedDistributor.AddConsumer(loop.SubmitTrustedQC)
   124  
   125  	// register dynamically updatable configs
   126  	if cfg.Registrar != nil {
   127  		err = cfg.Registrar.RegisterDurationConfig("hotstuff-block-rate-delay", timeoutConfig.GetBlockRateDelay, timeoutConfig.SetBlockRateDelay)
   128  		if err != nil {
   129  			return nil, fmt.Errorf("failed to register block rate delay config: %w", err)
   130  		}
   131  	}
   132  
   133  	return loop, nil
   134  }
   135  
   136  // NewForks creates new consensus forks manager
   137  func NewForks(final *flow.Header, headers storage.Headers, updater module.Finalizer, notifier hotstuff.Consumer, rootHeader *flow.Header, rootQC *flow.QuorumCertificate) (hotstuff.Forks, error) {
   138  	finalizer, err := newFinalizer(final, headers, updater, notifier, rootHeader, rootQC)
   139  	if err != nil {
   140  		return nil, fmt.Errorf("could not initialize finalizer: %w", err)
   141  	}
   142  
   143  	// initialize the fork choice
   144  	forkchoice, err := forkchoice.NewNewestForkChoice(finalizer, notifier)
   145  	if err != nil {
   146  		return nil, fmt.Errorf("could not initialize fork choice: %w", err)
   147  	}
   148  
   149  	// initialize the Forks manager
   150  	return forks.New(finalizer, forkchoice), nil
   151  }
   152  
   153  // NewValidator creates new instance of hotstuff validator needed for votes & proposal validation
   154  func NewValidator(metrics module.HotstuffMetrics, committee hotstuff.Committee, forks hotstuff.ForksReader) hotstuff.Validator {
   155  	packer := signature.NewConsensusSigDataPacker(committee)
   156  	verifier := verification.NewCombinedVerifier(committee, packer)
   157  
   158  	// initialize the Validator
   159  	validator := validatorImpl.New(committee, forks, verifier)
   160  	return validatorImpl.NewMetricsWrapper(validator, metrics) // wrapper for measuring time spent in Validator component
   161  }
   162  
   163  // newFinalizer recovers trusted root and creates new finalizer
   164  func newFinalizer(final *flow.Header, headers storage.Headers, updater module.Finalizer, notifier hotstuff.FinalizationConsumer, rootHeader *flow.Header, rootQC *flow.QuorumCertificate) (*finalizer.Finalizer, error) {
   165  	// recover the trusted root
   166  	trustedRoot, err := recoverTrustedRoot(final, headers, rootHeader, rootQC)
   167  	if err != nil {
   168  		return nil, fmt.Errorf("could not recover trusted root: %w", err)
   169  	}
   170  
   171  	// initialize the finalizer
   172  	finalizer, err := finalizer.New(trustedRoot, updater, notifier)
   173  	if err != nil {
   174  		return nil, fmt.Errorf("could not initialize finalizer: %w", err)
   175  	}
   176  
   177  	return finalizer, nil
   178  }
   179  
   180  // recoverTrustedRoot based on our local state returns root block and QC that can be used to initialize base state
   181  func recoverTrustedRoot(final *flow.Header, headers storage.Headers, rootHeader *flow.Header, rootQC *flow.QuorumCertificate) (*forks.BlockQC, error) {
   182  	if final.View < rootHeader.View {
   183  		return nil, fmt.Errorf("finalized Block has older view than trusted root")
   184  	}
   185  
   186  	// if finalized view is genesis block, then use genesis block as the trustedRoot
   187  	if final.View == rootHeader.View {
   188  		if final.ID() != rootHeader.ID() {
   189  			return nil, fmt.Errorf("finalized Block conflicts with trusted root")
   190  		}
   191  		return makeRootBlockQC(rootHeader, rootQC), nil
   192  	}
   193  
   194  	// get the parent for the latest finalized block
   195  	parent, err := headers.ByBlockID(final.ParentID)
   196  	if err != nil {
   197  		return nil, fmt.Errorf("could not get parent for finalized: %w", err)
   198  	}
   199  
   200  	// find a valid child of the finalized block in order to get its QC
   201  	children, err := headers.ByParentID(final.ID())
   202  	if err != nil {
   203  		// a finalized block must have a valid child, if err happens, we exit
   204  		return nil, fmt.Errorf("could not get children for finalized block (ID: %v, view: %v): %w", final.ID(), final.View, err)
   205  	}
   206  	if len(children) == 0 {
   207  		return nil, fmt.Errorf("finalized block has no children")
   208  	}
   209  
   210  	child := model.BlockFromFlow(children[0], final.View)
   211  
   212  	// create the root block to use
   213  	trustedRoot := &forks.BlockQC{
   214  		Block: model.BlockFromFlow(final, parent.View),
   215  		QC:    child.QC,
   216  	}
   217  
   218  	return trustedRoot, nil
   219  }
   220  
   221  func makeRootBlockQC(header *flow.Header, qc *flow.QuorumCertificate) *forks.BlockQC {
   222  	// By convention of Forks, the trusted root block does not need to have a qc
   223  	// (as is the case for the genesis block). For simplify of the implementation, we always omit
   224  	// the QC of the root block. Thereby, we have one algorithm which handles all cases,
   225  	// instead of having to distinguish between a genesis block without a qc
   226  	// and a later-finalized root block where we can retrieve the qc.
   227  	rootBlock := &model.Block{
   228  		View:        header.View,
   229  		BlockID:     header.ID(),
   230  		ProposerID:  header.ProposerID,
   231  		QC:          nil, // QC is omitted
   232  		PayloadHash: header.PayloadHash,
   233  		Timestamp:   header.Timestamp,
   234  	}
   235  	return &forks.BlockQC{
   236  		QC:    qc,
   237  		Block: rootBlock,
   238  	}
   239  }