github.com/Hnampk/my-fabric@v0.0.0-20201028083322-75069da399c0/gossip/gossip/channel/channel.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package channel 8 9 import ( 10 "bytes" 11 "fmt" 12 "reflect" 13 "strconv" 14 "sync" 15 "sync/atomic" 16 "time" 17 18 proto "github.com/hyperledger/fabric-protos-go/gossip" 19 common_utils "github.com/hyperledger/fabric/common/util" 20 "github.com/hyperledger/fabric/gossip/api" 21 "github.com/hyperledger/fabric/gossip/comm" 22 "github.com/hyperledger/fabric/gossip/common" 23 "github.com/hyperledger/fabric/gossip/discovery" 24 "github.com/hyperledger/fabric/gossip/election" 25 "github.com/hyperledger/fabric/gossip/filter" 26 "github.com/hyperledger/fabric/gossip/gossip/algo" 27 "github.com/hyperledger/fabric/gossip/gossip/msgstore" 28 "github.com/hyperledger/fabric/gossip/gossip/pull" 29 "github.com/hyperledger/fabric/gossip/metrics" 30 "github.com/hyperledger/fabric/gossip/protoext" 31 "github.com/hyperledger/fabric/gossip/util" 32 "github.com/hyperledger/fabric/protoutil" 33 ) 34 35 const DefMsgExpirationTimeout = election.DefLeaderAliveThreshold * 10 36 37 // Config is a configuration item 38 // of the channel store 39 type Config struct { 40 ID string 41 PublishStateInfoInterval time.Duration 42 MaxBlockCountToStore int 43 PullPeerNum int 44 PullInterval time.Duration 45 RequestStateInfoInterval time.Duration 46 BlockExpirationInterval time.Duration 47 StateInfoCacheSweepInterval time.Duration 48 TimeForMembershipTracker time.Duration 49 DigestWaitTime time.Duration 50 RequestWaitTime time.Duration 51 ResponseWaitTime time.Duration 52 MsgExpirationTimeout time.Duration 53 } 54 55 // GossipChannel defines an object that deals with all channel-related messages 56 type GossipChannel interface { 57 // Self returns a StateInfoMessage about the peer 58 Self() *protoext.SignedGossipMessage 59 60 // GetPeers returns a list of peers with metadata as published by them 61 GetPeers() []discovery.NetworkMember 62 63 // PeerFilter receives a SubChannelSelectionCriteria and returns a RoutingFilter that selects 64 // only peer identities that match the given criteria 65 PeerFilter(api.SubChannelSelectionCriteria) filter.RoutingFilter 66 67 // IsMemberInChan checks whether the given member is eligible to be in the channel 68 IsMemberInChan(member discovery.NetworkMember) bool 69 70 // UpdateLedgerHeight updates the ledger height the peer 71 // publishes to other peers in the channel 72 UpdateLedgerHeight(height uint64) 73 74 // UpdateChaincodes updates the chaincodes the peer publishes 75 // to other peers in the channel 76 UpdateChaincodes(chaincode []*proto.Chaincode) 77 78 // IsOrgInChannel returns whether the given organization is in the channel 79 IsOrgInChannel(membersOrg api.OrgIdentityType) bool 80 81 // EligibleForChannel returns whether the given member should get blocks 82 // for this channel 83 EligibleForChannel(member discovery.NetworkMember) bool 84 85 // HandleMessage processes a message sent by a remote peer 86 HandleMessage(protoext.ReceivedMessage) 87 88 // AddToMsgStore adds a given GossipMessage to the message store 89 AddToMsgStore(msg *protoext.SignedGossipMessage) 90 91 // ConfigureChannel (re)configures the list of organizations 92 // that are eligible to be in the channel 93 ConfigureChannel(joinMsg api.JoinChannelMessage) 94 95 // LeaveChannel makes the peer leave the channel 96 LeaveChannel() 97 98 // Stop stops the channel's activity 99 Stop() 100 } 101 102 // Adapter enables the gossipChannel 103 // to communicate with gossipServiceImpl. 104 type Adapter interface { 105 Sign(msg *proto.GossipMessage) (*protoext.SignedGossipMessage, error) 106 107 // GetConf returns the configuration that this GossipChannel will posses 108 GetConf() Config 109 110 // Gossip gossips a message in the channel 111 Gossip(message *protoext.SignedGossipMessage) 112 113 // Forward sends a message to the next hops 114 Forward(message protoext.ReceivedMessage) 115 116 // DeMultiplex de-multiplexes an item to subscribers 117 DeMultiplex(interface{}) 118 119 // GetMembership returns the known alive peers and their information 120 GetMembership() []discovery.NetworkMember 121 122 // Lookup returns a network member, or nil if not found 123 Lookup(PKIID common.PKIidType) *discovery.NetworkMember 124 125 // Send sends a message to a list of peers 126 Send(msg *protoext.SignedGossipMessage, peers ...*comm.RemotePeer) 127 128 // ValidateStateInfoMessage returns an error if a message 129 // hasn't been signed correctly, nil otherwise. 130 ValidateStateInfoMessage(message *protoext.SignedGossipMessage) error 131 132 // GetOrgOfPeer returns the organization ID of a given peer PKI-ID 133 GetOrgOfPeer(pkiID common.PKIidType) api.OrgIdentityType 134 135 // GetIdentityByPKIID returns an identity of a peer with a certain 136 // pkiID, or nil if not found 137 GetIdentityByPKIID(pkiID common.PKIidType) api.PeerIdentityType 138 } 139 140 type gossipChannel struct { 141 Adapter 142 sync.RWMutex 143 shouldGossipStateInfo int32 144 mcs api.MessageCryptoService 145 pkiID common.PKIidType 146 selfOrg api.OrgIdentityType 147 stopChan chan struct{} 148 stateInfoMsg *protoext.SignedGossipMessage 149 orgs []api.OrgIdentityType 150 joinMsg api.JoinChannelMessage 151 blockMsgStore msgstore.MessageStore 152 stateInfoMsgStore *stateInfoCache 153 leaderMsgStore msgstore.MessageStore 154 chainID common.ChannelID 155 blocksPuller pull.Mediator 156 logger util.Logger 157 stateInfoPublishScheduler *time.Ticker 158 stateInfoRequestScheduler *time.Ticker 159 memFilter *membershipFilter 160 ledgerHeight uint64 161 incTime uint64 162 leftChannel int32 163 membershipTracker *membershipTracker 164 } 165 166 type membershipFilter struct { 167 adapter Adapter 168 *gossipChannel 169 } 170 171 // GetMembership returns the known alive peers and their information 172 func (mf *membershipFilter) GetMembership() []discovery.NetworkMember { 173 if mf.hasLeftChannel() { 174 return nil 175 } 176 177 var members []discovery.NetworkMember 178 for _, mem := range mf.adapter.GetMembership() { 179 if mf.eligibleForChannelAndSameOrg(mem) { 180 members = append(members, mem) 181 } 182 } 183 return members 184 } 185 186 // NewGossipChannel creates a new GossipChannel 187 func NewGossipChannel(pkiID common.PKIidType, org api.OrgIdentityType, mcs api.MessageCryptoService, 188 channelID common.ChannelID, adapter Adapter, joinMsg api.JoinChannelMessage, 189 metrics *metrics.MembershipMetrics, logger util.Logger) GossipChannel { 190 gc := &gossipChannel{ 191 incTime: uint64(time.Now().UnixNano()), 192 selfOrg: org, 193 pkiID: pkiID, 194 mcs: mcs, 195 Adapter: adapter, 196 stopChan: make(chan struct{}, 1), 197 shouldGossipStateInfo: int32(0), 198 stateInfoPublishScheduler: time.NewTicker(adapter.GetConf().PublishStateInfoInterval), 199 stateInfoRequestScheduler: time.NewTicker(adapter.GetConf().RequestStateInfoInterval), 200 orgs: []api.OrgIdentityType{}, 201 chainID: channelID, 202 } 203 204 if logger == nil { 205 gc.logger = util.GetLogger(util.ChannelLogger, adapter.GetConf().ID) 206 } else { 207 gc.logger = logger 208 } 209 210 gc.memFilter = &membershipFilter{adapter: gc.Adapter, gossipChannel: gc} 211 212 comparator := protoext.NewGossipMessageComparator(adapter.GetConf().MaxBlockCountToStore) 213 214 gc.blocksPuller = gc.createBlockPuller() 215 216 seqNumFromMsg := func(m interface{}) string { 217 return fmt.Sprintf("%d", m.(*protoext.SignedGossipMessage).GetDataMsg().Payload.SeqNum) 218 } 219 gc.blockMsgStore = msgstore.NewMessageStoreExpirable(comparator, func(m interface{}) { 220 gc.logger.Debugf("Removing %s from the message store", seqNumFromMsg(m)) 221 gc.blocksPuller.Remove(seqNumFromMsg(m)) 222 }, gc.GetConf().BlockExpirationInterval, nil, nil, func(m interface{}) { 223 gc.logger.Debugf("Removing %s from the message store", seqNumFromMsg(m)) 224 gc.blocksPuller.Remove(seqNumFromMsg(m)) 225 }) 226 227 hashPeerExpiredInMembership := func(o interface{}) bool { 228 pkiID := o.(*protoext.SignedGossipMessage).GetStateInfo().PkiId 229 return gc.Lookup(pkiID) == nil 230 } 231 verifyStateInfoMsg := func(msg *protoext.SignedGossipMessage, orgs ...api.OrgIdentityType) bool { 232 si := msg.GetStateInfo() 233 // No point in verifying ourselves 234 if bytes.Equal(gc.pkiID, si.PkiId) { 235 return true 236 } 237 peerIdentity := adapter.GetIdentityByPKIID(si.PkiId) 238 if len(peerIdentity) == 0 { 239 gc.logger.Warning("Identity for peer", si.PkiId, "doesn't exist") 240 return false 241 } 242 isOrgInChan := func(org api.OrgIdentityType) bool { 243 if len(orgs) == 0 { 244 if !gc.IsOrgInChannel(org) { 245 return false 246 } 247 } else { 248 found := false 249 for _, chanMember := range orgs { 250 if bytes.Equal(chanMember, org) { 251 found = true 252 break 253 } 254 } 255 if !found { 256 return false 257 } 258 } 259 return true 260 } 261 262 org := gc.GetOrgOfPeer(si.PkiId) 263 if !isOrgInChan(org) { 264 gc.logger.Warning("peer", peerIdentity, "'s organization(", string(org), ") isn't in the channel", string(channelID)) 265 return false 266 } 267 if err := gc.mcs.VerifyByChannel(channelID, peerIdentity, msg.Signature, msg.Payload); err != nil { 268 gc.logger.Warningf("Peer %v isn't eligible for channel %s : %+v", peerIdentity, string(channelID), err) 269 return false 270 } 271 return true 272 } 273 gc.stateInfoMsgStore = newStateInfoCache(gc.GetConf().StateInfoCacheSweepInterval, hashPeerExpiredInMembership, verifyStateInfoMsg) 274 275 ttl := adapter.GetConf().MsgExpirationTimeout 276 pol := protoext.NewGossipMessageComparator(0) 277 278 gc.leaderMsgStore = msgstore.NewMessageStoreExpirable(pol, msgstore.Noop, ttl, nil, nil, nil) 279 280 gc.ConfigureChannel(joinMsg) 281 282 // Periodically publish state info 283 go gc.periodicalInvocation(gc.publishStateInfo, gc.stateInfoPublishScheduler.C) 284 // Periodically request state info 285 go gc.periodicalInvocation(gc.requestStateInfo, gc.stateInfoRequestScheduler.C) 286 287 ticker := time.NewTicker(gc.GetConf().TimeForMembershipTracker) 288 gc.membershipTracker = &membershipTracker{ 289 getPeersToTrack: gc.GetPeers, 290 report: gc.reportMembershipChanges, 291 stopChan: make(chan struct{}, 1), 292 tickerChannel: ticker.C, 293 metrics: metrics, 294 chainID: channelID, 295 } 296 297 go gc.membershipTracker.trackMembershipChanges() 298 return gc 299 } 300 301 func (gc *gossipChannel) reportMembershipChanges(input ...interface{}) { 302 args := []interface{}{fmt.Sprintf("[%s]", string(gc.chainID))} 303 args = append(args, input...) 304 gc.logger.Info(args) 305 } 306 307 // Stop stop the channel operations 308 func (gc *gossipChannel) Stop() { 309 close(gc.stopChan) 310 close(gc.membershipTracker.stopChan) 311 gc.blocksPuller.Stop() 312 gc.stateInfoPublishScheduler.Stop() 313 gc.stateInfoRequestScheduler.Stop() 314 gc.leaderMsgStore.Stop() 315 gc.stateInfoMsgStore.Stop() 316 gc.blockMsgStore.Stop() 317 } 318 319 func (gc *gossipChannel) periodicalInvocation(fn func(), c <-chan time.Time) { 320 for { 321 select { 322 case <-c: 323 fn() 324 case <-gc.stopChan: 325 return 326 } 327 } 328 } 329 330 // Self returns a StateInfoMessage about the peer 331 func (gc *gossipChannel) Self() *protoext.SignedGossipMessage { 332 gc.RLock() 333 defer gc.RUnlock() 334 return gc.stateInfoMsg 335 } 336 337 // LeaveChannel makes the peer leave the channel 338 func (gc *gossipChannel) LeaveChannel() { 339 gc.Lock() 340 defer gc.Unlock() 341 342 atomic.StoreInt32(&gc.leftChannel, 1) 343 344 var chaincodes []*proto.Chaincode 345 var height uint64 346 if prevMsg := gc.stateInfoMsg; prevMsg != nil { 347 chaincodes = prevMsg.GetStateInfo().Properties.Chaincodes 348 height = prevMsg.GetStateInfo().Properties.LedgerHeight 349 } 350 gc.updateProperties(height, chaincodes, true) 351 } 352 353 func (gc *gossipChannel) hasLeftChannel() bool { 354 return atomic.LoadInt32(&gc.leftChannel) == 1 355 } 356 357 // GetPeers returns a list of peers with metadata as published by them 358 func (gc *gossipChannel) GetPeers() []discovery.NetworkMember { 359 var members []discovery.NetworkMember 360 if gc.hasLeftChannel() { 361 return members 362 } 363 364 for _, member := range gc.GetMembership() { 365 if !gc.EligibleForChannel(member) { 366 continue 367 } 368 stateInf := gc.stateInfoMsgStore.MsgByID(member.PKIid) 369 if stateInf == nil { 370 continue 371 } 372 props := stateInf.GetStateInfo().Properties 373 if props != nil && props.LeftChannel { 374 continue 375 } 376 member.Properties = stateInf.GetStateInfo().Properties 377 member.Envelope = stateInf.Envelope 378 members = append(members, member) 379 } 380 return members 381 } 382 383 func (gc *gossipChannel) requestStateInfo() { 384 req, err := gc.createStateInfoRequest() 385 if err != nil { 386 gc.logger.Warningf("Failed creating SignedGossipMessage: %+v", err) 387 return 388 } 389 endpoints := filter.SelectPeers(gc.GetConf().PullPeerNum, gc.GetMembership(), gc.IsMemberInChan) 390 gc.Send(req, endpoints...) 391 } 392 393 func (gc *gossipChannel) eligibleForChannelAndSameOrg(member discovery.NetworkMember) bool { 394 sameOrg := func(networkMember discovery.NetworkMember) bool { 395 return bytes.Equal(gc.GetOrgOfPeer(networkMember.PKIid), gc.selfOrg) 396 } 397 return filter.CombineRoutingFilters(gc.EligibleForChannel, sameOrg)(member) 398 } 399 400 func (gc *gossipChannel) publishStateInfo() { 401 if atomic.LoadInt32(&gc.shouldGossipStateInfo) == int32(0) { 402 return 403 } 404 gc.RLock() 405 stateInfoMsg := gc.stateInfoMsg 406 gc.RUnlock() 407 gc.Gossip(stateInfoMsg) 408 if len(gc.GetMembership()) > 0 { 409 atomic.StoreInt32(&gc.shouldGossipStateInfo, int32(0)) 410 } 411 } 412 413 func (gc *gossipChannel) createBlockPuller() pull.Mediator { 414 conf := pull.Config{ 415 MsgType: proto.PullMsgType_BLOCK_MSG, 416 Channel: []byte(gc.chainID), 417 ID: gc.GetConf().ID, 418 PeerCountToSelect: gc.GetConf().PullPeerNum, 419 PullInterval: gc.GetConf().PullInterval, 420 Tag: proto.GossipMessage_CHAN_AND_ORG, 421 PullEngineConfig: algo.PullEngineConfig{ 422 DigestWaitTime: gc.GetConf().DigestWaitTime, 423 RequestWaitTime: gc.GetConf().RequestWaitTime, 424 ResponseWaitTime: gc.GetConf().ResponseWaitTime, 425 }, 426 } 427 seqNumFromMsg := func(msg *protoext.SignedGossipMessage) string { 428 dataMsg := msg.GetDataMsg() 429 if dataMsg == nil || dataMsg.Payload == nil { 430 gc.logger.Warning("Non-data block or with no payload") 431 return "" 432 } 433 return fmt.Sprintf("%d", dataMsg.Payload.SeqNum) 434 } 435 adapter := &pull.PullAdapter{ 436 Sndr: gc, 437 MemSvc: gc.memFilter, 438 IdExtractor: seqNumFromMsg, 439 MsgCons: func(msg *protoext.SignedGossipMessage) { 440 gc.DeMultiplex(msg) 441 }, 442 } 443 444 adapter.IngressDigFilter = func(digestMsg *proto.DataDigest) *proto.DataDigest { 445 gc.RLock() 446 height := gc.ledgerHeight 447 gc.RUnlock() 448 digests := digestMsg.Digests 449 digestMsg.Digests = nil 450 for i := range digests { 451 seqNum, err := strconv.ParseUint(string(digests[i]), 10, 64) 452 if err != nil { 453 gc.logger.Warningf("Can't parse digest %s : %+v", digests[i], err) 454 continue 455 } 456 if seqNum >= height { 457 digestMsg.Digests = append(digestMsg.Digests, digests[i]) 458 } 459 460 } 461 return digestMsg 462 } 463 464 return pull.NewPullMediator(conf, adapter) 465 } 466 467 // IsMemberInChan checks whether the given member is eligible to be in the channel 468 func (gc *gossipChannel) IsMemberInChan(member discovery.NetworkMember) bool { 469 org := gc.GetOrgOfPeer(member.PKIid) 470 if org == nil { 471 return false 472 } 473 474 return gc.IsOrgInChannel(org) 475 } 476 477 // PeerFilter receives a SubChannelSelectionCriteria and returns a RoutingFilter that selects 478 // only peer identities that match the given criteria 479 func (gc *gossipChannel) PeerFilter(messagePredicate api.SubChannelSelectionCriteria) filter.RoutingFilter { 480 return func(member discovery.NetworkMember) bool { 481 peerIdentity := gc.GetIdentityByPKIID(member.PKIid) 482 if len(peerIdentity) == 0 { 483 return false 484 } 485 msg := gc.stateInfoMsgStore.MembershipStore.MsgByID(member.PKIid) 486 if msg == nil { 487 return false 488 } 489 490 return messagePredicate(api.PeerSignature{ 491 Message: msg.Payload, 492 Signature: msg.Signature, 493 PeerIdentity: peerIdentity, 494 }) 495 } 496 } 497 498 // IsOrgInChannel returns whether the given organization is in the channel 499 func (gc *gossipChannel) IsOrgInChannel(membersOrg api.OrgIdentityType) bool { 500 gc.RLock() 501 defer gc.RUnlock() 502 for _, orgOfChan := range gc.orgs { 503 if bytes.Equal(orgOfChan, membersOrg) { 504 return true 505 } 506 } 507 return false 508 } 509 510 // EligibleForChannel returns whether the given member should get blocks 511 // for this channel 512 func (gc *gossipChannel) EligibleForChannel(member discovery.NetworkMember) bool { 513 peerIdentity := gc.GetIdentityByPKIID(member.PKIid) 514 if len(peerIdentity) == 0 { 515 gc.logger.Warning("Identity for peer", member.PKIid, "doesn't exist") 516 return false 517 } 518 msg := gc.stateInfoMsgStore.MsgByID(member.PKIid) 519 if msg == nil { 520 return false 521 } 522 return true 523 } 524 525 // AddToMsgStore adds a given GossipMessage to the message store 526 func (gc *gossipChannel) AddToMsgStore(msg *protoext.SignedGossipMessage) { 527 if protoext.IsDataMsg(msg.GossipMessage) { 528 gc.Lock() 529 defer gc.Unlock() 530 added := gc.blockMsgStore.Add(msg) 531 if added { 532 gc.logger.Debugf("Adding %v to the block puller", msg) 533 gc.blocksPuller.Add(msg) 534 } 535 } 536 537 if protoext.IsStateInfoMsg(msg.GossipMessage) { 538 gc.stateInfoMsgStore.Add(msg) 539 } 540 } 541 542 // ConfigureChannel (re)configures the list of organizations 543 // that are eligible to be in the channel 544 func (gc *gossipChannel) ConfigureChannel(joinMsg api.JoinChannelMessage) { 545 gc.Lock() 546 defer gc.Unlock() 547 548 if len(joinMsg.Members()) == 0 { 549 gc.logger.Warning("Received join channel message with empty set of members") 550 return 551 } 552 553 if gc.joinMsg == nil { 554 gc.joinMsg = joinMsg 555 } 556 557 if gc.joinMsg.SequenceNumber() > (joinMsg.SequenceNumber()) { 558 gc.logger.Warning("Already have a more updated JoinChannel message(", gc.joinMsg.SequenceNumber(), ") than", joinMsg.SequenceNumber()) 559 return 560 } 561 562 gc.orgs = joinMsg.Members() 563 gc.joinMsg = joinMsg 564 gc.stateInfoMsgStore.validate(joinMsg.Members()) 565 } 566 567 // HandleMessage processes a message sent by a remote peer 568 func (gc *gossipChannel) HandleMessage(msg protoext.ReceivedMessage) { 569 if !gc.verifyMsg(msg) { 570 gc.logger.Warning("Failed verifying message:", msg.GetGossipMessage().GossipMessage) 571 return 572 } 573 m := msg.GetGossipMessage() 574 if !protoext.IsChannelRestricted(m.GossipMessage) { 575 gc.logger.Warning("Got message", msg.GetGossipMessage(), "but it's not a per-channel message, discarding it") 576 return 577 } 578 orgID := gc.GetOrgOfPeer(msg.GetConnectionInfo().ID) 579 if len(orgID) == 0 { 580 gc.logger.Debug("Couldn't find org identity of peer", msg.GetConnectionInfo()) 581 return 582 } 583 if !gc.IsOrgInChannel(orgID) { 584 gc.logger.Warning("Point to point message came from", msg.GetConnectionInfo(), 585 ", org(", string(orgID), ") but it's not eligible for the channel", string(gc.chainID)) 586 return 587 } 588 589 if protoext.IsStateInfoPullRequestMsg(m.GossipMessage) { 590 msg.Respond(gc.createStateInfoSnapshot(orgID)) 591 return 592 } 593 594 if protoext.IsStateInfoSnapshot(m.GossipMessage) { 595 gc.handleStateInfSnapshot(m.GossipMessage, msg.GetConnectionInfo().ID) 596 return 597 } 598 599 if protoext.IsDataMsg(m.GossipMessage) || protoext.IsStateInfoMsg(m.GossipMessage) { 600 added := false 601 602 if protoext.IsDataMsg(m.GossipMessage) { 603 if m.GetDataMsg().Payload == nil { 604 gc.logger.Warning("Payload is empty, got it from", msg.GetConnectionInfo().ID) 605 return 606 } 607 // Would this block go into the message store if it was verified? 608 if !gc.blockMsgStore.CheckValid(msg.GetGossipMessage()) { 609 return 610 } 611 if !gc.verifyBlock(m.GossipMessage, msg.GetConnectionInfo().ID) { 612 gc.logger.Warning("Failed verifying block", m.GetDataMsg().Payload.SeqNum) 613 return 614 } 615 gc.Lock() 616 added = gc.blockMsgStore.Add(msg.GetGossipMessage()) 617 if added { 618 gc.logger.Debugf("Adding %v to the block puller", msg.GetGossipMessage()) 619 gc.blocksPuller.Add(msg.GetGossipMessage()) 620 } 621 gc.Unlock() 622 } else { // StateInfoMsg verification should be handled in a layer above 623 // since we don't have access to the id mapper here 624 added = gc.stateInfoMsgStore.Add(msg.GetGossipMessage()) 625 } 626 627 if added { 628 // Forward the message 629 gc.Forward(msg) 630 // DeMultiplex to local subscribers 631 gc.DeMultiplex(m) 632 } 633 return 634 } 635 636 if protoext.IsPullMsg(m.GossipMessage) && protoext.GetPullMsgType(m.GossipMessage) == proto.PullMsgType_BLOCK_MSG { 637 if gc.hasLeftChannel() { 638 gc.logger.Info("Received Pull message from", msg.GetConnectionInfo().Endpoint, "but left the channel", string(gc.chainID)) 639 return 640 } 641 // If we don't have a StateInfo message from the peer, 642 // no way of validating its eligibility in the channel. 643 if gc.stateInfoMsgStore.MsgByID(msg.GetConnectionInfo().ID) == nil { 644 gc.logger.Debug("Don't have StateInfo message of peer", msg.GetConnectionInfo()) 645 return 646 } 647 if !gc.eligibleForChannelAndSameOrg(discovery.NetworkMember{PKIid: msg.GetConnectionInfo().ID}) { 648 gc.logger.Warning(msg.GetConnectionInfo(), "isn't eligible for pulling blocks of", string(gc.chainID)) 649 return 650 } 651 if protoext.IsDataUpdate(m.GossipMessage) { 652 // Iterate over the envelopes, and filter out blocks 653 // that we already have in the blockMsgStore, or blocks that 654 // are too far in the past. 655 var msgs []*protoext.SignedGossipMessage 656 var items []*proto.Envelope 657 filteredEnvelopes := []*proto.Envelope{} 658 for _, item := range m.GetDataUpdate().Data { 659 gMsg, err := protoext.EnvelopeToGossipMessage(item) 660 if err != nil { 661 gc.logger.Warningf("Data update contains an invalid message: %+v", err) 662 return 663 } 664 if !bytes.Equal(gMsg.Channel, []byte(gc.chainID)) { 665 gc.logger.Warning("DataUpdate message contains item with channel", gMsg.Channel, "but should be", gc.chainID) 666 return 667 } 668 // Would this block go into the message store if it was verified? 669 if !gc.blockMsgStore.CheckValid(gMsg) { 670 continue 671 } 672 if !gc.verifyBlock(gMsg.GossipMessage, msg.GetConnectionInfo().ID) { 673 return 674 } 675 msgs = append(msgs, gMsg) 676 items = append(items, item) 677 } 678 679 gc.Lock() 680 defer gc.Unlock() 681 682 for i, gMsg := range msgs { 683 item := items[i] 684 added := gc.blockMsgStore.Add(gMsg) 685 if !added { 686 // If this block doesn't need to be added, it means it either already 687 // exists in memory or that it is too far in the past 688 continue 689 } 690 filteredEnvelopes = append(filteredEnvelopes, item) 691 } 692 693 // Replace the update message with just the blocks that should be processed 694 m.GetDataUpdate().Data = filteredEnvelopes 695 } 696 gc.blocksPuller.HandleMessage(msg) 697 } 698 699 if protoext.IsLeadershipMsg(m.GossipMessage) { 700 connInfo := msg.GetConnectionInfo() 701 senderOrg := gc.GetOrgOfPeer(connInfo.ID) 702 if !bytes.Equal(gc.selfOrg, senderOrg) { 703 gc.logger.Warningf("Received leadership message from %s that belongs to a foreign organization %s", 704 connInfo.Endpoint, string(senderOrg)) 705 return 706 } 707 msgCreatorOrg := gc.GetOrgOfPeer(m.GetLeadershipMsg().PkiId) 708 if !bytes.Equal(gc.selfOrg, msgCreatorOrg) { 709 gc.logger.Warningf("Received leadership message created by a foreign organization %s", string(msgCreatorOrg)) 710 return 711 } 712 // Handling leadership message 713 added := gc.leaderMsgStore.Add(m) 714 if added { 715 gc.DeMultiplex(m) 716 } 717 } 718 } 719 720 func (gc *gossipChannel) handleStateInfSnapshot(m *proto.GossipMessage, sender common.PKIidType) { 721 chanName := string(gc.chainID) 722 for _, envelope := range m.GetStateSnapshot().Elements { 723 stateInf, err := protoext.EnvelopeToGossipMessage(envelope) 724 if err != nil { 725 gc.logger.Warningf("Channel %s : StateInfo snapshot contains an invalid message: %+v", chanName, err) 726 return 727 } 728 if !protoext.IsStateInfoMsg(stateInf.GossipMessage) { 729 gc.logger.Warning("Channel", chanName, ": Element of StateInfoSnapshot isn't a StateInfoMessage:", 730 stateInf, "message sent from", sender) 731 return 732 } 733 si := stateInf.GetStateInfo() 734 orgID := gc.GetOrgOfPeer(si.PkiId) 735 if orgID == nil { 736 gc.logger.Debug("Channel", chanName, ": Couldn't find org identity of peer", 737 string(si.PkiId), "message sent from", string(sender)) 738 return 739 } 740 741 if !gc.IsOrgInChannel(orgID) { 742 gc.logger.Warning("Channel", chanName, ": Peer", stateInf.GetStateInfo().PkiId, 743 "is not in an eligible org, can't process a stateInfo from it, sent from", sender) 744 return 745 } 746 747 expectedMAC := GenerateMAC(si.PkiId, gc.chainID) 748 if !bytes.Equal(si.Channel_MAC, expectedMAC) { 749 gc.logger.Warning("Channel", chanName, ": StateInfo message", stateInf, 750 ", has an invalid MAC. Expected", expectedMAC, ", got", si.Channel_MAC, ", sent from", sender) 751 return 752 } 753 err = gc.ValidateStateInfoMessage(stateInf) 754 if err != nil { 755 gc.logger.Warningf("Channel %s: Failed validating state info message: %v sent from %v : %+v", chanName, stateInf, sender, err) 756 return 757 } 758 759 if gc.Lookup(si.PkiId) == nil { 760 // Skip StateInfo messages that belong to peers 761 // that have been expired 762 continue 763 } 764 765 gc.stateInfoMsgStore.Add(stateInf) 766 } 767 } 768 769 func (gc *gossipChannel) verifyBlock(msg *proto.GossipMessage, sender common.PKIidType) bool { 770 if !protoext.IsDataMsg(msg) { 771 gc.logger.Warning("Received from ", sender, "a DataUpdate message that contains a non-block GossipMessage:", msg) 772 return false 773 } 774 payload := msg.GetDataMsg().Payload 775 if payload == nil { 776 gc.logger.Warning("Received empty payload from", sender) 777 return false 778 } 779 seqNum := payload.SeqNum 780 rawBlock := payload.Data 781 block, err := protoutil.UnmarshalBlock(rawBlock) 782 if err != nil { 783 gc.logger.Warningf("Received improperly encoded block from %v in DataUpdate: %+v", sender, err) 784 return false 785 } 786 787 err = gc.mcs.VerifyBlock(msg.Channel, seqNum, block) 788 if err != nil { 789 gc.logger.Warningf("Received fabricated block from %v in DataUpdate: %+v", sender, err) 790 return false 791 } 792 return true 793 } 794 795 func (gc *gossipChannel) createStateInfoSnapshot(requestersOrg api.OrgIdentityType) *proto.GossipMessage { 796 sameOrg := bytes.Equal(gc.selfOrg, requestersOrg) 797 rawElements := gc.stateInfoMsgStore.Get() 798 elements := []*proto.Envelope{} 799 for _, rawEl := range rawElements { 800 msg := rawEl.(*protoext.SignedGossipMessage) 801 orgOfCurrentMsg := gc.GetOrgOfPeer(msg.GetStateInfo().PkiId) 802 // If we're in the same org as the requester, or the message belongs to a foreign org 803 // don't do any filtering 804 if sameOrg || !bytes.Equal(orgOfCurrentMsg, gc.selfOrg) { 805 elements = append(elements, msg.Envelope) 806 continue 807 } 808 // Else, the requester is in a different org, so disclose only StateInfo messages that their 809 // corresponding AliveMessages have external endpoints 810 if netMember := gc.Lookup(msg.GetStateInfo().PkiId); netMember == nil || netMember.Endpoint == "" { 811 continue 812 } 813 elements = append(elements, msg.Envelope) 814 } 815 816 return &proto.GossipMessage{ 817 Channel: gc.chainID, 818 Tag: proto.GossipMessage_CHAN_OR_ORG, 819 Nonce: 0, 820 Content: &proto.GossipMessage_StateSnapshot{ 821 StateSnapshot: &proto.StateInfoSnapshot{ 822 Elements: elements, 823 }, 824 }, 825 } 826 } 827 828 func (gc *gossipChannel) verifyMsg(msg protoext.ReceivedMessage) bool { 829 if msg == nil { 830 gc.logger.Warning("Messsage is nil") 831 return false 832 } 833 m := msg.GetGossipMessage() 834 if m == nil { 835 gc.logger.Warning("Message content is empty") 836 return false 837 } 838 839 if msg.GetConnectionInfo().ID == nil { 840 gc.logger.Warning("Message has nil PKI-ID") 841 return false 842 } 843 844 if protoext.IsStateInfoMsg(m.GossipMessage) { 845 si := m.GetStateInfo() 846 expectedMAC := GenerateMAC(si.PkiId, gc.chainID) 847 if !bytes.Equal(expectedMAC, si.Channel_MAC) { 848 gc.logger.Warning("Message contains wrong channel MAC(", si.Channel_MAC, "), expected", expectedMAC) 849 return false 850 } 851 return true 852 } 853 854 if protoext.IsStateInfoPullRequestMsg(m.GossipMessage) { 855 sipr := m.GetStateInfoPullReq() 856 expectedMAC := GenerateMAC(msg.GetConnectionInfo().ID, gc.chainID) 857 if !bytes.Equal(expectedMAC, sipr.Channel_MAC) { 858 gc.logger.Warning("Message contains wrong channel MAC(", sipr.Channel_MAC, "), expected", expectedMAC) 859 return false 860 } 861 return true 862 } 863 864 if !bytes.Equal(m.Channel, []byte(gc.chainID)) { 865 gc.logger.Warning("Message contains wrong channel(", m.Channel, "), expected", gc.chainID) 866 return false 867 } 868 return true 869 } 870 871 func (gc *gossipChannel) createStateInfoRequest() (*protoext.SignedGossipMessage, error) { 872 return protoext.NoopSign(&proto.GossipMessage{ 873 Tag: proto.GossipMessage_CHAN_OR_ORG, 874 Nonce: 0, 875 Content: &proto.GossipMessage_StateInfoPullReq{ 876 StateInfoPullReq: &proto.StateInfoPullRequest{ 877 Channel_MAC: GenerateMAC(gc.pkiID, gc.chainID), 878 }, 879 }, 880 }) 881 } 882 883 // UpdateLedgerHeight updates the ledger height the peer 884 // publishes to other peers in the channel 885 func (gc *gossipChannel) UpdateLedgerHeight(height uint64) { 886 gc.Lock() 887 defer gc.Unlock() 888 889 var chaincodes []*proto.Chaincode 890 var leftChannel bool 891 if prevMsg := gc.stateInfoMsg; prevMsg != nil { 892 leftChannel = prevMsg.GetStateInfo().Properties.LeftChannel 893 chaincodes = prevMsg.GetStateInfo().Properties.Chaincodes 894 } 895 gc.updateProperties(height, chaincodes, leftChannel) 896 } 897 898 // UpdateChaincodes updates the chaincodes the peer publishes 899 // to other peers in the channel 900 func (gc *gossipChannel) UpdateChaincodes(chaincodes []*proto.Chaincode) { 901 gc.Lock() 902 defer gc.Unlock() 903 904 var ledgerHeight uint64 = 1 905 var leftChannel bool 906 if prevMsg := gc.stateInfoMsg; prevMsg != nil { 907 ledgerHeight = prevMsg.GetStateInfo().Properties.LedgerHeight 908 leftChannel = prevMsg.GetStateInfo().Properties.LeftChannel 909 } 910 gc.updateProperties(ledgerHeight, chaincodes, leftChannel) 911 } 912 913 // UpdateStateInfo updates this channel's StateInfo message 914 // that is periodically published 915 func (gc *gossipChannel) updateStateInfo(msg *protoext.SignedGossipMessage) { 916 gc.stateInfoMsgStore.Add(msg) 917 gc.ledgerHeight = msg.GetStateInfo().Properties.LedgerHeight 918 gc.stateInfoMsg = msg 919 atomic.StoreInt32(&gc.shouldGossipStateInfo, int32(1)) 920 } 921 922 func (gc *gossipChannel) updateProperties(ledgerHeight uint64, chaincodes []*proto.Chaincode, leftChannel bool) { 923 stateInfMsg := &proto.StateInfo{ 924 Channel_MAC: GenerateMAC(gc.pkiID, gc.chainID), 925 PkiId: gc.pkiID, 926 Timestamp: &proto.PeerTime{ 927 IncNum: gc.incTime, 928 SeqNum: uint64(time.Now().UnixNano()), 929 }, 930 Properties: &proto.Properties{ 931 LeftChannel: leftChannel, 932 LedgerHeight: ledgerHeight, 933 Chaincodes: chaincodes, 934 }, 935 } 936 m := &proto.GossipMessage{ 937 Nonce: 0, 938 Tag: proto.GossipMessage_CHAN_OR_ORG, 939 Content: &proto.GossipMessage_StateInfo{ 940 StateInfo: stateInfMsg, 941 }, 942 } 943 944 msg, err := gc.Sign(m) 945 if err != nil { 946 gc.logger.Error("Failed signing message:", err) 947 return 948 } 949 gc.updateStateInfo(msg) 950 } 951 952 func newStateInfoCache(sweepInterval time.Duration, hasExpired func(interface{}) bool, verifyFunc membershipPredicate) *stateInfoCache { 953 membershipStore := util.NewMembershipStore() 954 pol := protoext.NewGossipMessageComparator(0) 955 956 s := &stateInfoCache{ 957 verify: verifyFunc, 958 MembershipStore: membershipStore, 959 stopChan: make(chan struct{}), 960 } 961 invalidationTrigger := func(m interface{}) { 962 pkiID := m.(*protoext.SignedGossipMessage).GetStateInfo().PkiId 963 membershipStore.Remove(pkiID) 964 } 965 s.MessageStore = msgstore.NewMessageStore(pol, invalidationTrigger) 966 967 go func() { 968 for { 969 select { 970 case <-s.stopChan: 971 return 972 case <-time.After(sweepInterval): 973 s.Purge(hasExpired) 974 } 975 } 976 }() 977 return s 978 } 979 980 // membershipPredicate receives a StateInfoMessage and optionally a slice of organization identifiers 981 // and returns whether the peer that signed the given StateInfoMessage is eligible 982 // to the channel or not 983 type membershipPredicate func(msg *protoext.SignedGossipMessage, orgs ...api.OrgIdentityType) bool 984 985 // stateInfoCache is actually a messageStore 986 // that also indexes messages that are added 987 // so that they could be extracted later 988 type stateInfoCache struct { 989 verify membershipPredicate 990 *util.MembershipStore 991 msgstore.MessageStore 992 stopChan chan struct{} 993 } 994 995 func (cache *stateInfoCache) validate(orgs []api.OrgIdentityType) { 996 for _, m := range cache.Get() { 997 msg := m.(*protoext.SignedGossipMessage) 998 if !cache.verify(msg, orgs...) { 999 cache.delete(msg) 1000 } 1001 } 1002 } 1003 1004 // Add attempts to add the given message to the stateInfoCache, 1005 // and if the message was added, also indexes it. 1006 // Message must be a StateInfo message. 1007 func (cache *stateInfoCache) Add(msg *protoext.SignedGossipMessage) bool { 1008 if !cache.MessageStore.CheckValid(msg) { 1009 return false 1010 } 1011 if !cache.verify(msg) { 1012 return false 1013 } 1014 added := cache.MessageStore.Add(msg) 1015 if added { 1016 pkiID := msg.GetStateInfo().PkiId 1017 cache.MembershipStore.Put(pkiID, msg) 1018 } 1019 return added 1020 } 1021 1022 func (cache *stateInfoCache) delete(msg *protoext.SignedGossipMessage) { 1023 cache.Purge(func(o interface{}) bool { 1024 pkiID := o.(*protoext.SignedGossipMessage).GetStateInfo().PkiId 1025 return bytes.Equal(pkiID, msg.GetStateInfo().PkiId) 1026 }) 1027 cache.Remove(msg.GetStateInfo().PkiId) 1028 } 1029 1030 func (cache *stateInfoCache) Stop() { 1031 cache.stopChan <- struct{}{} 1032 } 1033 1034 // GenerateMAC returns a byte slice that is derived from the peer's PKI-ID 1035 // and a channel name 1036 func GenerateMAC(pkiID common.PKIidType, channelID common.ChannelID) []byte { 1037 // Hash is computed on (PKI-ID || channel ID) 1038 var preImage []byte 1039 preImage = append(preImage, []byte(pkiID)...) 1040 preImage = append(preImage, []byte(channelID)...) 1041 return common_utils.ComputeSHA256(preImage) 1042 } 1043 1044 //membershipTracker is a struct for tracking changes in peers of the channel 1045 type membershipTracker struct { 1046 getPeersToTrack func() []discovery.NetworkMember 1047 report func(...interface{}) 1048 stopChan chan struct{} 1049 tickerChannel <-chan time.Time 1050 metrics *metrics.MembershipMetrics 1051 chainID common.ChannelID 1052 } 1053 1054 //endpoints return all peers by their endpoints 1055 func endpoints(members discovery.Members) [][]string { 1056 var currView [][]string 1057 for _, member := range members { 1058 ep := member.Endpoint 1059 epi := member.InternalEndpoint 1060 var endPoints []string 1061 if ep != epi { 1062 endPoints = append(endPoints, ep, epi) 1063 } else { 1064 endPoints = append(endPoints, ep) 1065 } 1066 currView = append(currView, endPoints) 1067 } 1068 return currView 1069 } 1070 1071 //checkIfPeersChanged checks which peers are offline and which are online for channel 1072 func (mt *membershipTracker) checkIfPeersChanged(prevPeers discovery.Members, currPeers discovery.Members, 1073 prevSetPeers map[string]struct{}, currSetPeers map[string]struct{}) { 1074 var currView [][]string 1075 1076 wereInPrev := endpoints(prevPeers.Filter(func(member discovery.NetworkMember) bool { 1077 _, exists := currSetPeers[string(member.PKIid)] 1078 return !exists 1079 })) 1080 newInCurr := endpoints(currPeers.Filter(func(member discovery.NetworkMember) bool { 1081 _, exists := prevSetPeers[string(member.PKIid)] 1082 return !exists 1083 })) 1084 currView = endpoints(currPeers) 1085 1086 if !reflect.DeepEqual(wereInPrev, newInCurr) { 1087 if len(wereInPrev) == 0 { 1088 mt.report("Membership view has changed. peers went online: ", newInCurr, ", current view: ", currView) 1089 } else if len(newInCurr) == 0 { 1090 mt.report("Membership view has changed. peers went offline: ", wereInPrev, ", current view: ", currView) 1091 } else { 1092 mt.report("Membership view has changed. peers went offline: ", wereInPrev, ", peers went online: ", newInCurr, ", current view: ", currView) 1093 } 1094 } 1095 } 1096 1097 func (mt *membershipTracker) createSetOfPeers(peersToMakeSet []discovery.NetworkMember) map[string]struct{} { 1098 setPeers := make(map[string]struct{}) 1099 for _, prevPeer := range peersToMakeSet { 1100 prevPeerID := string(prevPeer.PKIid) 1101 setPeers[prevPeerID] = struct{}{} 1102 } 1103 return setPeers 1104 } 1105 1106 func (mt *membershipTracker) trackMembershipChanges() { 1107 prev := mt.getPeersToTrack() 1108 prevSetPeers := mt.createSetOfPeers(prev) 1109 for { 1110 //timeout to check changes in peers 1111 select { 1112 case <-mt.stopChan: 1113 return 1114 case <-mt.tickerChannel: 1115 currPeers := mt.getPeersToTrack() 1116 mt.metrics.Total.With("channel", string(mt.chainID)).Set(float64(len(currPeers))) 1117 currSetPeers := mt.createSetOfPeers(currPeers) 1118 mt.checkIfPeersChanged(prev, currPeers, prevSetPeers, currSetPeers) 1119 prev = currPeers 1120 prevSetPeers = mt.createSetOfPeers(prev) 1121 } 1122 } 1123 }