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

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