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