Skip to content

Commit b48cea6

Browse files
committed
[FAB-6043] migrate gossip stateInfo metadata to proto
This commit adds a Properties sub-message to the StateInfo message and makes sure the gossip logic can handle peers with and without this field set. Change-Id: Ibe164db1e4dc4c5a1d861e62eb61da01d31778e6 Signed-off-by: yacovm <yacovm@il.ibm.com>
1 parent 3a8d54c commit b48cea6

File tree

11 files changed

+309
-145
lines changed

11 files changed

+309
-145
lines changed

gossip/common/metastate.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ type NodeMetastate struct {
2121
LedgerHeight uint64
2222
}
2323

24-
// NewNodeMetastate creates new meta data with given ledger height148.69
24+
// NewNodeMetastate creates new meta data with given ledger height
2525
func NewNodeMetastate(height uint64) *NodeMetastate {
2626
return &NodeMetastate{height}
2727
}

gossip/discovery/discovery.go

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ type NetworkMember struct {
7070
Metadata []byte
7171
PKIid common.PKIidType
7272
InternalEndpoint string
73+
Properties *proto.Properties
7374
}
7475

7576
// String returns a string representation of the NetworkMember

gossip/gossip/channel/channel.go

+2-6
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ func (gc *gossipChannel) GetPeers() []discovery.NetworkMember {
282282
continue
283283
}
284284
member.Metadata = stateInf.GetStateInfo().Metadata
285+
member.Properties = stateInf.GetStateInfo().Properties
285286
members = append(members, member)
286287
}
287288
return members
@@ -751,13 +752,8 @@ func (gc *gossipChannel) UpdateStateInfo(msg *proto.SignedGossipMessage) {
751752
gc.Lock()
752753
defer gc.Unlock()
753754

754-
nodeMeta, err := common.FromBytes(msg.GetStateInfo().Metadata)
755-
if err != nil {
756-
gc.logger.Warningf("Can't extract ledger height from metadata %+v", errors.WithStack(err))
757-
return
758-
}
759755
gc.stateInfoMsgStore.Add(msg)
760-
gc.ledgerHeight = nodeMeta.LedgerHeight
756+
gc.ledgerHeight = msg.GetStateInfo().Properties.LedgerHeight
761757
gc.stateInfoMsg = msg
762758
atomic.StoreInt32(&gc.shouldGossipStateInfo, int32(1))
763759
}

gossip/gossip/channel/channel_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ func TestChannelPeriodicalPublishStateInfo(t *testing.T) {
412412
nodeMeta, err := common.FromBytes(msg.GetStateInfo().Metadata)
413413
assert.NoError(t, err, "ReceivedMetadata is invalid")
414414
assert.Equal(t, ledgerHeight, int(nodeMeta.LedgerHeight), "Received different ledger height than expected")
415+
assert.Equal(t, ledgerHeight, int(msg.GetStateInfo().Properties.LedgerHeight))
415416
}
416417

417418
func TestChannelMsgStoreEviction(t *testing.T) {
@@ -1751,6 +1752,9 @@ func createStateInfoMsg(ledgerHeight int, pkiID common.PKIidType, channel common
17511752
Timestamp: &proto.PeerTime{IncNum: uint64(time.Now().UnixNano()), SeqNum: 1},
17521753
Metadata: metaBytes,
17531754
PkiId: []byte(pkiID),
1755+
Properties: &proto.Properties{
1756+
LedgerHeight: uint64(ledgerHeight),
1757+
},
17541758
},
17551759
},
17561760
}).NoopSign()

gossip/gossip/gossip_impl.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,10 @@ func (g *gossipServiceImpl) connect2BootstrapPeers() {
10891089
}
10901090

