Skip to content

Commit f1a88db

Browse files
committed
[FAB-2758] Decouple anchor peers endpoints from orgIDs
In the current implementation of the join channel message in the gossip layer, each anchor peer has its own organization, and the joinChannel invocation enumerates all anchor peers and builds a list of organizationIDs from them. When https://gerrit.hyperledger.org/r/#/c/7105/ will be introduced, it will be needed to create a channel only with either no anchor peers or anchor peers of the organization of the channel creator. This would confuse the gossip layer because it'll derive that each channel has only 1 organization instead of the original participants. I decoupled the anchor peers from the organization IDs by changing the JoinChannelMessage interface in api/channel.go to have Members() []OrgIdentityType which would return the channel members (organizations) and AnchorPeersOf(org OrgIdentityType) []AnchorPeer which would return for each organization, its corresponding anchor peers. Also (of course) updated the tests accordingly. Change-Id: I90131a0726fc7ca68fd750247f4df558c5cca0fd Signed-off-by: Yacov Manevich <[email protected]>
1 parent 844fe2d commit f1a88db

10 files changed

+125
-99
lines changed

gossip/api/channel.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,17 @@ type JoinChannelMessage interface {
4646
// the JoinChannelMessage originated from
4747
SequenceNumber() uint64
4848

49-
// AnchorPeers returns all the anchor peers that are in the channel
50-
AnchorPeers() []AnchorPeer
49+
// Members returns the organizations of the channel
50+
Members() []OrgIdentityType
51+
52+
// AnchorPeersOf returns the anchor peers of the given organization
53+
AnchorPeersOf(org OrgIdentityType) []AnchorPeer
5154
}
5255

5356
// AnchorPeer is an anchor peer's certificate and endpoint (host:port)
5457
type AnchorPeer struct {
55-
Host string // Host is the hostname/ip address of the remote peer
56-
Port int // Port is the port the remote peer is listening on
57-
OrgID OrgIdentityType // OrgID is the identity of the organization the anchor peer came from
58-
58+
Host string // Host is the hostname/ip address of the remote peer
59+
Port int // Port is the port the remote peer is listening on
5960
}
6061

6162
// OrgIdentityType defines the identity of an organization

gossip/gossip/channel/channel.go

+6-20
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ type Config struct {
4444
PullPeerNum int
4545
PullInterval time.Duration
4646
RequestStateInfoInterval time.Duration
47-
Identity api.PeerIdentityType
4847
}
4948

