Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions state/protocol/validity.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func IsValidEpochSetup(setup *flow.EpochSetup, verifyNetworkAddress bool) error
// (a) each has a unique node ID,
// (b) each has a unique network address (if `verifyNetworkAddress` is true),
// (c) participants are sorted in canonical order.
// (d) each has a valid role.
// Note that the system smart contracts manage the identity table as an unordered set! For the protocol state, we desire a fixed
// ordering to simplify various implementation details, like the DKG. Therefore, we order identities in `flow.EpochSetup` during
// conversion from cadence to Go in the function `convert.ServiceEvent(flow.ChainID, flow.Event)` in package `model/convert`
Expand Down Expand Up @@ -86,6 +87,13 @@ func IsValidEpochSetup(setup *flow.EpochSetup, verifyNetworkAddress bool) error
return fmt.Errorf("participants are not canonically ordered")
}

// (d) each participant has a valid role
for _, participant := range setup.Participants {
if !participant.Role.Valid() {
return fmt.Errorf("invalid participant role (%d) for node (%x)", participant.Role, participant.NodeID)
}
}

// 3. CHECK: Enforce sufficient number of nodes for each role
// IMPORTANT: here we remove all nodes with zero weight, as they are allowed to partake in communication but not in respective node functions
activeParticipants := setup.Participants.Filter(filter.HasInitialWeight[flow.IdentitySkeleton](true))
Expand Down
16 changes: 16 additions & 0 deletions state/protocol/validity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,22 @@ func TestEpochSetupValidity(t *testing.T) {
require.Error(t, err)
})

t.Run("invalid participant role", func(t *testing.T) {
_, result, _ := unittest.BootstrapFixture(participants)
setup := result.ServiceEvents[0].Event.(*flow.EpochSetup)

// mutate a consensus node (not a collector, so cluster assignment stays valid)
for i, p := range setup.Participants {
if p.Role == flow.RoleConsensus {
setup.Participants[i].Role = flow.Role(42)
break
}
}

err := protocol.IsValidEpochSetup(setup, true)
require.Error(t, err)
})

t.Run("network addresses are not unique", func(t *testing.T) {
_, result, _ := unittest.BootstrapFixture(participants)
setup := result.ServiceEvents[0].Event.(*flow.EpochSetup)
Expand Down
Loading