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 }