From 6b1ac6fd73e30958f37390e1c69e5b5a57a7f5ac Mon Sep 17 00:00:00 2001 From: yacovm Date: Wed, 23 Sep 2020 15:57:43 +0300 Subject: [PATCH] [FAB-18237] always update stateInfo message upon chaincode update With the change of FAB-18208, gossip saves CPU cycles by only updating metadata information if peer membership is not empty. However, this makes discovery incapable of operating in case anchor/bootstrap peers are not defined, or, in case the peer is the only peer in the network. This change makes gossip always update its information, including signing the stateInfo message, whenever it receives a chaincode update. Change-Id: Iaf04441944a3fe5d889233d35bdcb1173c31e2bc Signed-off-by: yacovm --- gossip/gossip/channel/channel.go | 14 +++++++- gossip/gossip/channel/channel_test.go | 8 +++++ integration/discovery/discovery_test.go | 43 ++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/gossip/gossip/channel/channel.go b/gossip/gossip/channel/channel.go index 85fe8b5039b..eb0d9515633 100644 --- a/gossip/gossip/channel/channel.go +++ b/gossip/gossip/channel/channel.go @@ -414,6 +414,11 @@ func (gc *gossipChannel) publishStateInfo() { return } + gc.publishSignedStateInfoMessage() + atomic.StoreInt32(&gc.shouldGossipStateInfo, int32(0)) +} + +func (gc *gossipChannel) publishSignedStateInfoMessage() { stateInfoMsg, err := gc.setupSignedStateInfoMessage() if err != nil { gc.logger.Errorf("Failed creating signed state info message: %v", err) @@ -421,7 +426,6 @@ func (gc *gossipChannel) publishStateInfo() { } gc.stateInfoMsgStore.Add(stateInfoMsg) gc.Gossip(stateInfoMsg) - atomic.StoreInt32(&gc.shouldGossipStateInfo, int32(0)) } func (gc *gossipChannel) setupSignedStateInfoMessage() (*protoext.SignedGossipMessage, error) { @@ -928,6 +932,14 @@ func (gc *gossipChannel) UpdateLedgerHeight(height uint64) { // UpdateChaincodes updates the chaincodes the peer publishes // to other peers in the channel func (gc *gossipChannel) UpdateChaincodes(chaincodes []*proto.Chaincode) { + // Always publish the signed state info message regardless. + // We do this because we have to update our data structures + // with the new chaincodes installed/instantiated, to be able to + // respond to discovery requests, no matter if we see other peers + // in the membership, or do not see them. + + defer gc.publishSignedStateInfoMessage() + gc.Lock() defer gc.Unlock() diff --git a/gossip/gossip/channel/channel_test.go b/gossip/gossip/channel/channel_test.go index a2a2e719310..c8fdb38a5e4 100644 --- a/gossip/gossip/channel/channel_test.go +++ b/gossip/gossip/channel/channel_test.go @@ -1132,6 +1132,14 @@ func TestNoGossipOrSigningWhenEmptyMembership(t *testing.T) { time.Sleep(conf.PublishStateInfoInterval * 3) // We haven't signed anything assert.Equal(t, uint32(2), atomic.LoadUint32(&adapter.signCallCount)) + + assert.Empty(t, gc.Self().GetStateInfo().Properties.Chaincodes) + gossipedWG.Add(1) + // Now, update chaincodes and check our chaincode information was indeed updated + gc.UpdateChaincodes([]*proto.Chaincode{{Name: "mycc"}}) + // We should have signed regardless! + assert.Equal(t, uint32(3), atomic.LoadUint32(&adapter.signCallCount)) + assert.Equal(t, "mycc", gc.Self().GetStateInfo().Properties.Chaincodes[0].Name) } func TestChannelPulledBadBlocks(t *testing.T) { diff --git a/integration/discovery/discovery_test.go b/integration/discovery/discovery_test.go index 8523762fb25..932cd86b3eb 100644 --- a/integration/discovery/discovery_test.go +++ b/integration/discovery/discovery_test.go @@ -84,7 +84,6 @@ var _ = Describe("DiscoveryService", func() { orderer = network.Orderer("orderer") network.CreateAndJoinChannel(orderer, "testchannel") - network.UpdateChannelAnchors(orderer, "testchannel") org1Peer0 = network.Peer("Org1", "peer0") org2Peer0 = network.Peer("Org2", "peer0") @@ -102,10 +101,46 @@ var _ = Describe("DiscoveryService", func() { os.RemoveAll(testDir) }) + It("discovers network configuration even without anchor peers present", func() { + chaincodeWhenNoAnchorPeers := nwo.Chaincode{ + Name: "noanchorpeersjustyet", + Version: "1.0", + Path: "github.com/hyperledger/fabric/integration/chaincode/simple/cmd", + Ctor: `{"Args":["init","a","100","b","200"]}`, + Policy: `OR ('Org1MSP.member')`, + } + By("Deploying chaincode before anchor peers are defined in the channel") + nwo.DeployChaincodeLegacy(network, "testchannel", orderer, chaincodeWhenNoAnchorPeers, org1Peer0) + + endorsersForChaincodeBeforeAnchorPeersExist := commands.Endorsers{ + UserCert: network.PeerUserCert(org1Peer0, "User1"), + UserKey: network.PeerUserKey(org1Peer0, "User1"), + MSPID: network.Organization(org1Peer0.Organization).MSPID, + Server: network.PeerAddress(org1Peer0, nwo.ListenPort), + Channel: "testchannel", + Chaincode: chaincodeWhenNoAnchorPeers.Name, + } + discoveryQuery := discoverEndorsers(network, endorsersForChaincodeBeforeAnchorPeersExist) + Eventually(discoveryQuery, network.EventuallyTimeout).Should(BeEquivalentTo( + []ChaincodeEndorsers{ + { + Chaincode: chaincodeWhenNoAnchorPeers.Name, + EndorsersByGroups: map[string][]nwo.DiscoveredPeer{ + "G0": {network.DiscoveredPeer(org1Peer0)}, + }, + Layouts: []*discovery.Layout{ + { + QuantitiesByGroup: map[string]uint32{"G0": 1}, + }, + }, + }, + }, + )) + }) + It("discovers network configuration, endorsers, and peer membership", func() { - // - // discovering network configuration information - // + By("Updating anchor peers") + network.UpdateChannelAnchors(orderer, "testchannel") By("retrieving the configuration") config := commands.Config{