forked from hyperledger/fabric
-
Notifications
You must be signed in to change notification settings - Fork 0
/
discovery.go
212 lines (172 loc) · 6.52 KB
/
discovery.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
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package discovery
import (
"fmt"
protolib "github.com/golang/protobuf/proto"
proto "github.com/hyperledger/fabric-protos-go/gossip"
"github.com/hyperledger/fabric/gossip/common"
"github.com/hyperledger/fabric/gossip/protoext"
)
// CryptoService is an interface that the discovery expects to be implemented and passed on creation
type CryptoService interface {
// ValidateAliveMsg validates that an Alive message is authentic
ValidateAliveMsg(message *protoext.SignedGossipMessage) bool
// SignMessage signs a message
SignMessage(m *proto.GossipMessage, internalEndpoint string) *proto.Envelope
}
// EnvelopeFilter may or may not remove part of the Envelope
// that the given SignedGossipMessage originates from.
type EnvelopeFilter func(message *protoext.SignedGossipMessage) *proto.Envelope
// Sieve defines the messages that are allowed to be sent to some remote peer,
// based on some criteria.
// Returns whether the sieve permits sending a given message.
type Sieve func(message *protoext.SignedGossipMessage) bool
// DisclosurePolicy defines which messages a given remote peer
// is eligible of knowing about, and also what is it eligible
// to know about out of a given SignedGossipMessage.
// Returns:
// 1) A Sieve for a given remote peer.
// The Sieve is applied for each peer in question and outputs
// whether the message should be disclosed to the remote peer.
// 2) A EnvelopeFilter for a given SignedGossipMessage, which may remove
// part of the Envelope the SignedGossipMessage originates from
type DisclosurePolicy func(remotePeer *NetworkMember) (Sieve, EnvelopeFilter)
// CommService is an interface that the discovery expects to be implemented and passed on creation
type CommService interface {
// Gossip gossips a message
Gossip(msg *protoext.SignedGossipMessage)
// SendToPeer sends to a given peer a message.
// The nonce can be anything since the communication module handles the nonce itself
SendToPeer(peer *NetworkMember, msg *protoext.SignedGossipMessage)
// Ping probes a remote peer and returns if it's responsive or not
Ping(peer *NetworkMember) bool
// Accept returns a read-only channel for membership messages sent from remote peers
Accept() <-chan protoext.ReceivedMessage
// PresumedDead returns a read-only channel for peers that are presumed to be dead
PresumedDead() <-chan common.PKIidType
// CloseConn orders to close the connection with a certain peer
CloseConn(peer *NetworkMember)
// Forward sends message to the next hop, excluding the hop
// from which message was initially received
Forward(msg protoext.ReceivedMessage)
// IdentitySwitch returns a read-only channel about identity change events
IdentitySwitch() <-chan common.PKIidType
}
// NetworkMember is a peer's representation
type NetworkMember struct {
Endpoint string
Metadata []byte
PKIid common.PKIidType
InternalEndpoint string
Properties *proto.Properties
*proto.Envelope
}
// Clone clones the NetworkMember
func (n NetworkMember) Clone() NetworkMember {
pkiIDClone := make(common.PKIidType, len(n.PKIid))
copy(pkiIDClone, n.PKIid)
nmClone := NetworkMember{
Endpoint: n.Endpoint,
Metadata: n.Metadata,
InternalEndpoint: n.InternalEndpoint,
PKIid: pkiIDClone,
}
if n.Properties != nil {
nmClone.Properties = protolib.Clone(n.Properties).(*proto.Properties)
}
if n.Envelope != nil {
nmClone.Envelope = protolib.Clone(n.Envelope).(*proto.Envelope)
}
return nmClone
}
// String returns a string representation of the NetworkMember
func (n NetworkMember) String() string {
return fmt.Sprintf("Endpoint: %s, InternalEndpoint: %s, PKI-ID: %s, Metadata: %x", n.Endpoint, n.InternalEndpoint, n.PKIid, n.Metadata)
}
// PreferredEndpoint computes the endpoint to connect to,
// while preferring internal endpoint over the standard
// endpoint
func (n NetworkMember) PreferredEndpoint() string {
if n.InternalEndpoint != "" {
return n.InternalEndpoint
}
return n.Endpoint
}
// PeerIdentification encompasses a remote peer's
// PKI-ID and whether its in the same org as the current
// peer or not
type PeerIdentification struct {
ID common.PKIidType
SelfOrg bool
}
type identifier func() (*PeerIdentification, error)
// Discovery is the interface that represents a discovery module
type Discovery interface {
// Lookup returns a network member, or nil if not found
Lookup(PKIID common.PKIidType) *NetworkMember
// Self returns this instance's membership information
Self() NetworkMember
// UpdateMetadata updates this instance's metadata
UpdateMetadata([]byte)
// UpdateEndpoint updates this instance's endpoint
UpdateEndpoint(string)
// Stops this instance
Stop()
// GetMembership returns the alive members in the view
GetMembership() []NetworkMember
// InitiateSync makes the instance ask a given number of peers
// for their membership information
InitiateSync(peerNum int)
// Connect makes this instance to connect to a remote instance
// The identifier param is a function that can be used to identify
// the peer, and to assert its PKI-ID, whether its in the peer's org or not,
// and whether the action was successful or not
Connect(member NetworkMember, id identifier)
}
// Members represents an aggregation of NetworkMembers
type Members []NetworkMember
// ByID returns a mapping from the PKI-IDs (in string form)
// to NetworkMember
func (members Members) ByID() map[string]NetworkMember {
res := make(map[string]NetworkMember, len(members))
for _, peer := range members {
res[string(peer.PKIid)] = peer
}
return res
}
// Intersect returns the intersection of 2 Members
func (members Members) Intersect(otherMembers Members) Members {
var res Members
m := otherMembers.ByID()
for _, member := range members {
if _, exists := m[string(member.PKIid)]; exists {
res = append(res, member)
}
}
return res
}
// Filter returns only members that satisfy the given filter
func (members Members) Filter(filter func(member NetworkMember) bool) Members {
var res Members
for _, member := range members {
if filter(member) {
res = append(res, member)
}
}
return res
}
// Map invokes the given function to every NetworkMember among the Members
func (members Members) Map(f func(member NetworkMember) NetworkMember) Members {
var res Members
for _, m := range members {
res = append(res, f(m))
}
return res
}
// HaveExternalEndpoints selects network members that have external endpoints
func HasExternalEndpoint(member NetworkMember) bool {
return member.Endpoint != ""
}