-
Notifications
You must be signed in to change notification settings - Fork 199
/
p2p.go
354 lines (296 loc) · 12.6 KB
/
p2p.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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
package p2p
import (
"context"
"encoding/hex"
"io"
"time"
"github.com/ElrondNetwork/elrond-go-core/core"
)
const displayLastPidChars = 12
const (
// ListsSharder is the variant that uses lists
ListsSharder = "ListsSharder"
// OneListSharder is the variant that is shard agnostic and uses one list
OneListSharder = "OneListSharder"
// NilListSharder is the variant that will not do connection trimming
NilListSharder = "NilListSharder"
)
// NodeOperation defines the p2p node operation
type NodeOperation string
// NormalOperation defines the normal mode operation: either seeder, observer or validator
const NormalOperation NodeOperation = "normal operation"
// FullArchiveMode defines the node operation as a full archive mode
const FullArchiveMode NodeOperation = "full archive mode"
const (
// ConnectionWatcherTypePrint - new connection found will be printed in the log file
ConnectionWatcherTypePrint = "print"
// ConnectionWatcherTypeDisabled - no connection watching should be made
ConnectionWatcherTypeDisabled = "disabled"
// ConnectionWatcherTypeEmpty - not set, no connection watching should be made
ConnectionWatcherTypeEmpty = ""
)
// MessageProcessor is the interface used to describe what a receive message processor should do
// All implementations that will be called from Messenger implementation will need to satisfy this interface
// If the function returns a non nil value, the received message will not be propagated to its connected peers
type MessageProcessor interface {
ProcessReceivedMessage(message MessageP2P, fromConnectedPeer core.PeerID) error
IsInterfaceNil() bool
}
// SendableData represents the struct used in data throttler implementation
type SendableData struct {
Buff []byte
Topic string
}
// PeerDiscoverer defines the behaviour of a peer discovery mechanism
type PeerDiscoverer interface {
Bootstrap() error
Name() string
IsInterfaceNil() bool
}
// Reconnecter defines the behaviour of a network reconnection mechanism
type Reconnecter interface {
ReconnectToNetwork(ctx context.Context)
IsInterfaceNil() bool
}
// Messenger is the main struct used for communication with other peers
type Messenger interface {
io.Closer
// ID is the Messenger's unique peer identifier across the network (a
// string). It is derived from the public key of the P2P credentials.
ID() core.PeerID
// Peers is the list of IDs of peers known to the Messenger.
Peers() []core.PeerID
// Addresses is the list of addresses that the Messenger is currently bound
// to and listening to.
Addresses() []string
// ConnectToPeer explicitly connect to a specific peer with a known address (note that the
// address contains the peer ID). This function is usually not called
// manually, because any underlying implementation of the Messenger interface
// should be keeping connections to peers open.
ConnectToPeer(address string) error
// IsConnected returns true if the Messenger are connected to a specific peer.
IsConnected(peerID core.PeerID) bool
// ConnectedPeers returns the list of IDs of the peers the Messenger is
// currently connected to.
ConnectedPeers() []core.PeerID
// ConnectedAddresses returns the list of addresses of the peers to which the
// Messenger is currently connected.
ConnectedAddresses() []string
// PeerAddresses returns the known addresses for the provided peer ID
PeerAddresses(pid core.PeerID) []string
// ConnectedPeersOnTopic returns the IDs of the peers to which the Messenger
// is currently connected, but filtered by a topic they are registered to.
ConnectedPeersOnTopic(topic string) []core.PeerID
// ConnectedFullHistoryPeersOnTopic returns the IDs of the full history peers to which the Messenger
// is currently connected, but filtered by a topic they are registered to.
ConnectedFullHistoryPeersOnTopic(topic string) []core.PeerID
// Bootstrap runs the initialization phase which includes peer discovery,
// setting up initial connections and self-announcement in the network.
Bootstrap() error
// CreateTopic defines a new topic for sending messages, and optionally
// creates a channel in the LoadBalancer for this topic (otherwise, the topic
// will use a default channel).
CreateTopic(name string, createChannelForTopic bool) error
// HasTopic returns true if the Messenger has declared interest in a topic
// and it is listening to messages referencing it.
HasTopic(name string) bool
// RegisterMessageProcessor adds the provided MessageProcessor to the list
// of handlers that are invoked whenever a message is received on the
// specified topic.
RegisterMessageProcessor(topic string, identifier string, handler MessageProcessor) error
// UnregisterAllMessageProcessors removes all the MessageProcessor set by the
// Messenger from the list of registered handlers for the messages on the
// given topic.
UnregisterAllMessageProcessors() error
// UnregisterMessageProcessor removes the MessageProcessor set by the
// Messenger from the list of registered handlers for the messages on the
// given topic.
UnregisterMessageProcessor(topic string, identifier string) error
// BroadcastOnChannelBlocking asynchronously waits until it can send a
// message on the channel, but once it is able to, it synchronously sends the
// message, blocking until sending is completed.
BroadcastOnChannelBlocking(channel string, topic string, buff []byte) error
// BroadcastOnChannel asynchronously sends a message on a given topic
// through a specified channel.
BroadcastOnChannel(channel string, topic string, buff []byte)
// Broadcast is a convenience function that calls BroadcastOnChannelBlocking,
// but implicitly sets the channel to be identical to the specified topic.
Broadcast(topic string, buff []byte)
// SendToConnectedPeer asynchronously sends a message to a peer directly,
// bypassing pubsub and topics. It opens a new connection with the given
// peer, but reuses a connection and a stream if possible.
SendToConnectedPeer(topic string, buff []byte, peerID core.PeerID) error
IsConnectedToTheNetwork() bool
ThresholdMinConnectedPeers() int
SetThresholdMinConnectedPeers(minConnectedPeers int) error
SetPeerShardResolver(peerShardResolver PeerShardResolver) error
SetPeerDenialEvaluator(handler PeerDenialEvaluator) error
GetConnectedPeersInfo() *ConnectedPeersInfo
UnjoinAllTopics() error
Port() int
WaitForConnections(maxWaitingTime time.Duration, minNumOfPeers uint32)
Sign(payload []byte) ([]byte, error)
Verify(payload []byte, pid core.PeerID, signature []byte) error
// IsInterfaceNil returns true if there is no value under the interface
IsInterfaceNil() bool
}
// MessageP2P defines what a p2p message can do (should return)
type MessageP2P interface {
From() []byte
Data() []byte
Payload() []byte
SeqNo() []byte
Topic() string
Signature() []byte
Key() []byte
Peer() core.PeerID
Timestamp() int64
IsInterfaceNil() bool
}
// ChannelLoadBalancer defines what a load balancer that uses chans should do
type ChannelLoadBalancer interface {
AddChannel(channel string) error
RemoveChannel(channel string) error
GetChannelOrDefault(channel string) chan *SendableData
CollectOneElementFromChannels() *SendableData
Close() error
IsInterfaceNil() bool
}
// DirectSender defines a component that can send direct messages to connected peers
type DirectSender interface {
NextSeqno() []byte
Send(topic string, buff []byte, peer core.PeerID) error
IsInterfaceNil() bool
}
// PeerDiscoveryFactory defines the factory for peer discoverer implementation
type PeerDiscoveryFactory interface {
CreatePeerDiscoverer() (PeerDiscoverer, error)
IsInterfaceNil() bool
}
// MessageOriginatorPid will output the message peer id in a pretty format
// If it can, it will display the last displayLastPidChars (12) characters from the pid
func MessageOriginatorPid(msg MessageP2P) string {
return PeerIdToShortString(msg.Peer())
}
// PeerIdToShortString trims the first displayLastPidChars characters of the provided peer ID after
// converting the peer ID to string using the Pretty functionality
func PeerIdToShortString(pid core.PeerID) string {
prettyPid := pid.Pretty()
lenPrettyPid := len(prettyPid)
if lenPrettyPid > displayLastPidChars {
return "..." + prettyPid[lenPrettyPid-displayLastPidChars:]
}
return prettyPid
}
// MessageOriginatorSeq will output the sequence number as hex
func MessageOriginatorSeq(msg MessageP2P) string {
return hex.EncodeToString(msg.SeqNo())
}
// PeerShardResolver is able to resolve the link between the provided PeerID and the shardID
type PeerShardResolver interface {
GetPeerInfo(pid core.PeerID) core.P2PPeerInfo
IsInterfaceNil() bool
}
// ConnectedPeersInfo represents the DTO structure used to output the metrics for connected peers
type ConnectedPeersInfo struct {
SelfShardID uint32
UnknownPeers []string
Seeders []string
IntraShardValidators map[uint32][]string
IntraShardObservers map[uint32][]string
CrossShardValidators map[uint32][]string
CrossShardObservers map[uint32][]string
FullHistoryObservers map[uint32][]string
NumValidatorsOnShard map[uint32]int
NumObserversOnShard map[uint32]int
NumPreferredPeersOnShard map[uint32]int
NumIntraShardValidators int
NumIntraShardObservers int
NumCrossShardValidators int
NumCrossShardObservers int
NumFullHistoryObservers int
}
// NetworkShardingCollector defines the updating methods used by the network sharding component
// The interface assures that the collected data will be used by the p2p network sharding components
type NetworkShardingCollector interface {
UpdatePeerIDInfo(pid core.PeerID, pk []byte, shardID uint32)
IsInterfaceNil() bool
}
// SignerVerifier is used in higher level protocol authentication of 2 peers after the basic p2p connection has been made
type SignerVerifier interface {
Sign(message []byte) ([]byte, error)
Verify(message []byte, sig []byte, pk []byte) error
PublicKey() []byte
IsInterfaceNil() bool
}
// Marshalizer defines the 2 basic operations: serialize (marshal) and deserialize (unmarshal)
type Marshalizer interface {
Marshal(obj interface{}) ([]byte, error)
Unmarshal(obj interface{}, buff []byte) error
IsInterfaceNil() bool
}
// PreferredPeersHolderHandler defines the behavior of a component able to handle preferred peers operations
type PreferredPeersHolderHandler interface {
PutConnectionAddress(peerID core.PeerID, address string)
PutShardID(peerID core.PeerID, shardID uint32)
Get() map[uint32][]core.PeerID
Contains(peerID core.PeerID) bool
Remove(peerID core.PeerID)
Clear()
IsInterfaceNil() bool
}
// PeerCounts represents the DTO structure used to output the count metrics for connected peers
type PeerCounts struct {
UnknownPeers int
IntraShardPeers int
CrossShardPeers int
}
// Sharder defines the eviction computing process of unwanted peers
type Sharder interface {
SetSeeders(addresses []string)
IsSeeder(pid core.PeerID) bool
SetPeerShardResolver(psp PeerShardResolver) error
IsInterfaceNil() bool
}
// PeerDenialEvaluator defines the behavior of a component that is able to decide if a peer ID is black listed or not
// TODO merge this interface with the PeerShardResolver => P2PProtocolHandler ?
// TODO move antiflooding inside network messenger
type PeerDenialEvaluator interface {
IsDenied(pid core.PeerID) bool
UpsertPeerID(pid core.PeerID, duration time.Duration) error
IsInterfaceNil() bool
}
// ConnectionMonitorWrapper uses a connection monitor but checks if the peer is blacklisted or not
// TODO this should be removed after merging of the PeerShardResolver and BlacklistHandler
type ConnectionMonitorWrapper interface {
CheckConnectionsBlocking()
SetPeerDenialEvaluator(handler PeerDenialEvaluator) error
PeerDenialEvaluator() PeerDenialEvaluator
IsInterfaceNil() bool
}
// Debugger represent a p2p debugger able to print p2p statistics (messages received/sent per topic)
type Debugger interface {
AddIncomingMessage(topic string, size uint64, isRejected bool)
AddOutgoingMessage(topic string, size uint64, isRejected bool)
Close() error
IsInterfaceNil() bool
}
// SyncTimer represent an entity able to tell the current time
type SyncTimer interface {
CurrentTime() time.Time
IsInterfaceNil() bool
}
// ConnectionsWatcher represent an entity able to watch new connections
type ConnectionsWatcher interface {
NewKnownConnection(pid core.PeerID, connection string)
Close() error
IsInterfaceNil() bool
}
// PeersRatingHandler represent an entity able to handle peers ratings
type PeersRatingHandler interface {
AddPeer(pid core.PeerID)
IncreaseRating(pid core.PeerID)
DecreaseRating(pid core.PeerID)
GetTopRatedPeersFromList(peers []core.PeerID, minNumOfPeersExpected int) []core.PeerID
IsInterfaceNil() bool
}