Skip to content

Commit 03ced55

Browse files
committed
update clustering bootstrap cmd and tests
1 parent 0f25336 commit 03ced55

File tree

5 files changed

+72
-8
lines changed

5 files changed

+72
-8
lines changed

cmd/bootstrap/cmd/clustering.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
package cmd
22

33
import (
4+
"fmt"
5+
"path/filepath"
6+
47
"github.com/spf13/cobra"
58

69
"github.com/onflow/flow-go/cmd"
10+
"github.com/onflow/flow-go/cmd/bootstrap/run"
711
"github.com/onflow/flow-go/cmd/util/cmd/common"
12+
hotstuff "github.com/onflow/flow-go/consensus/hotstuff/model"
813
model "github.com/onflow/flow-go/model/bootstrap"
14+
"github.com/onflow/flow-go/model/flow"
15+
cluster2 "github.com/onflow/flow-go/state/cluster"
916
"github.com/onflow/flow-go/state/protocol/prg"
1017
)
1118

@@ -132,8 +139,49 @@ func clusterAssignment(cmd *cobra.Command, args []string) {
132139
Assignments: assignments,
133140
Clusters: clusters,
134141
}
135-
err = common.WriteJSON(model.PathIntermediaryBootstrappingData, flagOutdir, output)
142+
err = common.WriteJSON(model.PathClusteringData, flagOutdir, output)
136143
if err != nil {
137144
log.Fatal().Err(err).Msg("failed to write json")
138145
}
146+
log.Info().Msgf("wrote file %s/%s", flagOutdir, model.PathClusteringData)
147+
log.Info().Msg("")
148+
149+
log.Info().Msg("constructing and writing cluster block votes for internal nodes")
150+
constructClusterRootVotes(
151+
output,
152+
model.FilterByRole(internalNodes, flow.RoleCollection),
153+
)
154+
log.Info().Msg("")
155+
}
156+
157+
// constructClusterRootVotes generates and writes vote files for internal collector nodes with private keys available.
158+
func constructClusterRootVotes(data IntermediaryClusteringData, internalCollectors []model.NodeInfo) {
159+
for i := range data.Clusters {
160+
clusterRootBlock, err := cluster2.CanonicalRootBlock(data.EpochCounter, data.Assignments[i])
161+
if err != nil {
162+
log.Fatal().Err(err).Msg("could not construct cluster root block")
163+
}
164+
block := hotstuff.GenesisBlockFromFlow(clusterRootBlock.ToHeader())
165+
// collate private NodeInfos for internal nodes in this cluster
166+
signers := make([]model.NodeInfo, 0)
167+
for _, nodeID := range data.Assignments[i] {
168+
for _, node := range internalCollectors {
169+
if node.NodeID == nodeID {
170+
signers = append(signers, node)
171+
}
172+
}
173+
}
174+
votes, err := run.CreateClusterRootBlockVotes(signers, block)
175+
if err != nil {
176+
log.Fatal().Err(err).Msg("could not create cluster root block votes")
177+
}
178+
for _, vote := range votes {
179+
path := filepath.Join(model.DirnameRootBlockVotes, fmt.Sprintf(model.FilenameRootClusterBlockVote, vote.SignerID))
180+
err = common.WriteJSON(path, flagOutdir, vote)
181+
if err != nil {
182+
log.Fatal().Err(err).Msg("failed to write json")
183+
}
184+
log.Info().Msgf("wrote file %s/%s", flagOutdir, path)
185+
}
186+
}
139187
}

