Skip to content

Commit a429da3

Browse files
FAB-1286 Support for leadership message - push
Naive implementation - leadership messages sent to all peers in membership. Change-Id: Ifab3a75ab0601ab7afbe8883283bc86760760cf2 Signed-off-by: Gennady Laventman <gennady@il.ibm.com>
1 parent e0411a6 commit a429da3

File tree

4 files changed

+182
-2
lines changed

4 files changed

+182
-2
lines changed

gossip/gossip/channel/channel.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ type gossipChannel struct {
119119
joinMsg api.JoinChannelMessage
120120
blockMsgStore msgstore.MessageStore
121121
stateInfoMsgStore msgstore.MessageStore
122+
leaderMsgStore msgstore.MessageStore
122123
chainID common.ChainID
123124
blocksPuller pull.Mediator
124125
logger *util.Logger
@@ -166,6 +167,7 @@ func NewGossipChannel(mcs api.MessageCryptoService, chainID common.ChainID, adap
166167

167168
gc.stateInfoMsgStore = NewStateInfoMessageStore()
168169
gc.blocksPuller = gc.createBlockPuller()
170+
gc.leaderMsgStore = msgstore.NewMessageStore(proto.NewGossipMessageComparator(0), func(m interface{}) {})
169171

170172
gc.ConfigureChannel(joinMsg)
171173

@@ -419,6 +421,15 @@ func (gc *gossipChannel) HandleMessage(msg comm.ReceivedMessage) {
419421
}
420422
gc.blocksPuller.HandleMessage(msg)
421423
}
424+
425+
if m.IsLeadershipMsg() {
426+
// Handling leadership message
427+
added := gc.leaderMsgStore.Add(m)
428+
if added {
429+
gc.DeMultiplex(m)
430+
}
431+
432+
}
422433
}
423434

