-
Notifications
You must be signed in to change notification settings - Fork 174
/
channels.go
223 lines (184 loc) · 9.32 KB
/
channels.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
// (c) 2019 Dapper Labs - ALL RIGHTS RESERVED
package engine
import (
"fmt"
"strings"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/network"
)
// init is called first time this package is imported.
// It creates and initializes the channelRoleMap map.
func init() {
initializeChannelRoleMap()
}
// channelRoleMap keeps a map between channels and the list of flow roles involved in them.
var channelRoleMap map[network.Channel]flow.RoleList
// RolesByChannel returns list of flow roles involved in the channel.
func RolesByChannel(channel network.Channel) (flow.RoleList, bool) {
if clusterChannel, isCluster := ClusterChannel(channel); isCluster {
// replaces channel with the stripped-off prefix
channel = clusterChannel
}
roles, ok := channelRoleMap[channel]
return roles, ok
}
// Exists returns true if channel exists in channelRoleMap.
// At the current state, any developer-defined channel should be added
// to channelRoleMap as a constant channel type manually.
func Exists(channel network.Channel) bool {
_, exists := RolesByChannel(channel)
return exists
}
// ChannelsByRole returns a list of all channels the role subscribes to.
func ChannelsByRole(role flow.Role) network.ChannelList {
channels := make(network.ChannelList, 0)
for channel, roles := range channelRoleMap {
if roles.Contains(role) {
channels = append(channels, channel)
}
}
return channels
}
// UniqueChannels returns list of non-cluster channels with a unique RoleList accompanied
// with the list of all cluster channels.
// e.g. if channel X and Y both are non-cluster channels and have role IDs [A,B,C] then only one of them will be in the returned list.
func UniqueChannels(channels network.ChannelList) network.ChannelList {
// uniques keeps the set of unique channels based on their RoleList.
uniques := make(network.ChannelList, 0)
// added keeps track of channels added to uniques for deduplication.
added := make(map[flow.Identifier]struct{})
// a channel is added to uniques if it is either a
// cluster channel, or no non-cluster channel with the same set of roles
// has already been added to uniques.
// We use identifier of RoleList to determine its uniqueness.
for _, channel := range channels {
id := channelRoleMap[channel].ID()
// non-cluster channel deduplicated based identifier of role list
if _, cluster := ClusterChannel(channel); !cluster {
if _, ok := added[id]; ok {
// a channel with same RoleList already added, hence skips
continue
}
added[id] = struct{}{}
}
uniques = append(uniques, channel)
}
return uniques
}
// Channels returns all channels that nodes of any role have subscribed to.
func Channels() network.ChannelList {
channels := make(network.ChannelList, 0)
for channel := range channelRoleMap {
channels = append(channels, channel)
}
return channels
}
// channels
const (
// Channels used for testing
TestNetwork = network.Channel("test-network")
TestMetrics = network.Channel("test-metrics")
// Channels for consensus protocols
ConsensusCommittee = network.Channel("consensus-committee")
consensusClusterPrefix = network.Channel("consensus-cluster") // dynamic channel, use ChannelConsensusCluster function
// Channels for protocols actively synchronizing state across nodes
SyncCommittee = network.Channel("sync-committee")
syncClusterPrefix = network.Channel("sync-cluster") // dynamic channel, use ChannelSyncCluster function
SyncExecution = network.Channel("sync-execution")
// Channels for actively pushing entities to subscribers
PushTransactions = network.Channel("push-transactions")
PushGuarantees = network.Channel("push-guarantees")
PushBlocks = network.Channel("push-blocks")
PushReceipts = network.Channel("push-receipts")
PushApprovals = network.Channel("push-approvals")
// Channels for actively requesting missing entities
RequestCollections = network.Channel("request-collections")
RequestChunks = network.Channel("request-chunks")
RequestReceiptsByBlockID = network.Channel("request-receipts-by-block-id")
RequestApprovalsByChunk = network.Channel("request-approvals-by-chunk")
// Channel aliases to make the code more readable / more robust to errors
ReceiveTransactions = PushTransactions
ReceiveGuarantees = PushGuarantees
ReceiveBlocks = PushBlocks
ReceiveReceipts = PushReceipts
ReceiveApprovals = PushApprovals
ProvideCollections = RequestCollections
ProvideChunks = RequestChunks
ProvideReceiptsByBlockID = RequestReceiptsByBlockID
ProvideApprovalsByChunk = RequestApprovalsByChunk
)
// initializeChannelRoleMap initializes an instance of channelRoleMap and populates it with the channels and their
// Note: Please update this map, if a new channel is defined or a the roles subscribing to a channel have changed
// corresponding list of roles.
func initializeChannelRoleMap() {
channelRoleMap = make(map[network.Channel]flow.RoleList)
// Channels for test
channelRoleMap[TestNetwork] = flow.RoleList{flow.RoleCollection, flow.RoleConsensus, flow.RoleExecution,
flow.RoleVerification, flow.RoleAccess}
channelRoleMap[TestMetrics] = flow.RoleList{flow.RoleCollection, flow.RoleConsensus, flow.RoleExecution,
flow.RoleVerification, flow.RoleAccess}
// Channels for consensus protocols
channelRoleMap[ConsensusCommittee] = flow.RoleList{flow.RoleConsensus}
// Channels for protocols actively synchronizing state across nodes
channelRoleMap[SyncCommittee] = flow.RoleList{flow.RoleConsensus}
channelRoleMap[SyncExecution] = flow.RoleList{flow.RoleExecution}
// Channels for actively pushing entities to subscribers
channelRoleMap[PushTransactions] = flow.RoleList{flow.RoleCollection}
channelRoleMap[PushGuarantees] = flow.RoleList{flow.RoleCollection, flow.RoleConsensus}
channelRoleMap[PushBlocks] = flow.RoleList{flow.RoleCollection, flow.RoleConsensus, flow.RoleExecution,
flow.RoleVerification, flow.RoleAccess}
channelRoleMap[PushReceipts] = flow.RoleList{flow.RoleConsensus, flow.RoleExecution, flow.RoleVerification,
flow.RoleAccess}
channelRoleMap[PushApprovals] = flow.RoleList{flow.RoleConsensus, flow.RoleVerification}
// Channels for actively requesting missing entities
channelRoleMap[RequestCollections] = flow.RoleList{flow.RoleCollection, flow.RoleExecution}
channelRoleMap[RequestChunks] = flow.RoleList{flow.RoleExecution, flow.RoleVerification}
channelRoleMap[RequestReceiptsByBlockID] = flow.RoleList{flow.RoleConsensus, flow.RoleExecution}
channelRoleMap[RequestApprovalsByChunk] = flow.RoleList{flow.RoleConsensus, flow.RoleVerification}
// Channel aliases to make the code more readable / more robust to errors
channelRoleMap[ReceiveGuarantees] = flow.RoleList{flow.RoleCollection, flow.RoleConsensus}
channelRoleMap[ReceiveBlocks] = flow.RoleList{flow.RoleCollection, flow.RoleConsensus, flow.RoleExecution,
flow.RoleVerification, flow.RoleAccess}
channelRoleMap[ReceiveReceipts] = flow.RoleList{flow.RoleConsensus, flow.RoleExecution, flow.RoleVerification,
flow.RoleAccess}
channelRoleMap[ReceiveApprovals] = flow.RoleList{flow.RoleConsensus, flow.RoleVerification}
channelRoleMap[ProvideCollections] = flow.RoleList{flow.RoleCollection, flow.RoleExecution}
channelRoleMap[ProvideChunks] = flow.RoleList{flow.RoleExecution, flow.RoleVerification}
channelRoleMap[ProvideReceiptsByBlockID] = flow.RoleList{flow.RoleConsensus, flow.RoleExecution}
channelRoleMap[ProvideApprovalsByChunk] = flow.RoleList{flow.RoleConsensus, flow.RoleVerification}
channelRoleMap[syncClusterPrefix] = flow.RoleList{flow.RoleCollection}
channelRoleMap[consensusClusterPrefix] = flow.RoleList{flow.RoleCollection}
}
// ClusterChannel returns true if channel is cluster-based.
// At the current implementation, only collection nodes are involved in a cluster-based channels.
// If the channel is a cluster-based one, this method also strips off the channel prefix and returns it.
func ClusterChannel(channel network.Channel) (network.Channel, bool) {
if strings.HasPrefix(channel.String(), syncClusterPrefix.String()) {
return syncClusterPrefix, true
}
if strings.HasPrefix(channel.String(), consensusClusterPrefix.String()) {
return consensusClusterPrefix, true
}
return "", false
}
// TopicFromChannel returns the unique LibP2P topic form the channel.
// The channel is made up of name string suffixed with root block id.
// The root block id is used to prevent cross talks between nodes on different sporks.
func TopicFromChannel(channel network.Channel, rootBlockID string) network.Topic {
// skip root block suffix, if this is a cluster specific channel. A cluster specific channel is inherently
// unique for each epoch
if strings.HasPrefix(channel.String(), syncClusterPrefix.String()) || strings.HasPrefix(string(channel), consensusClusterPrefix.String()) {
return network.Topic(channel)
}
return network.Topic(fmt.Sprintf("%s/%s", string(channel), rootBlockID))
}
// ChannelConsensusCluster returns a dynamic cluster consensus channel based on
// the chain ID of the cluster in question.
func ChannelConsensusCluster(clusterID flow.ChainID) network.Channel {
return network.Channel(fmt.Sprintf("%s-%s", consensusClusterPrefix, clusterID))
}
// ChannelSyncCluster returns a dynamic cluster sync channel based on the chain
// ID of the cluster in question.
func ChannelSyncCluster(clusterID flow.ChainID) network.Channel {
return network.Channel(fmt.Sprintf("%s-%s", syncClusterPrefix, clusterID))
}