github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/gossip/service/gossip_service.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package service 8 9 import ( 10 "sync" 11 12 gproto "github.com/hyperledger/fabric-protos-go/gossip" 13 tspb "github.com/hyperledger/fabric-protos-go/transientstore" 14 corecomm "github.com/hyperledger/fabric/core/comm" 15 "github.com/hyperledger/fabric/core/committer" 16 "github.com/hyperledger/fabric/core/committer/txvalidator" 17 "github.com/hyperledger/fabric/core/common/privdata" 18 "github.com/hyperledger/fabric/core/deliverservice" 19 "github.com/hyperledger/fabric/core/transientstore" 20 "github.com/hyperledger/fabric/gossip/api" 21 "github.com/hyperledger/fabric/gossip/comm" 22 "github.com/hyperledger/fabric/gossip/common" 23 gossipcommon "github.com/hyperledger/fabric/gossip/common" 24 "github.com/hyperledger/fabric/gossip/discovery" 25 "github.com/hyperledger/fabric/gossip/election" 26 "github.com/hyperledger/fabric/gossip/filter" 27 "github.com/hyperledger/fabric/gossip/gossip" 28 gossipmetrics "github.com/hyperledger/fabric/gossip/metrics" 29 gossipprivdata "github.com/hyperledger/fabric/gossip/privdata" 30 "github.com/hyperledger/fabric/gossip/protoext" 31 "github.com/hyperledger/fabric/gossip/state" 32 "github.com/hyperledger/fabric/gossip/util" 33 "github.com/hyperledger/fabric/internal/pkg/identity" 34 "github.com/hyperledger/fabric/internal/pkg/peer/blocksprovider" 35 "github.com/hyperledger/fabric/internal/pkg/peer/orderers" 36 "github.com/hyperledger/fabric/protoutil" 37 "github.com/pkg/errors" 38 "google.golang.org/grpc" 39 ) 40 41 // gossipSvc is the interface of the gossip component. 42 type gossipSvc interface { 43 // SelfMembershipInfo returns the peer's membership information 44 SelfMembershipInfo() discovery.NetworkMember 45 46 // SelfChannelInfo returns the peer's latest StateInfo message of a given channel 47 SelfChannelInfo(common.ChannelID) *protoext.SignedGossipMessage 48 49 // Send sends a message to remote peers 50 Send(msg *gproto.GossipMessage, peers ...*comm.RemotePeer) 51 52 // SendByCriteria sends a given message to all peers that match the given SendCriteria 53 SendByCriteria(*protoext.SignedGossipMessage, gossip.SendCriteria) error 54 55 // GetPeers returns the NetworkMembers considered alive 56 Peers() []discovery.NetworkMember 57 58 // PeersOfChannel returns the NetworkMembers considered alive 59 // and also subscribed to the channel given 60 PeersOfChannel(common.ChannelID) []discovery.NetworkMember 61 62 // UpdateMetadata updates the self metadata of the discovery layer 63 // the peer publishes to other peers 64 UpdateMetadata(metadata []byte) 65 66 // UpdateLedgerHeight updates the ledger height the peer 67 // publishes to other peers in the channel 68 UpdateLedgerHeight(height uint64, channelID common.ChannelID) 69 70 // UpdateChaincodes updates the chaincodes the peer publishes 71 // to other peers in the channel 72 UpdateChaincodes(chaincode []*gproto.Chaincode, channelID common.ChannelID) 73 74 // Gossip sends a message to other peers to the network 75 Gossip(msg *gproto.GossipMessage) 76 77 // PeerFilter receives a SubChannelSelectionCriteria and returns a RoutingFilter that selects 78 // only peer identities that match the given criteria, and that they published their channel participation 79 PeerFilter(channel common.ChannelID, messagePredicate api.SubChannelSelectionCriteria) (filter.RoutingFilter, error) 80 81 // Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate. 82 // If passThrough is false, the messages are processed by the gossip layer beforehand. 83 // If passThrough is true, the gossip layer doesn't intervene and the messages 84 // can be used to send a reply back to the sender 85 Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *gproto.GossipMessage, <-chan protoext.ReceivedMessage) 86 87 // JoinChan makes the Gossip instance join a channel 88 JoinChan(joinMsg api.JoinChannelMessage, channelID common.ChannelID) 89 90 // LeaveChan makes the Gossip instance leave a channel. 91 // It still disseminates stateInfo message, but doesn't participate 92 // in block pulling anymore, and can't return anymore a list of peers 93 // in the channel. 94 LeaveChan(channelID common.ChannelID) 95 96 // SuspectPeers makes the gossip instance validate identities of suspected peers, and close 97 // any connections to peers with identities that are found invalid 98 SuspectPeers(s api.PeerSuspector) 99 100 // IdentityInfo returns information known peer identities 101 IdentityInfo() api.PeerIdentitySet 102 103 // IsInMyOrg checks whether a network member is in this peer's org 104 IsInMyOrg(member discovery.NetworkMember) bool 105 106 // Stop stops the gossip component 107 Stop() 108 } 109 110 // GossipServiceAdapter serves to provide basic functionality 111 // required from gossip service by delivery service 112 type GossipServiceAdapter interface { 113 // PeersOfChannel returns slice with members of specified channel 114 PeersOfChannel(gossipcommon.ChannelID) []discovery.NetworkMember 115 116 // AddPayload adds payload to the local state sync buffer 117 AddPayload(channelID string, payload *gproto.Payload) error 118 119 // Gossip the message across the peers 120 Gossip(msg *gproto.GossipMessage) 121 } 122 123 // DeliveryServiceFactory factory to create and initialize delivery service instance 124 type DeliveryServiceFactory interface { 125 // Returns an instance of delivery client 126 Service(g GossipServiceAdapter, ordererSource *orderers.ConnectionSource, msc api.MessageCryptoService, isStaticLead bool) deliverservice.DeliverService 127 } 128 129 type deliveryFactoryImpl struct { 130 signer identity.SignerSerializer 131 credentialSupport *corecomm.CredentialSupport 132 deliverGRPCClient *corecomm.GRPCClient 133 deliverServiceConfig *deliverservice.DeliverServiceConfig 134 } 135 136 // Returns an instance of delivery client 137 func (df *deliveryFactoryImpl) Service(g GossipServiceAdapter, ordererSource *orderers.ConnectionSource, mcs api.MessageCryptoService, isStaticLeader bool) deliverservice.DeliverService { 138 return deliverservice.NewDeliverService(&deliverservice.Config{ 139 IsStaticLeader: isStaticLeader, 140 CryptoSvc: mcs, 141 Gossip: g, 142 Signer: df.signer, 143 DeliverGRPCClient: df.deliverGRPCClient, 144 DeliverServiceConfig: df.deliverServiceConfig, 145 OrdererSource: ordererSource, 146 }) 147 } 148 149 type privateHandler struct { 150 support Support 151 coordinator gossipprivdata.Coordinator 152 distributor gossipprivdata.PvtDataDistributor 153 reconciler gossipprivdata.PvtDataReconciler 154 } 155 156 func (p privateHandler) close() { 157 p.coordinator.Close() 158 p.reconciler.Stop() 159 } 160 161 type GossipService struct { 162 gossipSvc 163 privateHandlers map[string]privateHandler 164 chains map[string]state.GossipStateProvider 165 leaderElection map[string]election.LeaderElectionService 166 deliveryService map[string]deliverservice.DeliverService 167 deliveryFactory DeliveryServiceFactory 168 lock sync.RWMutex 169 mcs api.MessageCryptoService 170 peerIdentity []byte 171 secAdv api.SecurityAdvisor 172 metrics *gossipmetrics.GossipMetrics 173 serviceConfig *ServiceConfig 174 } 175 176 // This is an implementation of api.JoinChannelMessage. 177 type joinChannelMessage struct { 178 seqNum uint64 179 members2AnchorPeers map[string][]api.AnchorPeer 180 } 181 182 func (jcm *joinChannelMessage) SequenceNumber() uint64 { 183 return jcm.seqNum 184 } 185 186 // Members returns the organizations of the channel 187 func (jcm *joinChannelMessage) Members() []api.OrgIdentityType { 188 members := make([]api.OrgIdentityType, 0, len(jcm.members2AnchorPeers)) 189 for org := range jcm.members2AnchorPeers { 190 members = append(members, api.OrgIdentityType(org)) 191 } 192 return members 193 } 194 195 // AnchorPeersOf returns the anchor peers of the given organization 196 func (jcm *joinChannelMessage) AnchorPeersOf(org api.OrgIdentityType) []api.AnchorPeer { 197 return jcm.members2AnchorPeers[string(org)] 198 } 199 200 var logger = util.GetLogger(util.ServiceLogger, "") 201 202 // New creates the gossip service. 203 func New( 204 peerIdentity identity.SignerSerializer, 205 gossipMetrics *gossipmetrics.GossipMetrics, 206 endpoint string, 207 s *grpc.Server, 208 mcs api.MessageCryptoService, 209 secAdv api.SecurityAdvisor, 210 secureDialOpts api.PeerSecureDialOpts, 211 credSupport *corecomm.CredentialSupport, 212 deliverGRPCClient *corecomm.GRPCClient, 213 gossipConfig *gossip.Config, 214 serviceConfig *ServiceConfig, 215 deliverServiceConfig *deliverservice.DeliverServiceConfig, 216 ) (*GossipService, error) { 217 serializedIdentity, err := peerIdentity.Serialize() 218 if err != nil { 219 return nil, err 220 } 221 222 logger.Infof("Initialize gossip with endpoint %s", endpoint) 223 224 gossipComponent := gossip.New( 225 gossipConfig, 226 s, 227 secAdv, 228 mcs, 229 serializedIdentity, 230 secureDialOpts, 231 gossipMetrics, 232 ) 233 234 return &GossipService{ 235 gossipSvc: gossipComponent, 236 mcs: mcs, 237 privateHandlers: make(map[string]privateHandler), 238 chains: make(map[string]state.GossipStateProvider), 239 leaderElection: make(map[string]election.LeaderElectionService), 240 deliveryService: make(map[string]deliverservice.DeliverService), 241 deliveryFactory: &deliveryFactoryImpl{ 242 signer: peerIdentity, 243 credentialSupport: credSupport, 244 deliverGRPCClient: deliverGRPCClient, 245 deliverServiceConfig: deliverServiceConfig, 246 }, 247 peerIdentity: serializedIdentity, 248 secAdv: secAdv, 249 metrics: gossipMetrics, 250 serviceConfig: serviceConfig, 251 }, nil 252 } 253 254 // DistributePrivateData distribute private read write set inside the channel based on the collections policies 255 func (g *GossipService) DistributePrivateData(channelID string, txID string, privData *tspb.TxPvtReadWriteSetWithConfigInfo, blkHt uint64) error { 256 g.lock.RLock() 257 handler, exists := g.privateHandlers[channelID] 258 g.lock.RUnlock() 259 if !exists { 260 return errors.Errorf("No private data handler for %s", channelID) 261 } 262 263 if err := handler.distributor.Distribute(txID, privData, blkHt); err != nil { 264 logger.Error("Failed to distributed private collection, txID", txID, "channel", channelID, "due to", err) 265 return err 266 } 267 268 if err := handler.coordinator.StorePvtData(txID, privData, blkHt); err != nil { 269 logger.Error("Failed to store private data into transient store, txID", 270 txID, "channel", channelID, "due to", err) 271 return err 272 } 273 return nil 274 } 275 276 // NewConfigEventer creates a ConfigProcessor which the channelconfig.BundleSource can ultimately route config updates to 277 func (g *GossipService) NewConfigEventer() ConfigProcessor { 278 return newConfigEventer(g) 279 } 280 281 // Support aggregates functionality of several 282 // interfaces required by gossip service 283 type Support struct { 284 Validator txvalidator.Validator 285 Committer committer.Committer 286 CollectionStore privdata.CollectionStore 287 IdDeserializeFactory gossipprivdata.IdentityDeserializerFactory 288 CapabilityProvider gossipprivdata.CapabilityProvider 289 } 290 291 // InitializeChannel allocates the state provider and should be invoked once per channel per execution 292 func (g *GossipService) InitializeChannel(channelID string, ordererSource *orderers.ConnectionSource, store *transientstore.Store, support Support) { 293 g.lock.Lock() 294 defer g.lock.Unlock() 295 // Initialize new state provider for given committer 296 logger.Debug("Creating state provider for channelID", channelID) 297 servicesAdapter := &state.ServicesMediator{GossipAdapter: g, MCSAdapter: g.mcs} 298 299 // Initialize private data fetcher 300 dataRetriever := gossipprivdata.NewDataRetriever(store, support.Committer) 301 collectionAccessFactory := gossipprivdata.NewCollectionAccessFactory(support.IdDeserializeFactory) 302 fetcher := gossipprivdata.NewPuller(g.metrics.PrivdataMetrics, support.CollectionStore, g.gossipSvc, dataRetriever, 303 collectionAccessFactory, channelID, g.serviceConfig.BtlPullMargin) 304 305 coordinatorConfig := gossipprivdata.CoordinatorConfig{ 306 TransientBlockRetention: g.serviceConfig.TransientstoreMaxBlockRetention, 307 PullRetryThreshold: g.serviceConfig.PvtDataPullRetryThreshold, 308 SkipPullingInvalidTransactions: g.serviceConfig.SkipPullingInvalidTransactionsDuringCommit, 309 } 310 coordinator := gossipprivdata.NewCoordinator(gossipprivdata.Support{ 311 ChainID: channelID, 312 CollectionStore: support.CollectionStore, 313 Validator: support.Validator, 314 Committer: support.Committer, 315 Fetcher: fetcher, 316 CapabilityProvider: support.CapabilityProvider, 317 }, store, g.createSelfSignedData(), g.metrics.PrivdataMetrics, coordinatorConfig, 318 support.IdDeserializeFactory) 319 320 privdataConfig := gossipprivdata.GlobalConfig() 321 var reconciler gossipprivdata.PvtDataReconciler 322 323 if privdataConfig.ReconciliationEnabled { 324 reconciler = gossipprivdata.NewReconciler(channelID, g.metrics.PrivdataMetrics, 325 support.Committer, fetcher, privdataConfig) 326 } else { 327 reconciler = &gossipprivdata.NoOpReconciler{} 328 } 329 330 pushAckTimeout := g.serviceConfig.PvtDataPushAckTimeout 331 g.privateHandlers[channelID] = privateHandler{ 332 support: support, 333 coordinator: coordinator, 334 distributor: gossipprivdata.NewDistributor(channelID, g, collectionAccessFactory, g.metrics.PrivdataMetrics, pushAckTimeout), 335 reconciler: reconciler, 336 } 337 g.privateHandlers[channelID].reconciler.Start() 338 339 blockingMode := !g.serviceConfig.NonBlockingCommitMode 340 stateConfig := state.GlobalConfig() 341 g.chains[channelID] = state.NewGossipStateProvider( 342 channelID, 343 servicesAdapter, 344 coordinator, 345 g.metrics.StateMetrics, 346 blockingMode, 347 stateConfig) 348 if g.deliveryService[channelID] == nil { 349 g.deliveryService[channelID] = g.deliveryFactory.Service(g, ordererSource, g.mcs, g.serviceConfig.OrgLeader) 350 } 351 352 // Delivery service might be nil only if it was not able to get connected 353 // to the ordering service 354 if g.deliveryService[channelID] != nil { 355 // Parameters: 356 // - peer.gossip.useLeaderElection 357 // - peer.gossip.orgLeader 358 // 359 // are mutual exclusive, setting both to true is not defined, hence 360 // peer will panic and terminate 361 leaderElection := g.serviceConfig.UseLeaderElection 362 isStaticOrgLeader := g.serviceConfig.OrgLeader 363 364 if leaderElection && isStaticOrgLeader { 365 logger.Panic("Setting both orgLeader and useLeaderElection to true isn't supported, aborting execution") 366 } 367 368 if leaderElection { 369 logger.Debug("Delivery uses dynamic leader election mechanism, channel", channelID) 370 g.leaderElection[channelID] = g.newLeaderElectionComponent(channelID, g.onStatusChangeFactory(channelID, 371 support.Committer), g.metrics.ElectionMetrics) 372 } else if isStaticOrgLeader { 373 logger.Debug("This peer is configured to connect to ordering service for blocks delivery, channel", channelID) 374 g.deliveryService[channelID].StartDeliverForChannel(channelID, support.Committer, func() {}) 375 } else { 376 logger.Debug("This peer is not configured to connect to ordering service for blocks delivery, channel", channelID) 377 } 378 } else { 379 logger.Warning("Delivery client is down won't be able to pull blocks for chain", channelID) 380 } 381 382 } 383 384 func (g *GossipService) createSelfSignedData() protoutil.SignedData { 385 msg := make([]byte, 32) 386 sig, err := g.mcs.Sign(msg) 387 if err != nil { 388 logger.Panicf("Failed creating self signed data because message signing failed: %v", err) 389 } 390 return protoutil.SignedData{ 391 Data: msg, 392 Signature: sig, 393 Identity: g.peerIdentity, 394 } 395 } 396 397 // updateAnchors constructs a joinChannelMessage and sends it to the gossipSvc 398 func (g *GossipService) updateAnchors(config Config) { 399 myOrg := string(g.secAdv.OrgByPeerIdentity(api.PeerIdentityType(g.peerIdentity))) 400 if !g.amIinChannel(myOrg, config) { 401 logger.Error("Tried joining channel", config.ChannelID(), "but our org(", myOrg, "), isn't "+ 402 "among the orgs of the channel:", orgListFromConfig(config), ", aborting.") 403 return 404 } 405 jcm := &joinChannelMessage{seqNum: config.Sequence(), members2AnchorPeers: map[string][]api.AnchorPeer{}} 406 for _, appOrg := range config.Organizations() { 407 logger.Debug(appOrg.MSPID(), "anchor peers:", appOrg.AnchorPeers()) 408 jcm.members2AnchorPeers[appOrg.MSPID()] = []api.AnchorPeer{} 409 for _, ap := range appOrg.AnchorPeers() { 410 anchorPeer := api.AnchorPeer{ 411 Host: ap.Host, 412 Port: int(ap.Port), 413 } 414 jcm.members2AnchorPeers[appOrg.MSPID()] = append(jcm.members2AnchorPeers[appOrg.MSPID()], anchorPeer) 415 } 416 } 417 418 // Initialize new state provider for given committer 419 logger.Debug("Creating state provider for channelID", config.ChannelID()) 420 g.JoinChan(jcm, gossipcommon.ChannelID(config.ChannelID())) 421 } 422 423 // AddPayload appends message payload to for given chain 424 func (g *GossipService) AddPayload(channelID string, payload *gproto.Payload) error { 425 g.lock.RLock() 426 defer g.lock.RUnlock() 427 return g.chains[channelID].AddPayload(payload) 428 } 429 430 // Stop stops the gossip component 431 func (g *GossipService) Stop() { 432 g.lock.Lock() 433 defer g.lock.Unlock() 434 435 for chainID := range g.chains { 436 logger.Info("Stopping chain", chainID) 437 if le, exists := g.leaderElection[chainID]; exists { 438 logger.Infof("Stopping leader election for %s", chainID) 439 le.Stop() 440 } 441 g.chains[chainID].Stop() 442 g.privateHandlers[chainID].close() 443 444 if g.deliveryService[chainID] != nil { 445 g.deliveryService[chainID].Stop() 446 } 447 } 448 g.gossipSvc.Stop() 449 } 450 451 func (g *GossipService) newLeaderElectionComponent(channelID string, callback func(bool), 452 electionMetrics *gossipmetrics.ElectionMetrics) election.LeaderElectionService { 453 PKIid := g.mcs.GetPKIidOfCert(g.peerIdentity) 454 adapter := election.NewAdapter(g, PKIid, gossipcommon.ChannelID(channelID), electionMetrics) 455 config := election.ElectionConfig{ 456 StartupGracePeriod: g.serviceConfig.ElectionStartupGracePeriod, 457 MembershipSampleInterval: g.serviceConfig.ElectionMembershipSampleInterval, 458 LeaderAliveThreshold: g.serviceConfig.ElectionLeaderAliveThreshold, 459 LeaderElectionDuration: g.serviceConfig.ElectionLeaderElectionDuration, 460 } 461 return election.NewLeaderElectionService(adapter, string(PKIid), callback, config) 462 } 463 464 func (g *GossipService) amIinChannel(myOrg string, config Config) bool { 465 for _, orgName := range orgListFromConfig(config) { 466 if orgName == myOrg { 467 return true 468 } 469 } 470 return false 471 } 472 473 func (g *GossipService) onStatusChangeFactory(channelID string, committer blocksprovider.LedgerInfo) func(bool) { 474 return func(isLeader bool) { 475 if isLeader { 476 yield := func() { 477 g.lock.RLock() 478 le := g.leaderElection[channelID] 479 g.lock.RUnlock() 480 le.Yield() 481 } 482 logger.Info("Elected as a leader, starting delivery service for channel", channelID) 483 if err := g.deliveryService[channelID].StartDeliverForChannel(channelID, committer, yield); err != nil { 484 logger.Errorf("Delivery service is not able to start blocks delivery for chain, due to %+v", err) 485 } 486 } else { 487 logger.Info("Renounced leadership, stopping delivery service for channel", channelID) 488 if err := g.deliveryService[channelID].StopDeliverForChannel(channelID); err != nil { 489 logger.Errorf("Delivery service is not able to stop blocks delivery for chain, due to %+v", err) 490 } 491 } 492 } 493 } 494 495 func orgListFromConfig(config Config) []string { 496 var orgList []string 497 for _, appOrg := range config.Organizations() { 498 orgList = append(orgList, appOrg.MSPID()) 499 } 500 return orgList 501 }