github.com/koko1123/flow-go-1@v0.29.6/cmd/bootstrap/run/cluster_qc.go (about) 1 package run 2 3 import ( 4 "fmt" 5 6 "github.com/rs/zerolog" 7 8 "github.com/koko1123/flow-go-1/consensus/hotstuff" 9 "github.com/koko1123/flow-go-1/consensus/hotstuff/committees" 10 "github.com/koko1123/flow-go-1/consensus/hotstuff/mocks" 11 "github.com/koko1123/flow-go-1/consensus/hotstuff/model" 12 "github.com/koko1123/flow-go-1/consensus/hotstuff/validator" 13 "github.com/koko1123/flow-go-1/consensus/hotstuff/verification" 14 "github.com/koko1123/flow-go-1/consensus/hotstuff/votecollector" 15 "github.com/koko1123/flow-go-1/model/bootstrap" 16 "github.com/koko1123/flow-go-1/model/cluster" 17 "github.com/koko1123/flow-go-1/model/flow" 18 "github.com/koko1123/flow-go-1/model/flow/order" 19 "github.com/koko1123/flow-go-1/module/local" 20 ) 21 22 // GenerateClusterRootQC creates votes and generates a QC based on participant data 23 func GenerateClusterRootQC(signers []bootstrap.NodeInfo, allCommitteeMembers flow.IdentityList, clusterBlock *cluster.Block) (*flow.QuorumCertificate, error) { 24 clusterRootBlock := model.GenesisBlockFromFlow(clusterBlock.Header) 25 26 // STEP 1: create votes for cluster root block 27 votes, err := createRootBlockVotes(signers, clusterRootBlock) 28 if err != nil { 29 return nil, err 30 } 31 32 // STEP 2: create VoteProcessor 33 ordered := allCommitteeMembers.Sort(order.Canonical) 34 committee, err := committees.NewStaticCommittee(ordered, flow.Identifier{}, nil, nil) 35 if err != nil { 36 return nil, err 37 } 38 var createdQC *flow.QuorumCertificate 39 processor, err := votecollector.NewBootstrapStakingVoteProcessor(zerolog.Logger{}, committee, clusterRootBlock, func(qc *flow.QuorumCertificate) { 40 createdQC = qc 41 }) 42 if err != nil { 43 return nil, fmt.Errorf("could not create cluster's StakingVoteProcessor: %w", err) 44 } 45 46 // STEP 3: feed the votes into the vote processor to create QC 47 for _, vote := range votes { 48 err := processor.Process(vote) 49 if err != nil { 50 return nil, fmt.Errorf("could not process vote: %w", err) 51 } 52 } 53 if createdQC == nil { 54 return nil, fmt.Errorf("not enough votes to create qc for bootstrapping") 55 } 56 57 // STEP 4: validate constructed QC 58 val, err := createClusterValidator(committee) 59 if err != nil { 60 return nil, fmt.Errorf("could not create cluster validator: %w", err) 61 } 62 err = val.ValidateQC(createdQC, clusterRootBlock) 63 64 return createdQC, err 65 } 66 67 // createClusterValidator creates validator for cluster consensus 68 func createClusterValidator(committee hotstuff.Committee) (hotstuff.Validator, error) { 69 verifier := verification.NewStakingVerifier() 70 71 forks := &mocks.ForksReader{} 72 hotstuffValidator := validator.New(committee, forks, verifier) 73 return hotstuffValidator, nil 74 } 75 76 // createRootBlockVotes generates a vote for the rootBlock from each participant 77 func createRootBlockVotes(participants []bootstrap.NodeInfo, rootBlock *model.Block) ([]*model.Vote, error) { 78 votes := make([]*model.Vote, 0, len(participants)) 79 for _, participant := range participants { 80 // create the participant's local identity 81 keys, err := participant.PrivateKeys() 82 if err != nil { 83 return nil, fmt.Errorf("could not retrieve private keys for participant: %w", err) 84 } 85 me, err := local.New(participant.Identity(), keys.StakingKey) 86 if err != nil { 87 return nil, err 88 } 89 90 // generate root block vote 91 vote, err := verification.NewStakingSigner(me).CreateVote(rootBlock) 92 if err != nil { 93 return nil, fmt.Errorf("could not create cluster vote for participant %v: %w", me.NodeID(), err) 94 } 95 votes = append(votes, vote) 96 } 97 return votes, nil 98 }