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 }