cmd/bootstrap/cmd/finalize_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,19 @@ func TestFinalize_HappyPath(t *testing.T) {
6868
flagPartnerWeights = partnerWeights
6969
flagInternalNodePrivInfoDir = internalPrivDir
7070

71+
flagIntermediaryClusteringDataPath = filepath.Join(bootDir, model.PathClusteringData)
72+
flagRootClusterBlockVotesDir = filepath.Join(bootDir, model.DirnameRootBlockVotes)
73+
flagEpochCounter = epochCounter
74+
75+
// clusterAssignment will generate the collector clusters
76+
// In addition, it also generates votes from internal collector nodes
77+
clusterAssignment(clusterAssignmentCmd, nil)
78+
7179
flagRootChain = chainName
7280
flagRootParent = hex.EncodeToString(rootParent[:])
7381
flagRootHeight = rootHeight
7482
flagRootView = 1_000
7583
flagRootCommit = hex.EncodeToString(rootCommit[:])
76-
flagEpochCounter = epochCounter
7784
flagNumViewsInEpoch = 100_000
7885
flagNumViewsInStakingAuction = 50_000
7986
flagNumViewsInDKGPhase = 2_000

cmd/bootstrap/cmd/rootblock.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,14 @@ func addRootBlockCmdFlags() {
114114
rootBlockCmd.Flags().StringVar(&flagKVStoreVersion, "kvstore-version", "default",
115115
"protocol state KVStore version to initialize ('default' or an integer equal to a supported protocol version: '0', '1', '2', ...)")
116116
rootBlockCmd.Flags().BytesHexVar(&flagEpochRandomSeed, "random-seed", nil, "random seed")
117+
rootBlockCmd.Flags().StringVar(&flagIntermediaryClusteringDataPath, "intermediary-clustering-data", "", "path to a JSON file containing intermediary clustering data generated by the clustering command")
117118

118119
cmd.MarkFlagRequired(rootBlockCmd, "root-chain")
119120
cmd.MarkFlagRequired(rootBlockCmd, "root-parent")
120121
cmd.MarkFlagRequired(rootBlockCmd, "root-height")
121122
cmd.MarkFlagRequired(rootBlockCmd, "root-view")
122123
cmd.MarkFlagRequired(rootBlockCmd, "random-seed")
124+
cmd.MarkFlagRequired(rootBlockCmd, "intermediary-clustering-data")
123125

124126
// Epoch timing config - these values must be set identically to `EpochTimingConfig` in the FlowEpoch smart contract.
125127
// See https://github.com/onflow/flow-core-contracts/blob/240579784e9bb8d97d91d0e3213614e25562c078/contracts/epochs/FlowEpoch.cdc#L259-L266

cmd/bootstrap/cmd/rootblock_test.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ const rootBlockHappyPathLogs = "collecting partner network and staking keys" +
2828
`removed 0 internal partner nodes` +
2929
`checking constraints on consensus nodes` +
3030
`assembling network and staking keys` +
31-
`wrote file \S+/node-infos.pub.json` +
3231
`running DKG for consensus nodes` +
3332
`read \d+ node infos for DKG` +
3433
`will run DKG` +
3534
`finished running DKG` +
3635
`.+/random-beacon.priv.json` +
3736
`wrote file \S+/root-dkg-data.priv.json` +
38-
`computing collection node clusters` +
37+
`reading votes for collection node cluster root blocks` +
38+
`read vote .+` +
3939
`constructing root blocks for collection node clusters` +
4040
`constructing root QCs for collection node clusters` +
4141
`producing QC for cluster .*` +
@@ -59,11 +59,14 @@ func setupHappyPathFlags(bootDir, partnerDir, partnerWeights, internalPrivDir, c
5959
flagPartnerWeights = partnerWeights
6060
flagInternalNodePrivInfoDir = internalPrivDir
6161

62+
flagIntermediaryClusteringDataPath = filepath.Join(bootDir, model.PathClusteringData)
63+
flagRootClusterBlockVotesDir = filepath.Join(bootDir, model.DirnameRootBlockVotes)
64+
flagEpochCounter = 0
65+
6266
flagRootParent = hex.EncodeToString(rootParent[:])
6367
flagRootChain = "main"
6468
flagRootHeight = 12332
6569
flagRootView = 1000
66-
flagEpochCounter = 0
6770
flagNumViewsInEpoch = 100_000
6871
flagNumViewsInStakingAuction = 50_000
6972
flagNumViewsInDKGPhase = 2_000
@@ -81,6 +84,10 @@ func TestRootBlock_HappyPath(t *testing.T) {
8184
utils.RunWithSporkBootstrapDir(t, func(bootDir, partnerDir, partnerWeights, internalPrivDir, configPath string) {
8285
setupHappyPathFlags(bootDir, partnerDir, partnerWeights, internalPrivDir, configPath)
8386

87+
// clusterAssignment will generate the collector clusters
88+
// In addition, it also generates votes from internal collector nodes
89+
clusterAssignment(clusterAssignmentCmd, nil)
90+
8491
// KV store values (epoch extension view count and finalization safety threshold) must be explicitly set for mainnet
8592
require.NoError(t, rootBlockCmd.Flags().Set("kvstore-finalization-safety-threshold", "1000"))
8693
require.NoError(t, rootBlockCmd.Flags().Set("kvstore-epoch-extension-view-count", "100000"))

cmd/bootstrap/run/cluster_qc.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func GenerateClusterRootQC(signers []bootstrap.NodeInfo, allCommitteeMembers flo
2525
clusterRootBlock := model.GenesisBlockFromFlow(clusterBlock.ToHeader())
2626

2727
// STEP 1: create votes for cluster root block
28-
votes, err := createRootBlockVotes(signers, clusterRootBlock)
28+
votes, err := CreateClusterRootBlockVotes(signers, clusterRootBlock)
2929
if err != nil {
3030
return nil, err
3131
}
@@ -94,8 +94,8 @@ func createClusterValidator(committee hotstuff.DynamicCommittee) (hotstuff.Valid
9494
return hotstuffValidator, nil
9595
}
9696

97-
// createRootBlockVotes generates a vote for the rootBlock from each participant
98-
func createRootBlockVotes(participants []bootstrap.NodeInfo, rootBlock *model.Block) ([]*model.Vote, error) {
97+
// CreateClusterRootBlockVotes generates a vote for the rootBlock from each participant
98+
func CreateClusterRootBlockVotes(participants []bootstrap.NodeInfo, rootBlock *model.Block) ([]*model.Vote, error) {
9999
votes := make([]*model.Vote, 0, len(participants))
100100
for _, participant := range participants {
101101
// create the participant's local identity

0 commit comments

Comments
 (0)