424435
func (gc *gossipChannel) handleStateInfSnapshot(m *proto.GossipMessage, sender common.PKIidType) {

gossip/gossip/gossip_impl.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ func (g *gossipServiceImpl) gossipBatch(msgs []*proto.GossipMessage) {
391391
var blocks []*proto.GossipMessage
392392
var stateInfoMsgs []*proto.GossipMessage
393393
var orgMsgs []*proto.GossipMessage
394+
var leadershipMsgs []*proto.GossipMessage
394395

395396
isABlock := func(o interface{}) bool {
396397
return o.(*proto.GossipMessage).IsDataMsg()
@@ -401,6 +402,9 @@ func (g *gossipServiceImpl) gossipBatch(msgs []*proto.GossipMessage) {
401402
isOrgRestricted := func(o interface{}) bool {
402403
return o.(*proto.GossipMessage).IsOrgRestricted()
403404
}
405+
isLeadershipMsg := func(o interface{}) bool {
406+
return o.(*proto.GossipMessage).IsLeadershipMsg()
407+
}
404408

405409
// Gossip blocks
406410
blocks, msgs = partitionMessages(isABlock, msgs)
@@ -414,6 +418,12 @@ func (g *gossipServiceImpl) gossipBatch(msgs []*proto.GossipMessage) {
414418
return gc.IsMemberInChan
415419
})
416420

421+
//Gossip Leadership messages
422+
leadershipMsgs, msgs = partitionMessages(isLeadershipMsg, msgs)
423+
g.gossipInChan(leadershipMsgs, func(gc channel.GossipChannel) filter.RoutingFilter {
424+
return filter.CombineRoutingFilters(gc.IsSubscribed, gc.IsMemberInChan, g.isInMyorg)
425+
})
426+
417427
// Gossip messages restricted to our org
418428
orgMsgs, msgs = partitionMessages(isOrgRestricted, msgs)
419429
peers2Send := filter.SelectPeers(g.conf.PropagatePeerNum, g.disc.GetMembership(), g.isInMyorg)
@@ -451,10 +461,17 @@ func (g *gossipServiceImpl) gossipInChan(messages []*proto.GossipMessage, chanRo
451461
continue
452462
}
453463
// Select the peers to send the messages to
454-
peers2Send := filter.SelectPeers(g.conf.PropagatePeerNum, g.disc.GetMembership(), chanRoutingFactory(gc))
464+
// For leadership messages we will select all peers that pass routing factory - e.g. all peers in channel and org
465+
membership := g.disc.GetMembership()
466+
allPeersInCh := filter.SelectPeers(len(membership), membership, chanRoutingFactory(gc))
467+
peers2Send := filter.SelectPeers(g.conf.PropagatePeerNum, membership, chanRoutingFactory(gc))
455468
// Send the messages to the remote peers
456469
for _, msg := range messagesOfChannel {
457-
g.comm.Send(msg, peers2Send...)
470+
if msg.IsLeadershipMsg() {
471+
g.comm.Send(msg, allPeersInCh...)
472+
} else {
473+
g.comm.Send(msg, peers2Send...)
474+
}
458475
}
459476
}
460477
}

gossip/gossip/gossip_test.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ func acceptData(m interface{}) bool {
6262
return false
6363
}
6464

65+
func acceptLeadershp(message interface{}) bool {
66+
validMsg := message.(*proto.GossipMessage).Tag == proto.GossipMessage_CHAN_AND_ORG &&
67+
message.(*proto.GossipMessage).IsLeadershipMsg()
68+
69+
return validMsg
70+
}
71+
6572
type joinChanMsg struct {
6673
anchorPeers []api.AnchorPeer
6774
}
@@ -489,6 +496,34 @@ func TestDissemination(t *testing.T) {
489496
for i := 0; i < n; i++ {
490497
assert.Equal(t, msgsCount2Send, receivedMessages[i])
491498
}
499+
500+
//Sending leadership messages
501+
receivedLeadershipMessages := make([]int, n)
502+
wgLeadership := sync.WaitGroup{}
503+
wgLeadership.Add(n)
504+
for i := 1; i <= n; i++ {
505+
leadershipChan, _ := peers[i-1].Accept(acceptLeadershp, false)
506+
go func(index int, ch <-chan *proto.GossipMessage) {
507+
defer wgLeadership.Done()
508+
<-ch
509+
receivedLeadershipMessages[index]++
510+
}(i-1, leadershipChan)
511+
}
512+
513+
seqNum := 0
514+
incTime := uint64(time.Now().UnixNano())
515+
t3 := time.Now()
516+
517+
leadershipMsg := createLeadershipMsg(true, common.ChainID("A"), incTime, uint64(seqNum), boot.(*gossipServiceImpl).conf.SelfEndpoint, boot.(*gossipServiceImpl).comm.GetPKIid())
518+
boot.Gossip(leadershipMsg)
519+
520+
waitUntilOrFailBlocking(t, wgLeadership.Wait)
521+
t.Log("Leadership message dissemination took", time.Since(t3))
522+
523+
for i := 0; i < n; i++ {
524+
assert.Equal(t, 1, receivedLeadershipMessages[i])
525+
}
526+
492527
t.Log("Stopping peers")
493528

494529
stop := func() {
@@ -784,6 +819,78 @@ func TestEndedGoroutines(t *testing.T) {
784819
ensureGoroutineExit(t)
785820
}
786821

822+
//func TestLeadershipMsgDissemination(t *testing.T) {
823+
// t.Parallel()
824+
// portPrefix := 3610
825+
// t1 := time.Now()
826+
// // Scenario: 20 nodes and a bootstrap node.
827+
// // The bootstrap node sends 10 leadership messages and we count
828+
// // that each node got 10 messages after a few seconds
829+
//
830+
// stopped := int32(0)
831+
// go waitForTestCompletion(&stopped, t)
832+
//
833+
// n := 10
834+
// msgsCount2Send := 10
835+
// boot := newGossipInstance(portPrefix, 0, 100)
836+
// boot.JoinChan(&joinChanMsg{}, common.ChainID("A"))
837+
// boot.UpdateChannelMetadata([]byte{}, common.ChainID("A"))
838+
//
839+
// peers := make([]Gossip, n)
840+
// receivedMessages := make([]int, n)
841+
// wg := sync.WaitGroup{}
842+
// wg.Add(n)
843+
// for i := 1; i <= n; i++ {
844+
// pI := newGossipInstance(portPrefix, i, 100, 0)
845+
// peers[i-1] = pI
846+
// pI.JoinChan(&joinChanMsg{}, common.ChainID("A"))
847+
// pI.UpdateChannelMetadata([]byte{}, common.ChainID("A"))
848+
// acceptChan, _ := pI.Accept(acceptLeadershp, false)
849+
// go func(index int, ch <-chan *proto.GossipMessage) {
850+
// defer wg.Done()
851+
// for j := 0; j < msgsCount2Send; j++ {
852+
// <-ch
853+
// receivedMessages[index]++
854+
// }
855+
// }(i-1, acceptChan)
856+
// }
857+
//
858+
// membershipTime := time.Now()
859+
// waitUntilOrFail(t, checkPeersMembership(peers, n))
860+
// t.Log("Membership establishment took", time.Since(membershipTime))
861+
//
862+
// seqNum := 0
863+
// incTime := uint64(time.Now().UnixNano())
864+
//
865+
// for i := 1; i <= msgsCount2Send; i++ {
866+
// seqNum++
867+
// leadershipMsg := createLeadershipMsg(true, common.ChainID("A"), incTime, uint64(seqNum), boot.(*gossipServiceImpl).conf.SelfEndpoint, boot.(*gossipServiceImpl).comm.GetPKIid())
868+
// boot.Gossip(leadershipMsg)
869+
// time.Sleep(time.Duration(500) * time.Millisecond)
870+
// }
871+
//
872+
// t2 := time.Now()
873+
// waitUntilOrFailBlocking(t, wg.Wait)
874+
// t.Log("Leadership message dissemination took", time.Since(t2))
875+
//
876+
// for i := 0; i < n; i++ {
877+
// assert.Equal(t, msgsCount2Send, receivedMessages[i])
878+
// }
879+
// t.Log("Stopping peers")
880+
//
881+
// stop := func() {
882+
// stopPeers(append(peers, boot))
883+
// }
884+
//
885+
// stopTime := time.Now()
886+
// waitUntilOrFailBlocking(t, stop)
887+
// t.Log("Stop took", time.Since(stopTime))
888+
// t.Log("Took", time.Since(t1))
889+
// atomic.StoreInt32(&stopped, int32(1))
890+
// fmt.Println("<<<TestLeadershipMsgDissemination>>>")
891+
// testWG.Done()
892+
//}
893+
787894
func createDataMsg(seqnum uint64, data []byte, hash string, channel common.ChainID) *proto.GossipMessage {
788895
return &proto.GossipMessage{
789896
Channel: []byte(channel),
@@ -801,6 +908,32 @@ func createDataMsg(seqnum uint64, data []byte, hash string, channel common.Chain
801908
}
802909
}
803910

911+
func createLeadershipMsg(isDeclaration bool, channel common.ChainID, incTime uint64, seqNum uint64, endpoint string, pkiid []byte) *proto.GossipMessage {
912+
913+
metadata := []byte{}
914+
metadata = strconv.AppendBool(metadata, isDeclaration)
915+
916+
leadershipMsg := &proto.LeadershipMessage{
917+
Membership: &proto.Member{
918+
PkiID: pkiid,
919+
Endpoint: endpoint,
920+
Metadata: metadata,
921+
},
922+
Timestamp: &proto.PeerTime{
923+
IncNumber: incTime,
924+
SeqNum: seqNum,
925+
},
926+
}
927+
928+
msg := &proto.GossipMessage{
929+
Nonce: 0,
930+
Tag: proto.GossipMessage_CHAN_AND_ORG,
931+
Content: &proto.GossipMessage_LeadershipMsg{LeadershipMsg: leadershipMsg},
932+
Channel: channel,
933+
}
934+
return msg
935+
}
936+
804937
type goroutinePredicate func(g goroutine) bool
805938

806939
var connectionLeak = func(g goroutine) bool {

gossip/proto/extensions.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ func (mc *msgComparator) invalidationPolicy(this interface{}, that interface{})
6161
return mc.identityInvalidationPolicy(thisMsg.GetPeerIdentity(), thatMsg.GetPeerIdentity())
6262
}
6363

64+
if thisMsg.IsLeadershipMsg() && thatMsg.IsLeadershipMsg() {
65+
return leaderInvalidationPolicy(thisMsg.GetLeadershipMsg(), thatMsg.GetLeadershipMsg())
66+
}
67+
6468
return common.MessageNoAction
6569
}
6670

@@ -106,6 +110,14 @@ func aliveInvalidationPolicy(thisMsg *AliveMessage, thatMsg *AliveMessage) commo
106110
return compareTimestamps(thisMsg.Timestamp, thatMsg.Timestamp)
107111
}
108112

113+
func leaderInvalidationPolicy(thisMsg *LeadershipMessage, thatMsg *LeadershipMessage) common.InvalidationResult {
114+
if !bytes.Equal(thisMsg.Membership.PkiID, thatMsg.Membership.PkiID) {
115+
return common.MessageNoAction
116+
}
117+
118+
return compareTimestamps(thisMsg.Timestamp, thatMsg.Timestamp)
119+
}
120+
109121
func compareTimestamps(thisTS *PeerTime, thatTS *PeerTime) common.InvalidationResult {
110122
if thisTS.IncNumber == thatTS.IncNumber {
111123
if thisTS.SeqNum > thatTS.SeqNum {
@@ -279,6 +291,13 @@ func (m *GossipMessage) IsTagLegal() error {
279291
return nil
280292
}
281293

294+
if m.IsLeadershipMsg() {
295+
if m.Tag != GossipMessage_CHAN_AND_ORG {
296+
return fmt.Errorf("Tag should be %s", GossipMessage_Tag_name[int32(GossipMessage_CHAN_AND_ORG)])
297+
}
298+
return nil
299+
}
300+
282301
return fmt.Errorf("Unknown message type: %v", m)
283302
}
284303

0 commit comments

Comments
 (0)