github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/gossip/state/state_test.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8                   http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package state
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"strconv"
    23  	"sync"
    24  	"testing"
    25  	"time"
    26  
    27  	pb "github.com/golang/protobuf/proto"
    28  	"github.com/hyperledger/fabric/common/configtx/test"
    29  	"github.com/hyperledger/fabric/common/util"
    30  	"github.com/hyperledger/fabric/core/committer"
    31  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
    32  	"github.com/hyperledger/fabric/core/mocks/validator"
    33  	"github.com/hyperledger/fabric/gossip/api"
    34  	"github.com/hyperledger/fabric/gossip/comm"
    35  	"github.com/hyperledger/fabric/gossip/common"
    36  	"github.com/hyperledger/fabric/gossip/gossip"
    37  	"github.com/hyperledger/fabric/gossip/identity"
    38  	gossipUtil "github.com/hyperledger/fabric/gossip/util"
    39  	pcomm "github.com/hyperledger/fabric/protos/common"
    40  	proto "github.com/hyperledger/fabric/protos/gossip"
    41  	"github.com/spf13/viper"
    42  	"github.com/stretchr/testify/assert"
    43  )
    44  
    45  var (
    46  	portPrefix = 5610
    47  	logger     = gossipUtil.GetLogger(gossipUtil.LoggingStateModule, "")
    48  )
    49  
    50  var orgID = []byte("ORG1")
    51  
    52  type joinChanMsg struct {
    53  }
    54  
    55  // SequenceNumber returns the sequence number of the block that the message
    56  // is derived from
    57  func (*joinChanMsg) SequenceNumber() uint64 {
    58  	return uint64(time.Now().UnixNano())
    59  }
    60  
    61  // AnchorPeers returns all the anchor peers that are in the channel
    62  func (*joinChanMsg) AnchorPeers() []api.AnchorPeer {
    63  	return []api.AnchorPeer{{OrgID: orgID}}
    64  }
    65  
    66  type orgCryptoService struct {
    67  }
    68  
    69  // OrgByPeerIdentity returns the OrgIdentityType
    70  // of a given peer identity
    71  func (*orgCryptoService) OrgByPeerIdentity(identity api.PeerIdentityType) api.OrgIdentityType {
    72  	return orgID
    73  }
    74  
    75  // Verify verifies a JoinChannelMessage, returns nil on success,
    76  // and an error on failure
    77  func (*orgCryptoService) Verify(joinChanMsg api.JoinChannelMessage) error {
    78  	return nil
    79  }
    80  
    81  type naiveCryptoService struct {
    82  }
    83  
    84  // GetPKIidOfCert returns the PKI-ID of a peer's identity
    85  func (*naiveCryptoService) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType {
    86  	return common.PKIidType(peerIdentity)
    87  }
    88  
    89  // VerifyBlock returns nil if the block is properly signed,
    90  // else returns error
    91  func (*naiveCryptoService) VerifyBlock(chainID common.ChainID, signedBlock api.SignedBlock) error {
    92  	return nil
    93  }
    94  
    95  // Sign signs msg with this peer's signing key and outputs
    96  // the signature if no error occurred.
    97  func (*naiveCryptoService) Sign(msg []byte) ([]byte, error) {
    98  	return msg, nil
    99  }
   100  
   101  // Verify checks that signature is a valid signature of message under a peer's verification key.
   102  // If the verification succeeded, Verify returns nil meaning no error occurred.
   103  // If peerCert is nil, then the signature is verified against this peer's verification key.
   104  func (*naiveCryptoService) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error {
   105  	equal := bytes.Equal(signature, message)
   106  	if !equal {
   107  		return fmt.Errorf("Wrong signature:%v, %v", signature, message)
   108  	}
   109  	return nil
   110  }
   111  
   112  // VerifyByChannel checks that signature is a valid signature of message
   113  // under a peer's verification key, but also in the context of a specific channel.
   114  // If the verification succeeded, Verify returns nil meaning no error occurred.
   115  // If peerIdentity is nil, then the signature is verified against this peer's verification key.
   116  func (*naiveCryptoService) VerifyByChannel(chainID common.ChainID, peerIdentity api.PeerIdentityType, signature, message []byte) error {
   117  	return nil
   118  }
   119  
   120  func (*naiveCryptoService) ValidateIdentity(peerIdentity api.PeerIdentityType) error {
   121  	return nil
   122  }
   123  
   124  func bootPeers(ids ...int) []string {
   125  	peers := []string{}
   126  	for _, id := range ids {
   127  		peers = append(peers, fmt.Sprintf("localhost:%d", id+portPrefix))
   128  	}
   129  	return peers
   130  }
   131  
   132  // Simple presentation of peer which includes only
   133  // communication module, gossip and state transfer
   134  type peerNode struct {
   135  	g gossip.Gossip
   136  	s GossipStateProvider
   137  
   138  	commit committer.Committer
   139  }
   140  
   141  // Shutting down all modules used
   142  func (node *peerNode) shutdown() {
   143  	node.s.Stop()
   144  	node.g.Stop()
   145  }
   146  
   147  // Default configuration to be used for gossip and communication modules
   148  func newGossipConfig(id int, maxMsgCount int, boot ...int) *gossip.Config {
   149  	port := id + portPrefix
   150  	return &gossip.Config{
   151  		BindPort:                   port,
   152  		BootstrapPeers:             bootPeers(boot...),
   153  		ID:                         fmt.Sprintf("p%d", id),
   154  		MaxBlockCountToStore:       maxMsgCount,
   155  		MaxPropagationBurstLatency: time.Duration(10) * time.Millisecond,
   156  		MaxPropagationBurstSize:    10,
   157  		PropagateIterations:        1,
   158  		PropagatePeerNum:           3,
   159  		PullInterval:               time.Duration(4) * time.Second,
   160  		PullPeerNum:                5,
   161  		InternalEndpoint:           fmt.Sprintf("localhost:%d", port),
   162  		PublishCertPeriod:          10 * time.Second,
   163  		RequestStateInfoInterval:   4 * time.Second,
   164  		PublishStateInfoInterval:   4 * time.Second,
   165  	}
   166  }
   167  
   168  // Create gossip instance
   169  func newGossipInstance(config *gossip.Config) gossip.Gossip {
   170  	cryptoService := &naiveCryptoService{}
   171  	idMapper := identity.NewIdentityMapper(cryptoService)
   172  
   173  	return gossip.NewGossipServiceWithServer(config, &orgCryptoService{}, cryptoService, idMapper, []byte(config.InternalEndpoint))
   174  }
   175  
   176  // Create new instance of KVLedger to be used for testing
   177  func newCommitter(id int) committer.Committer {
   178  	ledger, _ := ledgermgmt.CreateLedger(strconv.Itoa(id))
   179  	cb, _ := test.MakeGenesisBlock(util.GetTestChainID())
   180  	ledger.Commit(cb)
   181  	return committer.NewLedgerCommitter(ledger, &validator.MockValidator{})
   182  }
   183  
   184  // Constructing pseudo peer node, simulating only gossip and state transfer part
   185  func newPeerNode(config *gossip.Config, committer committer.Committer) *peerNode {
   186  
   187  	// Gossip component based on configuration provided and communication module
   188  	gossip := newGossipInstance(config)
   189  
   190  	logger.Debug("Joinning channel", util.GetTestChainID())
   191  	gossip.JoinChan(&joinChanMsg{}, common.ChainID(util.GetTestChainID()))
   192  
   193  	// Initialize pseudo peer simulator, which has only three
   194  	// basic parts
   195  	return &peerNode{
   196  		g: gossip,
   197  		s: NewGossipStateProvider(util.GetTestChainID(), gossip, committer),
   198  
   199  		commit: committer,
   200  	}
   201  }
   202  
   203  /*// Simple scenario to start first booting node, gossip a message
   204  // then start second node and verify second node also receives it
   205  func TestNewGossipStateProvider_GossipingOneMessage(t *testing.T) {
   206  	bootId := 0
   207  	ledgerPath := "/tmp/tests/ledger/"
   208  	defer os.RemoveAll(ledgerPath)
   209  
   210  	bootNodeCommitter := newCommitter(bootId, ledgerPath + "node/")
   211  	defer bootNodeCommitter.Close()
   212  
   213  	bootNode := newPeerNode(newGossipConfig(bootId, 100), bootNodeCommitter)
   214  	defer bootNode.shutdown()
   215  
   216  	rawblock := &peer.Block2{}
   217  	if err := pb.Unmarshal([]byte{}, rawblock); err != nil {
   218  		t.Fail()
   219  	}
   220  
   221  	if bytes, err := pb.Marshal(rawblock); err == nil {
   222  		payload := &proto.Payload{1, "", bytes}
   223  		bootNode.s.AddPayload(payload)
   224  	} else {
   225  		t.Fail()
   226  	}
   227  
   228  	waitUntilTrueOrTimeout(t, func() bool {
   229  		if block := bootNode.s.GetBlock(uint64(1)); block != nil {
   230  			return true
   231  		}
   232  		return false
   233  	}, 5 * time.Second)
   234  
   235  	bootNode.g.Gossip(createDataMsg(uint64(1), []byte{}, ""))
   236  
   237  	peerCommitter := newCommitter(1, ledgerPath + "node/")
   238  	defer peerCommitter.Close()
   239  
   240  	peer := newPeerNode(newGossipConfig(1, 100, bootId), peerCommitter)
   241  	defer peer.shutdown()
   242  
   243  	ready := make(chan interface{})
   244  
   245  	go func(p *peerNode) {
   246  		for len(p.g.GetPeers()) != 1 {
   247  			time.Sleep(100 * time.Millisecond)
   248  		}
   249  		ready <- struct{}{}
   250  	}(peer)
   251  
   252  	select {
   253  	case <-ready:
   254  		{
   255  			break
   256  		}
   257  	case <-time.After(1 * time.Second):
   258  		{
   259  			t.Fail()
   260  		}
   261  	}
   262  
   263  	// Let sure anti-entropy will have a chance to bring missing block
   264  	waitUntilTrueOrTimeout(t, func() bool {
   265  		if block := peer.s.GetBlock(uint64(1)); block != nil {
   266  			return true
   267  		}
   268  		return false
   269  	}, 2 * defAntiEntropyInterval + 1 * time.Second)
   270  
   271  	block := peer.s.GetBlock(uint64(1))
   272  
   273  	assert.NotNil(t, block)
   274  }
   275  
   276  func TestNewGossipStateProvider_RepeatGossipingOneMessage(t *testing.T) {
   277  	for i := 0; i < 10; i++ {
   278  		TestNewGossipStateProvider_GossipingOneMessage(t)
   279  	}
   280  }*/
   281  
   282  func TestNewGossipStateProvider_SendingManyMessages(t *testing.T) {
   283  	viper.Set("peer.fileSystemPath", "/tmp/tests/ledger/node")
   284  	ledgermgmt.InitializeTestEnv()
   285  	defer ledgermgmt.CleanupTestEnv()
   286  
   287  	bootstrapSetSize := 5
   288  	bootstrapSet := make([]*peerNode, 0)
   289  
   290  	for i := 0; i < bootstrapSetSize; i++ {
   291  		committer := newCommitter(i)
   292  		bootstrapSet = append(bootstrapSet, newPeerNode(newGossipConfig(i, 100), committer))
   293  	}
   294  
   295  	defer func() {
   296  		for _, p := range bootstrapSet {
   297  			p.shutdown()
   298  		}
   299  	}()
   300  
   301  	msgCount := 10
   302  
   303  	for i := 1; i <= msgCount; i++ {
   304  		rawblock := pcomm.NewBlock(uint64(i), []byte{})
   305  		if bytes, err := pb.Marshal(rawblock); err == nil {
   306  			payload := &proto.Payload{uint64(i), "", bytes}
   307  			bootstrapSet[0].s.AddPayload(payload)
   308  		} else {
   309  			t.Fail()
   310  		}
   311  	}
   312  
   313  	standartPeersSize := 10
   314  	peersSet := make([]*peerNode, 0)
   315  
   316  	for i := 0; i < standartPeersSize; i++ {
   317  		committer := newCommitter(bootstrapSetSize + i)
   318  		peersSet = append(peersSet, newPeerNode(newGossipConfig(bootstrapSetSize+i, 100, 0, 1, 2, 3, 4), committer))
   319  	}
   320  
   321  	defer func() {
   322  		for _, p := range peersSet {
   323  			p.shutdown()
   324  		}
   325  	}()
   326  
   327  	waitUntilTrueOrTimeout(t, func() bool {
   328  		for _, p := range peersSet {
   329  			if len(p.g.PeersOfChannel(common.ChainID(util.GetTestChainID()))) != bootstrapSetSize+standartPeersSize-1 {
   330  				logger.Debug("Peer discovery has not finished yet")
   331  				return false
   332  			}
   333  		}
   334  		logger.Debug("All peer discovered each other!!!")
   335  		return true
   336  	}, 30*time.Second)
   337  
   338  	logger.Debug("Waiting for all blocks to arrive.")
   339  	waitUntilTrueOrTimeout(t, func() bool {
   340  		logger.Debug("Trying to see all peers get all blocks")
   341  		for _, p := range peersSet {
   342  			height, err := p.commit.LedgerHeight()
   343  			if height != uint64(msgCount+1) || err != nil {
   344  				return false
   345  			}
   346  		}
   347  		logger.Debug("All peers have same ledger height!!!")
   348  		return true
   349  	}, 60*time.Second)
   350  }
   351  
   352  func TestGossipStateProvider_TestStateMessages(t *testing.T) {
   353  	viper.Set("peer.fileSystemPath", "/tmp/tests/ledger/node")
   354  	ledgermgmt.InitializeTestEnv()
   355  	defer ledgermgmt.CleanupTestEnv()
   356  
   357  	bootPeer := newPeerNode(newGossipConfig(0, 100), newCommitter(0))
   358  	defer bootPeer.shutdown()
   359  
   360  	peer := newPeerNode(newGossipConfig(1, 100, 0), newCommitter(1))
   361  	defer peer.shutdown()
   362  
   363  	_, bootCh := bootPeer.g.Accept(remoteStateMsgFilter, true)
   364  	_, peerCh := peer.g.Accept(remoteStateMsgFilter, true)
   365  
   366  	wg := sync.WaitGroup{}
   367  	wg.Add(2)
   368  
   369  	go func() {
   370  		msg := <-bootCh
   371  		logger.Info("Bootstrap node got message, ", msg)
   372  		assert.True(t, msg.GetGossipMessage().GetStateRequest() != nil)
   373  		msg.Respond(&proto.GossipMessage{
   374  			Content: &proto.GossipMessage_StateResponse{&proto.RemoteStateResponse{nil}},
   375  		})
   376  		wg.Done()
   377  	}()
   378  
   379  	go func() {
   380  		msg := <-peerCh
   381  		logger.Info("Peer node got an answer, ", msg)
   382  		assert.True(t, msg.GetGossipMessage().GetStateResponse() != nil)
   383  		wg.Done()
   384  
   385  	}()
   386  
   387  	readyCh := make(chan struct{})
   388  	go func() {
   389  		wg.Wait()
   390  		readyCh <- struct{}{}
   391  	}()
   392  
   393  	time.Sleep(time.Duration(5) * time.Second)
   394  	logger.Info("Sending gossip message with remote state request")
   395  
   396  	chainID := common.ChainID(util.GetTestChainID())
   397  
   398  	peer.g.Send(&proto.GossipMessage{
   399  		Content: &proto.GossipMessage_StateRequest{&proto.RemoteStateRequest{nil}},
   400  	}, &comm.RemotePeer{peer.g.PeersOfChannel(chainID)[0].Endpoint, peer.g.PeersOfChannel(chainID)[0].PKIid})
   401  	logger.Info("Waiting until peers exchange messages")
   402  
   403  	select {
   404  	case <-readyCh:
   405  		{
   406  			logger.Info("Done!!!")
   407  
   408  		}
   409  	case <-time.After(time.Duration(10) * time.Second):
   410  		{
   411  			t.Fail()
   412  		}
   413  	}
   414  }
   415  
   416  func waitUntilTrueOrTimeout(t *testing.T, predicate func() bool, timeout time.Duration) {
   417  	ch := make(chan struct{})
   418  	go func() {
   419  		logger.Debug("Started to spin off, until predicate will be satisfied.")
   420  		for !predicate() {
   421  			time.Sleep(1 * time.Second)
   422  		}
   423  		ch <- struct{}{}
   424  		logger.Debug("Done.")
   425  	}()
   426  
   427  	select {
   428  	case <-ch:
   429  		break
   430  	case <-time.After(timeout):
   431  		t.Fatal("Timeout has expired")
   432  		break
   433  	}
   434  	logger.Debug("Stop waiting until timeout or true")
   435  }