github.com/onflow/flow-go@v0.33.17/consensus/hotstuff/blockproducer/block_producer.go (about)

     1  package blockproducer
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/flow-go/consensus/hotstuff"
     7  	"github.com/onflow/flow-go/consensus/hotstuff/model"
     8  	"github.com/onflow/flow-go/model/flow"
     9  	"github.com/onflow/flow-go/module"
    10  )
    11  
    12  // BlockProducer is responsible for producing new block proposals
    13  type BlockProducer struct {
    14  	signer    hotstuff.Signer
    15  	committee hotstuff.Replicas
    16  	builder   module.Builder
    17  }
    18  
    19  var _ hotstuff.BlockProducer = (*BlockProducer)(nil)
    20  
    21  // New creates a new BlockProducer which wraps the chain compliance layer block builder
    22  // to provide hotstuff with block proposals.
    23  // No errors are expected during normal operation.
    24  func New(signer hotstuff.Signer, committee hotstuff.Replicas, builder module.Builder) (*BlockProducer, error) {
    25  	bp := &BlockProducer{
    26  		signer:    signer,
    27  		committee: committee,
    28  		builder:   builder,
    29  	}
    30  	return bp, nil
    31  }
    32  
    33  // MakeBlockProposal builds a new HotStuff block proposal using the given view,
    34  // the given quorum certificate for its parent and [optionally] a timeout certificate for last view(could be nil).
    35  // No errors are expected during normal operation.
    36  func (bp *BlockProducer) MakeBlockProposal(view uint64, qc *flow.QuorumCertificate, lastViewTC *flow.TimeoutCertificate) (*flow.Header, error) {
    37  	// the custom functions allows us to set some custom fields on the block;
    38  	// in hotstuff, we use this for view number and signature-related fields
    39  	setHotstuffFields := func(header *flow.Header) error {
    40  		header.View = view
    41  		header.ParentView = qc.View
    42  		header.ParentVoterIndices = qc.SignerIndices
    43  		header.ParentVoterSigData = qc.SigData
    44  		header.ProposerID = bp.committee.Self()
    45  		header.LastViewTC = lastViewTC
    46  
    47  		// turn the header into a block header proposal as known by hotstuff
    48  		block := model.Block{
    49  			BlockID:     header.ID(),
    50  			View:        view,
    51  			ProposerID:  header.ProposerID,
    52  			QC:          qc,
    53  			PayloadHash: header.PayloadHash,
    54  			Timestamp:   header.Timestamp,
    55  		}
    56  
    57  		// then sign the proposal
    58  		proposal, err := bp.signer.CreateProposal(&block)
    59  		if err != nil {
    60  			return fmt.Errorf("could not sign block proposal: %w", err)
    61  		}
    62  
    63  		header.ProposerSigData = proposal.SigData
    64  		return nil
    65  	}
    66  
    67  	// retrieve a fully built block header from the builder
    68  	header, err := bp.builder.BuildOn(qc.BlockID, setHotstuffFields)
    69  	if err != nil {
    70  		return nil, fmt.Errorf("could not build block proposal on top of %v: %w", qc.BlockID, err)
    71  	}
    72  
    73  	return header, nil
    74  }