github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/collection/epochmgr/factories/hotstuff.go (about)

     1  package factories
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/dgraph-io/badger/v2"
     7  	"github.com/rs/zerolog"
     8  
     9  	"github.com/onflow/flow-go/consensus"
    10  	"github.com/onflow/flow-go/consensus/hotstuff"
    11  	"github.com/onflow/flow-go/consensus/hotstuff/blockproducer"
    12  	"github.com/onflow/flow-go/consensus/hotstuff/committees"
    13  	"github.com/onflow/flow-go/consensus/hotstuff/notifications"
    14  	"github.com/onflow/flow-go/consensus/hotstuff/notifications/pubsub"
    15  	"github.com/onflow/flow-go/consensus/hotstuff/persister"
    16  	"github.com/onflow/flow-go/consensus/hotstuff/timeoutcollector"
    17  	validatorImpl "github.com/onflow/flow-go/consensus/hotstuff/validator"
    18  	"github.com/onflow/flow-go/consensus/hotstuff/verification"
    19  	"github.com/onflow/flow-go/consensus/hotstuff/votecollector"
    20  	recovery "github.com/onflow/flow-go/consensus/recovery/cluster"
    21  	"github.com/onflow/flow-go/model/flow"
    22  	"github.com/onflow/flow-go/module"
    23  	hotmetrics "github.com/onflow/flow-go/module/metrics/hotstuff"
    24  	msig "github.com/onflow/flow-go/module/signature"
    25  	"github.com/onflow/flow-go/state/cluster"
    26  	"github.com/onflow/flow-go/state/protocol"
    27  	"github.com/onflow/flow-go/storage"
    28  )
    29  
    30  type HotStuffMetricsFunc func(chainID flow.ChainID) module.HotstuffMetrics
    31  
    32  type HotStuffFactory struct {
    33  	baseLogger     zerolog.Logger
    34  	me             module.Local
    35  	db             *badger.DB
    36  	protoState     protocol.State
    37  	engineMetrics  module.EngineMetrics
    38  	mempoolMetrics module.MempoolMetrics
    39  	createMetrics  HotStuffMetricsFunc
    40  	opts           []consensus.Option
    41  }
    42  
    43  func NewHotStuffFactory(
    44  	log zerolog.Logger,
    45  	me module.Local,
    46  	db *badger.DB,
    47  	protoState protocol.State,
    48  	engineMetrics module.EngineMetrics,
    49  	mempoolMetrics module.MempoolMetrics,
    50  	createMetrics HotStuffMetricsFunc,
    51  	opts ...consensus.Option,
    52  ) (*HotStuffFactory, error) {
    53  
    54  	factory := &HotStuffFactory{
    55  		baseLogger:     log,
    56  		me:             me,
    57  		db:             db,
    58  		protoState:     protoState,
    59  		engineMetrics:  engineMetrics,
    60  		mempoolMetrics: mempoolMetrics,
    61  		createMetrics:  createMetrics,
    62  		opts:           opts,
    63  	}
    64  	return factory, nil
    65  }
    66  
    67  func (f *HotStuffFactory) CreateModules(
    68  	epoch protocol.Epoch,
    69  	cluster protocol.Cluster,
    70  	clusterState cluster.State,
    71  	headers storage.Headers,
    72  	payloads storage.ClusterPayloads,
    73  	updater module.Finalizer,
    74  ) (*consensus.HotstuffModules, module.HotstuffMetrics, error) {
    75  	// setup metrics/logging with the new chain ID
    76  	log := f.createLogger(cluster)
    77  	metrics := f.createMetrics(cluster.ChainID())
    78  	telemetryConsumer := notifications.NewTelemetryConsumer(log)
    79  	slashingConsumer := notifications.NewSlashingViolationsConsumer(log)
    80  	notifier := pubsub.NewDistributor()
    81  	notifier.AddConsumer(notifications.NewLogConsumer(log))
    82  	notifier.AddConsumer(hotmetrics.NewMetricsConsumer(metrics))
    83  	notifier.AddParticipantConsumer(telemetryConsumer)
    84  	notifier.AddProposalViolationConsumer(slashingConsumer)
    85  
    86  	var (
    87  		err       error
    88  		committee hotstuff.DynamicCommittee
    89  	)
    90  	committee, err = committees.NewClusterCommittee(f.protoState, payloads, cluster, epoch, f.me.NodeID())
    91  	if err != nil {
    92  		return nil, nil, fmt.Errorf("could not create cluster committee: %w", err)
    93  	}
    94  	committee = committees.NewMetricsWrapper(committee, metrics) // wrapper for measuring time spent determining consensus committee relations
    95  
    96  	// create a signing provider
    97  	var signer hotstuff.Signer = verification.NewStakingSigner(f.me)
    98  	signer = verification.NewMetricsWrapper(signer, metrics) // wrapper for measuring time spent with crypto-related operations
    99  
   100  	finalizedBlock, err := clusterState.Final().Head()
   101  	if err != nil {
   102  		return nil, nil, fmt.Errorf("could not get cluster finalized block: %w", err)
   103  	}
   104  
   105  	forks, err := consensus.NewForks(
   106  		finalizedBlock,
   107  		headers,
   108  		updater,
   109  		notifier,
   110  		cluster.RootBlock().Header,
   111  		cluster.RootQC(),
   112  	)
   113  	if err != nil {
   114  		return nil, nil, err
   115  	}
   116  
   117  	voteAggregationDistributor := pubsub.NewVoteAggregationDistributor()
   118  	voteAggregationDistributor.AddVoteCollectorConsumer(telemetryConsumer)
   119  	voteAggregationDistributor.AddVoteAggregationViolationConsumer(slashingConsumer)
   120  
   121  	verifier := verification.NewStakingVerifier()
   122  	validator := validatorImpl.NewMetricsWrapper(validatorImpl.New(committee, verifier), metrics)
   123  	voteProcessorFactory := votecollector.NewStakingVoteProcessorFactory(committee, voteAggregationDistributor.OnQcConstructedFromVotes)
   124  	voteAggregator, err := consensus.NewVoteAggregator(
   125  		log,
   126  		metrics,
   127  		f.engineMetrics,
   128  		f.mempoolMetrics,
   129  		// since we don't want to aggregate votes for finalized view,
   130  		// the lowest retained view starts with the next view of the last finalized view.
   131  		finalizedBlock.View+1,
   132  		voteAggregationDistributor,
   133  		voteProcessorFactory,
   134  		notifier.FollowerDistributor,
   135  	)
   136  	if err != nil {
   137  		return nil, nil, err
   138  	}
   139  
   140  	timeoutCollectorDistributor := pubsub.NewTimeoutAggregationDistributor()
   141  	timeoutCollectorDistributor.AddTimeoutCollectorConsumer(telemetryConsumer)
   142  	timeoutCollectorDistributor.AddTimeoutAggregationViolationConsumer(slashingConsumer)
   143  
   144  	timeoutProcessorFactory := timeoutcollector.NewTimeoutProcessorFactory(log, timeoutCollectorDistributor, committee, validator, msig.CollectorTimeoutTag)
   145  	timeoutAggregator, err := consensus.NewTimeoutAggregator(
   146  		log,
   147  		metrics,
   148  		f.engineMetrics,
   149  		f.mempoolMetrics,
   150  		notifier,
   151  		timeoutProcessorFactory,
   152  		timeoutCollectorDistributor,
   153  		finalizedBlock.View+1,
   154  	)
   155  	if err != nil {
   156  		return nil, nil, err
   157  	}
   158  
   159  	return &consensus.HotstuffModules{
   160  		Forks:                       forks,
   161  		Validator:                   validator,
   162  		Notifier:                    notifier,
   163  		Committee:                   committee,
   164  		Signer:                      signer,
   165  		Persist:                     persister.New(f.db, cluster.ChainID()),
   166  		VoteAggregator:              voteAggregator,
   167  		TimeoutAggregator:           timeoutAggregator,
   168  		VoteCollectorDistributor:    voteAggregationDistributor.VoteCollectorDistributor,
   169  		TimeoutCollectorDistributor: timeoutCollectorDistributor.TimeoutCollectorDistributor,
   170  	}, metrics, nil
   171  }
   172  
   173  func (f *HotStuffFactory) Create(
   174  	cluster protocol.Cluster,
   175  	clusterState cluster.State,
   176  	metrics module.HotstuffMetrics,
   177  	builder module.Builder,
   178  	headers storage.Headers,
   179  	hotstuffModules *consensus.HotstuffModules,
   180  ) (module.HotStuff, error) {
   181  
   182  	// setup metrics/logging with the new chain ID
   183  	builder = blockproducer.NewMetricsWrapper(builder, metrics) // wrapper for measuring time spent building block payload component
   184  
   185  	finalizedBlock, pendingBlocks, err := recovery.FindLatest(clusterState, headers)
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  
   190  	log := f.createLogger(cluster)
   191  	participant, err := consensus.NewParticipant(
   192  		log,
   193  		metrics,
   194  		f.mempoolMetrics,
   195  		builder,
   196  		finalizedBlock,
   197  		pendingBlocks,
   198  		hotstuffModules,
   199  		f.opts...,
   200  	)
   201  	return participant, err
   202  }
   203  
   204  // createLogger creates a logger by wrapping base logger by decorating it will cluster ID
   205  func (f *HotStuffFactory) createLogger(cluster protocol.Cluster) zerolog.Logger {
   206  	return f.baseLogger.With().Str("chain", cluster.ChainID().String()).Logger()
   207  }