10911091
func (g *gossipServiceImpl) createStateInfoMsg(metadata []byte, chainID common.ChainID) (*proto.SignedGossipMessage, error) {
1092+
metaState, err := common.FromBytes(metadata)
1093+
if err != nil {
1094+
return nil, err
1095+
}
10921096
pkiID := g.comm.GetPKIid()
10931097
stateInfMsg := &proto.StateInfo{
10941098
Channel_MAC: channel.GenerateMAC(pkiID, chainID),
@@ -1098,6 +1102,9 @@ func (g *gossipServiceImpl) createStateInfoMsg(metadata []byte, chainID common.C
10981102
IncNum: uint64(g.incTime.UnixNano()),
10991103
SeqNum: uint64(time.Now().UnixNano()),
11001104
},
1105+
Properties: &proto.Properties{
1106+
LedgerHeight: metaState.LedgerHeight,
1107+
},
11011108
}
11021109
m := &proto.GossipMessage{
11031110
Nonce: 0,
@@ -1112,7 +1119,7 @@ func (g *gossipServiceImpl) createStateInfoMsg(metadata []byte, chainID common.C
11121119
signer := func(msg []byte) ([]byte, error) {
11131120
return g.mcs.Sign(msg)
11141121
}
1115-
_, err := sMsg.Sign(signer)
1122+
_, err = sMsg.Sign(signer)
11161123
return sMsg, errors.WithStack(err)
11171124
}
11181125

gossip/gossip/gossip_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,10 @@ func TestDataLeakage(t *testing.T) {
897897
assert.Len(t, peers[instanceIndex].PeersOfChannel(channel), 2)
898898
if i == 0 {
899899
assert.Equal(t, channelAmetadata, peers[instanceIndex].PeersOfChannel(channel)[0].Metadata)
900+
assert.Equal(t, uint64(1), peers[instanceIndex].PeersOfChannel(channel)[0].Properties.LedgerHeight)
900901
} else {
901902
assert.Equal(t, channelBmetadata, peers[instanceIndex].PeersOfChannel(channel)[0].Metadata)
903+
assert.Equal(t, uint64(2), peers[instanceIndex].PeersOfChannel(channel)[0].Properties.LedgerHeight)
902904
}
903905
}
904906
}

gossip/state/state.go

+12-4
Original file line numberDiff line numberDiff line change
@@ -547,10 +547,15 @@ func (s *GossipStateProviderImpl) antiEntropy() {
547547
func (s *GossipStateProviderImpl) maxAvailableLedgerHeight() uint64 {
548548
max := uint64(0)
549549
for _, p := range s.mediator.PeersOfChannel(common2.ChainID(s.chainID)) {
550-
if nodeMetastate, err := common2.FromBytes(p.Metadata); err == nil {
551-
if max < nodeMetastate.LedgerHeight {
552-
max = nodeMetastate.LedgerHeight
553-
}
550+
var peerHeight uint64
551+
if p.Properties != nil {
552+
peerHeight = p.Properties.LedgerHeight
553+
} else if nodeMetastate, err := common2.FromBytes(p.Metadata); err == nil {
554+
peerHeight = nodeMetastate.LedgerHeight
555+
}
556+
557+
if max < peerHeight {
558+
max = peerHeight
554559
}
555560
}
556561
return max
@@ -660,6 +665,9 @@ func (s *GossipStateProviderImpl) filterPeers(predicate func(peer discovery.Netw
660665
// by provided input parameter
661666
func (s *GossipStateProviderImpl) hasRequiredHeight(height uint64) func(peer discovery.NetworkMember) bool {
662667
return func(peer discovery.NetworkMember) bool {
668+
if peer.Properties != nil {
669+
return peer.Properties.LedgerHeight >= height
670+
}
663671
if nodeMetadata, err := common2.FromBytes(peer.Metadata); err != nil {
664672
logger.Errorf("Unable to de-serialize node meta state, error = %+v", errors.WithStack(err))
665673
} else if nodeMetadata.LedgerHeight >= height {

gossip/state/state_test.go

+102
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"math/rand"
1414
"strconv"
1515
"sync"
16+
"sync/atomic"
1617
"testing"
1718
"time"
1819

@@ -553,6 +554,107 @@ func TestGossipReception(t *testing.T) {
553554
}
554555
}
555556

557+
func TestMetadataCompatibility(t *testing.T) {
558+
// Scenario: For each test, spawn a peer and supply it
559+
// with a specific mock of PeersOfChannel from peers that
560+
// either set both metadata properly, or only the properties, or none, or both.
561+
// Ensure the logic handles all of the 4 possible cases as needed
562+
563+
// Returns whether the given networkMember was selected or not
564+
wasNetworkMemberSelected := func(t *testing.T, networkMember discovery.NetworkMember, wg *sync.WaitGroup) bool {
565+
var wasGivenNetworkMemberSelected int32
566+
finChan := make(chan struct{})
567+
g := &mocks.GossipMock{}
568+
g.On("Send", mock.Anything, mock.Anything).Run(func(arguments mock.Arguments) {
569+
defer wg.Done()
570+
msg := arguments.Get(0).(*proto.GossipMessage)
571+
assert.NotNil(t, msg.GetStateRequest())
572+
peer := arguments.Get(1).([]*comm.RemotePeer)[0]
573+
if bytes.Equal(networkMember.PKIid, peer.PKIID) {
574+
atomic.StoreInt32(&wasGivenNetworkMemberSelected, 1)
575+
}
576+
finChan <- struct{}{}
577+
})
578+
g.On("Accept", mock.Anything, false).Return(make(<-chan *proto.GossipMessage), nil)
579+
g.On("Accept", mock.Anything, true).Return(nil, make(<-chan proto.ReceivedMessage))
580+
metaState := common.NewNodeMetastate(5)
581+
b, _ := metaState.Bytes()
582+
defaultPeer := discovery.NetworkMember{
583+
InternalEndpoint: "b",
584+
PKIid: common.PKIidType("b"),
585+
Metadata: b,
586+
Properties: &proto.Properties{
587+
LedgerHeight: 5,
588+
},
589+
}
590+
g.On("PeersOfChannel", mock.Anything).Return([]discovery.NetworkMember{
591+
defaultPeer,
592+
networkMember,
593+
})
594+
mc := &mockCommitter{}
595+
mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil)
596+
p := newPeerNodeWithGossip(newGossipConfig(0), mc, noopPeerIdentityAcceptor, g)
597+
defer p.shutdown()
598+
select {
599+
case <-time.After(time.Second * 20):
600+
t.Fatal("Didn't send a request within a timely manner")
601+
case <-finChan:
602+
}
603+
return atomic.LoadInt32(&wasGivenNetworkMemberSelected) == 1
604+
}
605+
606+
peerWithoutMetadata := discovery.NetworkMember{
607+
PKIid: common.PKIidType("peerWithoutMetadata"),
608+
Properties: &proto.Properties{
609+
LedgerHeight: 10,
610+
},
611+
InternalEndpoint: "peerWithoutMetadata",
612+
}
613+
614+
ms := common.NodeMetastate{
615+
LedgerHeight: 10,
616+
}
617+
b, _ := ms.Bytes()
618+
peerWithoutProperties := discovery.NetworkMember{
619+
PKIid: common.PKIidType("peerWithoutProperties"),
620+
InternalEndpoint: "peerWithoutProperties",
621+
Metadata: b,
622+
}
623+
624+
peerWithoutEverything := discovery.NetworkMember{
625+
PKIid: common.PKIidType("peerWithoutProperties"),
626+
InternalEndpoint: "peerWithoutProperties",
627+
}
628+
629+
peerWithEverything := discovery.NetworkMember{
630+
PKIid: common.PKIidType("peerWitEverything"),
631+
InternalEndpoint: "peerWitEverything",
632+
Metadata: b,
633+
Properties: &proto.Properties{
634+
LedgerHeight: 10,
635+
},
636+
}
637+
638+
tests := []struct {
639+
shouldGivenBeSelected bool
640+
member discovery.NetworkMember
641+
}{
642+
{member: peerWithoutMetadata, shouldGivenBeSelected: true},
643+
{member: peerWithoutProperties, shouldGivenBeSelected: true},
644+
{member: peerWithoutEverything, shouldGivenBeSelected: false},
645+
{member: peerWithEverything, shouldGivenBeSelected: true},
646+
}
647+
648+
var wg sync.WaitGroup
649+
wg.Add(len(tests))
650+
for _, tst := range tests {
651+
go func(shouldGivenBeSelected bool, member discovery.NetworkMember) {
652+
assert.Equal(t, shouldGivenBeSelected, wasNetworkMemberSelected(t, member, &wg))
653+
}(tst.shouldGivenBeSelected, tst.member)
654+
}
655+
wg.Wait()
656+
}
657+
556658
func TestAccessControl(t *testing.T) {
557659
viper.Set("peer.fileSystemPath", "/tmp/tests/ledger/node")
558660
ledgermgmt.InitializeTestEnv()

protos/gossip/extensions.go

+10
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,16 @@ func digestsToHex(digests []string) []string {
580580
return a
581581
}
582582

583+
// LedgerHeight returns the ledger height that is specified
584+
// in the StateInfo message
585+
func (msg *StateInfo) LedgerHeight() (uint64, error) {
586+
if msg.Properties != nil {
587+
return msg.Properties.LedgerHeight, nil
588+
}
589+
metaState, err := common.FromBytes(msg.Metadata)
590+
return metaState.LedgerHeight, err
591+
}
592+
583593
// Abs returns abs(a-b)
584594
func abs(a, b uint64) uint64 {
585595
if a > b {

0 commit comments

Comments
 (0)