5049
// GossipChannel defines an object that deals with all channel-related messages
@@ -103,9 +102,6 @@ type Adapter interface {
103102
// hasn't been signed correctly, nil otherwise.
104103
ValidateStateInfoMessage(message *proto.SignedGossipMessage) error
105104

106-
// OrgByPeerIdentity returns the organization ID of a given peer identity
107-
OrgByPeerIdentity(identity api.PeerIdentityType) api.OrgIdentityType
108-
109105
// GetOrgOfPeer returns the organization ID of a given peer PKI-ID
110106
GetOrgOfPeer(pkiID common.PKIidType) api.OrgIdentityType
111107

@@ -328,6 +324,11 @@ func (gc *gossipChannel) ConfigureChannel(joinMsg api.JoinChannelMessage) {
328324
gc.Lock()
329325
defer gc.Unlock()
330326

327+
if len(joinMsg.Members()) == 0 {
328+
gc.logger.Warning("Received join channel message with empty set of members")
329+
return
330+
}
331+
331332
if gc.joinMsg == nil {
332333
gc.joinMsg = joinMsg
333334
}
@@ -337,22 +338,7 @@ func (gc *gossipChannel) ConfigureChannel(joinMsg api.JoinChannelMessage) {
337338
return
338339
}
339340

340-
var orgs []api.OrgIdentityType
341-
existingOrgInJoinChanMsg := make(map[string]struct{})
342-
// We are in the channel if the joinMsg contains an empty set of anchor peers
343-
selfOrg := gc.OrgByPeerIdentity(gc.GetConf().Identity)
344-
if len(joinMsg.AnchorPeers()) == 0 {
345-
orgs = []api.OrgIdentityType{selfOrg}
346-
}
347-
for _, anchorPeer := range joinMsg.AnchorPeers() {
348-
orgID := anchorPeer.OrgID
349-
if _, exists := existingOrgInJoinChanMsg[string(orgID)]; !exists {
350-
orgs = append(orgs, orgID)
351-
existingOrgInJoinChanMsg[string(orgID)] = struct{}{}
352-
}
353-
}
354-
355-
gc.orgs = orgs
341+
gc.orgs = joinMsg.Members()
356342
gc.joinMsg = joinMsg
357343
}
358344

gossip/gossip/channel/channel_test.go

+32-26
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ var conf = Config{
4444
PullPeerNum: 3,
4545
PullInterval: time.Second,
4646
RequestStateInfoInterval: time.Millisecond * 100,
47-
Identity: api.PeerIdentityType("pkiIDInOrg1"),
4847
}
4948

5049
func init() {
@@ -66,8 +65,8 @@ var (
6665
)
6766

6867
type joinChanMsg struct {
69-
getTS func() time.Time
70-
anchorPeers func() []api.AnchorPeer
68+
getTS func() time.Time
69+
members2AnchorPeers map[string][]api.AnchorPeer
7170
}
7271

7372
// SequenceNumber returns the sequence number of the block
@@ -80,12 +79,26 @@ func (jcm *joinChanMsg) SequenceNumber() uint64 {
8079
return uint64(time.Now().UnixNano())
8180
}
8281

83-
// AnchorPeers returns all the anchor peers that are in the channel
84-
func (jcm *joinChanMsg) AnchorPeers() []api.AnchorPeer {
85-
if jcm.anchorPeers != nil {
86-
return jcm.anchorPeers()
82+
// Members returns the organizations of the channel
83+
func (jcm *joinChanMsg) Members() []api.OrgIdentityType {
84+
if jcm.members2AnchorPeers == nil {
85+
return []api.OrgIdentityType{orgInChannelA}
8786
}
88-
return []api.AnchorPeer{{OrgID: orgInChannelA}}
87+
members := make([]api.OrgIdentityType, len(jcm.members2AnchorPeers))
88+
i := 0
89+
for org := range jcm.members2AnchorPeers {
90+
members[i] = api.OrgIdentityType(org)
91+
i++
92+
}
93+
return members
94+
}
95+
96+
// AnchorPeersOf returns the anchor peers of the given organization
97+
func (jcm *joinChanMsg) AnchorPeersOf(org api.OrgIdentityType) []api.AnchorPeer {
98+
if jcm.members2AnchorPeers == nil {
99+
return []api.AnchorPeer{}
100+
}
101+
return jcm.members2AnchorPeers[string(org)]
89102
}
90103

91104
type cryptoService struct {
@@ -197,10 +210,6 @@ func (ga *gossipAdapterMock) ValidateStateInfoMessage(msg *proto.SignedGossipMes
197210
return args.Get(0).(error)
198211
}
199212

200-
func (ga *gossipAdapterMock) OrgByPeerIdentity(identity api.PeerIdentityType) api.OrgIdentityType {
201-
return ga.GetOrgOfPeer(common.PKIidType(identity))
202-
}
203-
204213
func (ga *gossipAdapterMock) GetOrgOfPeer(PKIIID common.PKIidType) api.OrgIdentityType {
205214
args := ga.Called(PKIIID)
206215
return args.Get(0).(api.OrgIdentityType)
@@ -743,30 +752,30 @@ func TestChannelReconfigureChannel(t *testing.T) {
743752
adapter.On("GetOrgOfPeer", pkiIDinOrg2).Return(orgNotInChannelA)
744753

745754
outdatedJoinChanMsg := &joinChanMsg{
746-
anchorPeers: func() []api.AnchorPeer {
747-
return []api.AnchorPeer{{OrgID: orgNotInChannelA}}
748-
},
749755
getTS: func() time.Time {
750756
return time.Now()
751757
},
758+
members2AnchorPeers: map[string][]api.AnchorPeer{
759+
string(orgNotInChannelA): {},
760+
},
752761
}
753762

754763
newJoinChanMsg := &joinChanMsg{
755-
anchorPeers: func() []api.AnchorPeer {
756-
return []api.AnchorPeer{{OrgID: orgInChannelA}}
757-
},
758764
getTS: func() time.Time {
759765
return time.Now().Add(time.Millisecond * 100)
760766
},
767+
members2AnchorPeers: map[string][]api.AnchorPeer{
768+
string(orgInChannelA): {},
769+
},
761770
}
762771

763772
updatedJoinChanMsg := &joinChanMsg{
764-
anchorPeers: func() []api.AnchorPeer {
765-
return []api.AnchorPeer{{OrgID: orgNotInChannelA}}
766-
},
767773
getTS: func() time.Time {
768774
return time.Now().Add(time.Millisecond * 200)
769775
},
776+
members2AnchorPeers: map[string][]api.AnchorPeer{
777+
string(orgNotInChannelA): {},
778+
},
770779
}
771780

772781
gc := NewGossipChannel(cs, channelA, adapter, api.JoinChannelMessage(newJoinChanMsg))
@@ -832,11 +841,8 @@ func TestChannelNoAnchorPeers(t *testing.T) {
832841
adapter.On("GetOrgOfPeer", pkiIDinOrg2).Return(orgNotInChannelA)
833842

834843
jcm := &joinChanMsg{
835-
anchorPeers: func() []api.AnchorPeer {
836-
return []api.AnchorPeer{}
837-
},
838-
getTS: func() time.Time {
839-
return time.Now().Add(time.Millisecond * 100)
844+
members2AnchorPeers: map[string][]api.AnchorPeer{
845+
string(orgInChannelA): {},
840846
},
841847
}
842848

gossip/gossip/chanstate.go

-6
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ func (ga *gossipAdapterImpl) GetConf() channel.Config {
8686
PullInterval: ga.conf.PullInterval,
8787
PullPeerNum: ga.conf.PullPeerNum,
8888
RequestStateInfoInterval: ga.conf.RequestStateInfoInterval,
89-
Identity: ga.selfIdentity,
9089
}
9190
}
9291

@@ -105,11 +104,6 @@ func (ga *gossipAdapterImpl) ValidateStateInfoMessage(msg *proto.SignedGossipMes
105104
return ga.gossipServiceImpl.validateStateInfoMsg(msg)
106105
}
107106

108-
// OrgByPeerIdentity extracts the organization identifier from a peer's identity
109-
func (ga *gossipAdapterImpl) OrgByPeerIdentity(identity api.PeerIdentityType) api.OrgIdentityType {
110-
return ga.gossipServiceImpl.secAdvisor.OrgByPeerIdentity(identity)
111-
}
112-
113107
// GetOrgOfPeer returns the organization identifier of a certain peer
114108
func (ga *gossipAdapterImpl) GetOrgOfPeer(PKIID common.PKIidType) api.OrgIdentityType {
115109
return ga.gossipServiceImpl.getOrgOfPeer(PKIID)

gossip/gossip/gossip_impl.go

+12-7
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,13 @@ func (g *gossipServiceImpl) JoinChan(joinMsg api.JoinChannelMessage, chainID com
175175
// joinMsg is supposed to have been already verified
176176
g.chanState.joinChannel(joinMsg, chainID)
177177

178-
for _, ap := range joinMsg.AnchorPeers() {
178+
for _, org := range joinMsg.Members() {
179+
g.learnAnchorPeers(org, joinMsg.AnchorPeersOf(org))
180+
}
181+
}
182+
183+
func (g *gossipServiceImpl) learnAnchorPeers(orgOfAnchorPeers api.OrgIdentityType, anchorPeers []api.AnchorPeer) {
184+
for _, ap := range anchorPeers {
179185
if ap.Host == "" {
180186
g.logger.Warning("Got empty hostname, skipping connecting to anchor peer", ap)
181187
continue
@@ -191,20 +197,19 @@ func (g *gossipServiceImpl) JoinChan(joinMsg api.JoinChannelMessage, chainID com
191197
continue
192198
}
193199

194-
inOurOrg := bytes.Equal(g.selfOrg, ap.OrgID)
200+
inOurOrg := bytes.Equal(g.selfOrg, orgOfAnchorPeers)
195201
if !inOurOrg && g.selfNetworkMember().Endpoint == "" {
196-
g.logger.Infof("Anchor peer %s:%d isn't in our org(%v) and we have no external endpoint, skipping", ap.Host, ap.Port, string(ap.OrgID))
202+
g.logger.Infof("Anchor peer %s:%d isn't in our org(%v) and we have no external endpoint, skipping", ap.Host, ap.Port, string(orgOfAnchorPeers))
197203
continue
198204
}
199-
anchorPeerOrg := ap.OrgID
200205
isInOurOrg := func() bool {
201-
identity, err := g.comm.Handshake(&comm.RemotePeer{Endpoint: endpoint})
206+
remotePeerIdentity, err := g.comm.Handshake(&comm.RemotePeer{Endpoint: endpoint})
202207
if err != nil {
203208
g.logger.Warning("Deep probe of", endpoint, "failed:", err)
204209
return false
205210
}
206-
isAnchorPeerInMyOrg := bytes.Equal(g.selfOrg, g.secAdvisor.OrgByPeerIdentity(identity))
207-
if bytes.Equal(anchorPeerOrg, g.selfOrg) && !isAnchorPeerInMyOrg {
211+
isAnchorPeerInMyOrg := bytes.Equal(g.selfOrg, g.secAdvisor.OrgByPeerIdentity(remotePeerIdentity))
212+
if bytes.Equal(orgOfAnchorPeers, g.selfOrg) && !isAnchorPeerInMyOrg {
208213
g.logger.Warning("Anchor peer", endpoint, "isn't in our org, but is claimed to be")
209214
}
210215
return isAnchorPeerInMyOrg

gossip/gossip/gossip_test.go

+24-11
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func acceptLeadershp(message interface{}) bool {
7272
}
7373

7474
type joinChanMsg struct {
75-
anchorPeers []api.AnchorPeer
75+
members2AnchorPeers map[string][]api.AnchorPeer
7676
}
7777

7878
// SequenceNumber returns the sequence number of the block this joinChanMsg
@@ -81,12 +81,26 @@ func (*joinChanMsg) SequenceNumber() uint64 {
8181
return uint64(time.Now().UnixNano())
8282
}
8383

84-
// AnchorPeers returns all the anchor peers that are in the channel
85-
func (jcm *joinChanMsg) AnchorPeers() []api.AnchorPeer {
86-
if len(jcm.anchorPeers) == 0 {
87-
return []api.AnchorPeer{{OrgID: orgInChannelA}}
84+
// Members returns the organizations of the channel
85+
func (jcm *joinChanMsg) Members() []api.OrgIdentityType {
86+
if jcm.members2AnchorPeers == nil {
87+
return []api.OrgIdentityType{orgInChannelA}
8888
}
89-
return jcm.anchorPeers
89+
members := make([]api.OrgIdentityType, len(jcm.members2AnchorPeers))
90+
i := 0
91+
for org := range jcm.members2AnchorPeers {
92+
members[i] = api.OrgIdentityType(org)
93+
i++
94+
}
95+
return members
96+
}
97+
98+
// AnchorPeersOf returns the anchor peers of the given organization
99+
func (jcm *joinChanMsg) AnchorPeersOf(org api.OrgIdentityType) []api.AnchorPeer {
100+
if jcm.members2AnchorPeers == nil {
101+
return []api.AnchorPeer{}
102+
}
103+
return jcm.members2AnchorPeers[string(org)]
90104
}
91105

92106
type naiveCryptoService struct {
@@ -335,14 +349,13 @@ func TestConnectToAnchorPeers(t *testing.T) {
335349
n := 10
336350
anchorPeercount := 3
337351

338-
jcm := &joinChanMsg{anchorPeers: []api.AnchorPeer{}}
352+
jcm := &joinChanMsg{members2AnchorPeers: map[string][]api.AnchorPeer{string(orgInChannelA): {}}}
339353
for i := 0; i < anchorPeercount; i++ {
340354
ap := api.AnchorPeer{
341-
Port: portPrefix + i,
342-
Host: "localhost",
343-
OrgID: orgInChannelA,
355+
Port: portPrefix + i,
356+
Host: "localhost",
344357
}
345-
jcm.anchorPeers = append(jcm.anchorPeers, ap)
358+
jcm.members2AnchorPeers[string(orgInChannelA)] = append(jcm.members2AnchorPeers[string(orgInChannelA)], ap)
346359
}
347360

348361
peers := make([]Gossip, n)

gossip/gossip/orgs_test.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,14 @@ func TestMultipleOrgEndpointLeakage(t *testing.T) {
192192
}
193193

194194
jcm := &joinChanMsg{
195-
anchorPeers: []api.AnchorPeer{
196-
{Host: "localhost", Port: 11611, OrgID: api.OrgIdentityType(orgA)},
197-
{Host: "localhost", Port: 11615, OrgID: api.OrgIdentityType(orgB)},
198-
{Host: "localhost", Port: 11616, OrgID: api.OrgIdentityType(orgA)},
195+
members2AnchorPeers: map[string][]api.AnchorPeer{
196+
orgA: {
197+
{Host: "localhost", Port: 11611},
198+
{Host: "localhost", Port: 11616},
199+
},
200+
orgB: {
201+
{Host: "localhost", Port: 11615},
202+
},
199203
},
200204
}
201205

gossip/service/gossip_service.go

+20-9
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,28 @@ type gossipServiceImpl struct {
8787

8888
// This is an implementation of api.JoinChannelMessage.
8989
type joinChannelMessage struct {
90-
seqNum uint64
91-
anchorPeers []api.AnchorPeer
90+
seqNum uint64
91+
members2AnchorPeers map[string][]api.AnchorPeer
9292
}
9393

9494
func (jcm *joinChannelMessage) SequenceNumber() uint64 {
9595
return jcm.seqNum
9696
}
9797

98-
func (jcm *joinChannelMessage) AnchorPeers() []api.AnchorPeer {
99-
return jcm.anchorPeers
98+
// Members returns the organizations of the channel
99+
func (jcm *joinChannelMessage) Members() []api.OrgIdentityType {
100+
members := make([]api.OrgIdentityType, len(jcm.members2AnchorPeers))
101+
i := 0
102+
for org := range jcm.members2AnchorPeers {
103+
members[i] = api.OrgIdentityType(org)
104+
i++
105+
}
106+
return members
107+
}
108+
109+
// AnchorPeersOf returns the anchor peers of the given organization
110+
func (jcm *joinChannelMessage) AnchorPeersOf(org api.OrgIdentityType) []api.AnchorPeer {
111+
return jcm.members2AnchorPeers[string(org)]
100112
}
101113

102114
var logger = util.GetLogger(util.LoggingServiceModule, "")
@@ -209,15 +221,14 @@ func (g *gossipServiceImpl) configUpdated(config Config) {
209221
"among the orgs of the channel:", orgListFromConfig(config), ", aborting.")
210222
return
211223
}
212-
jcm := &joinChannelMessage{seqNum: config.Sequence(), anchorPeers: []api.AnchorPeer{}}
224+
jcm := &joinChannelMessage{seqNum: config.Sequence(), members2AnchorPeers: map[string][]api.AnchorPeer{}}
213225
for orgID, appOrg := range config.Organizations() {
214226
for _, ap := range appOrg.AnchorPeers() {
215227
anchorPeer := api.AnchorPeer{
216-
Host: ap.Host,
217-
Port: int(ap.Port),
218-
OrgID: api.OrgIdentityType(orgID),
228+
Host: ap.Host,
229+
Port: int(ap.Port),
219230
}
220-
jcm.anchorPeers = append(jcm.anchorPeers, anchorPeer)
231+
jcm.members2AnchorPeers[orgID] = append(jcm.members2AnchorPeers[orgID], anchorPeer)
221232
}
222233
}
223234

0 commit comments

Comments
 (0)