github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/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 return nil 47 } 48 49 // TODO: We should utilize the `EventHandler`'s `SafetyRules` to generate the block signature instead of using an independent signing logic: https://github.com/dapperlabs/flow-go/issues/6892 50 signProposal := func(header *flow.Header) error { 51 // turn the header into a block header proposal as known by hotstuff 52 block := model.Block{ 53 BlockID: header.ID(), 54 View: view, 55 ProposerID: header.ProposerID, 56 QC: qc, 57 PayloadHash: header.PayloadHash, 58 Timestamp: header.Timestamp, 59 } 60 61 // then sign the proposal 62 proposal, err := bp.signer.CreateProposal(&block) 63 if err != nil { 64 return fmt.Errorf("could not sign block proposal: %w", err) 65 } 66 67 header.ProposerSigData = proposal.SigData 68 return nil 69 } 70 71 // retrieve a fully built block header from the builder 72 header, err := bp.builder.BuildOn(qc.BlockID, setHotstuffFields, signProposal) 73 if err != nil { 74 return nil, fmt.Errorf("could not build block proposal on top of %v: %w", qc.BlockID, err) 75 } 76 77 return header, nil 78 }