Skip to content

Commit d14e62e

Browse files
committed
remove internal collector nodes constraint
No longer require a minimum count of internal nodes; instead just report whether enough internal nodes are present to vote for cluster QCs.
1 parent 25d4974 commit d14e62e

File tree

5 files changed

+18
-39
lines changed

5 files changed

+18
-39
lines changed

cmd/bootstrap/cmd/clustering.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func clusterAssignment(cmd *cobra.Command, args []string) {
120120
}
121121

122122
log.Info().Msg("computing collection node clusters")
123-
assignments, clusters, err := common.ConstructClusterAssignment(log, partnerList, internalList, int(flagCollectionClusters), clusteringPrg)
123+
assignments, clusters, canConstructQCs, err := common.ConstructClusterAssignment(log, partnerList, internalList, int(flagCollectionClusters), clusteringPrg)
124124
if err != nil {
125125
log.Fatal().Err(err).Msg("unable to generate cluster assignment")
126126
}
@@ -146,10 +146,10 @@ func clusterAssignment(cmd *cobra.Command, args []string) {
146146
)
147147
log.Info().Msg("")
148148

149-
if checkClusterConstraint(clusters, partnerNodes, internalNodes) {
150-
log.Info().Msg("Enough votes for collection clusters are present - bootstrapping can continue with root block creation")
149+
if canConstructQCs {
150+
log.Info().Msg("enough votes for collection clusters are present - bootstrapping can continue with root block creation")
151151
} else {
152-
log.Info().Msg("Not enough internal votes to generate cluster QCs, need partner votes before root block creation")
152+
log.Info().Msg("not enough internal votes to generate cluster QCs, need partner votes before root block creation")
153153
}
154154
}
155155

cmd/bootstrap/cmd/constraints.go

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,3 @@ func checkConstraints(partnerNodes, internalNodes []model.NodeInfo) {
3636

3737
ensureUniformNodeWeightsPerRole(all)
3838
}
39-
40-
// Check the ratio of internal/partner nodes in each cluster. The identities
41-
// in each cluster do not matter for this check.
42-
// Internal nodes must comprise >1/3 of each collector cluster.
43-
func checkClusterConstraint(clusters flow.ClusterList, partnersInfo []model.NodeInfo, internalsInfo []model.NodeInfo) bool {
44-
partners := model.ToIdentityList(partnersInfo)
45-
internals := model.ToIdentityList(internalsInfo)
46-
for _, cluster := range clusters {
47-
var clusterPartnerCount, clusterInternalCount int
48-
for _, node := range cluster {
49-
if _, exists := partners.ByNodeID(node.NodeID); exists {
50-
clusterPartnerCount++
51-
}
52-
if _, exists := internals.ByNodeID(node.NodeID); exists {
53-
clusterInternalCount++
54-
}
55-
}
56-
if clusterInternalCount*2 <= clusterPartnerCount {
57-
return false
58-
}
59-
}
60-
return true
61-
}

cmd/bootstrap/cmd/finalize_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,16 @@ func TestClusterAssignment(t *testing.T) {
137137

138138
log := zerolog.Nop()
139139
// should not error
140-
_, clusters, err := common.ConstructClusterAssignment(log, model.ToIdentityList(partners), model.ToIdentityList(internals), int(flagCollectionClusters), prng)
140+
_, _, canConstructQCs, err := common.ConstructClusterAssignment(log, model.ToIdentityList(partners), model.ToIdentityList(internals), int(flagCollectionClusters), prng)
141141
require.NoError(t, err)
142-
require.True(t, checkClusterConstraint(clusters, partners, internals))
142+
require.True(t, canConstructQCs)
143143

144144
// unhappy Path
145145
internals = internals[:len(internals)-1] // reduce one internal node
146-
// should error
147-
_, _, err = common.ConstructClusterAssignment(log, model.ToIdentityList(partners), model.ToIdentityList(internals), int(flagCollectionClusters), prng)
148-
require.Error(t, err)
146+
// should no longer be able to construct QCs using only votes from internal nodes
147+
_, _, canConstructQCs, err = common.ConstructClusterAssignment(log, model.ToIdentityList(partners), model.ToIdentityList(internals), int(flagCollectionClusters), prng)
148+
require.NoError(t, err)
149+
require.False(t, canConstructQCs)
149150
// revert the flag value
150151
flagCollectionClusters = tmp
151152
}

cmd/bootstrap/run/epochs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ func GenerateRecoverTxArgsWithDKG(
181181
return nil, fmt.Errorf("could not initialize PRNG: %w", err)
182182
}
183183
log.Info().Msgf("partitioning %d partners + %d internal nodes into %d collector clusters", len(partnerCollectors), len(internalCollectors), collectionClusters)
184-
assignments, clusters, err := common.ConstructClusterAssignment(log, partnerCollectors, internalCollectors, collectionClusters, rng)
184+
assignments, clusters, _, err := common.ConstructClusterAssignment(log, partnerCollectors, internalCollectors, collectionClusters, rng)
185185
if err != nil {
186186
return nil, fmt.Errorf("unable to generate cluster assignment: %w", err)
187187
}

cmd/util/cmd/common/clusters.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package common
22

33
import (
44
"encoding/hex"
5-
"errors"
65
"fmt"
76

87
"github.com/onflow/crypto/random"
@@ -40,8 +39,9 @@ import (
4039
// Returns:
4140
// - flow.AssignmentList: the generated assignment list.
4241
// - flow.ClusterList: the generate collection cluster list.
42+
// - bool: whether all cluster QCs can be created with only votes from internal nodes.
4343
// - error: if any error occurs. Any error returned from this function is irrecoverable.
44-
func ConstructClusterAssignment(log zerolog.Logger, partnerNodes, internalNodes flow.IdentityList, numCollectionClusters int, randomSource random.Rand) (flow.AssignmentList, flow.ClusterList, error) {
44+
func ConstructClusterAssignment(log zerolog.Logger, partnerNodes, internalNodes flow.IdentityList, numCollectionClusters int, randomSource random.Rand) (flow.AssignmentList, flow.ClusterList, bool, error) {
4545

4646
partnerCollectors := partnerNodes.Filter(filter.HasRole[flow.Identity](flow.RoleCollection))
4747
internalCollectors := internalNodes.Filter(filter.HasRole[flow.Identity](flow.RoleCollection))
@@ -78,7 +78,7 @@ func ConstructClusterAssignment(log zerolog.Logger, partnerNodes, internalNodes
7878
// first, round-robin internal nodes into each cluster
7979
for i, node := range internalCollectors {
8080
if node.InitialWeight != refWeight {
81-
return nil, nil, fmt.Errorf("current implementation requires all collectors (partner & interal nodes) to have equal weight")
81+
return nil, nil, false, fmt.Errorf("current implementation requires all collectors (partner & interal nodes) to have equal weight")
8282
}
8383
clusterIndex := i % numCollectionClusters
8484
identifierLists[clusterIndex] = append(identifierLists[clusterIndex], node.NodeID)
@@ -88,17 +88,18 @@ func ConstructClusterAssignment(log zerolog.Logger, partnerNodes, internalNodes
8888
// next, round-robin partner nodes into each cluster
8989
for i, node := range partnerCollectors {
9090
if node.InitialWeight != refWeight {
91-
return nil, nil, fmt.Errorf("current implementation requires all collectors (partner & interal nodes) to have equal weight")
91+
return nil, nil, false, fmt.Errorf("current implementation requires all collectors (partner & interal nodes) to have equal weight")
9292
}
9393
clusterIndex := i % numCollectionClusters
9494
identifierLists[clusterIndex] = append(identifierLists[clusterIndex], node.NodeID)
9595
constraint[clusterIndex] -= 1
9696
}
9797

9898
// check the 2/3 constraint: for every cluster `i`, constraint[i] must be strictly positive
99+
canConstructAllClusterQCs := true
99100
for i := 0; i < numCollectionClusters; i++ {
100101
if constraint[i] <= 0 {
101-
return nil, nil, errors.New("there isn't enough internal nodes to have at least 1/3 internal nodes in each cluster")
102+
canConstructAllClusterQCs = false
102103
}
103104
}
104105

@@ -110,7 +111,7 @@ func ConstructClusterAssignment(log zerolog.Logger, partnerNodes, internalNodes
110111
log.Fatal().Err(err).Msg("could not create cluster list")
111112
}
112113

113-
return assignments, clusters, nil
114+
return assignments, clusters, canConstructAllClusterQCs, nil
114115
}
115116

116117
// ConvertClusterAssignmentsCdc converts golang cluster assignments type to Cadence type `[[String]]`.

0 commit comments

Comments
 (0)