github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/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) 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) deliverservice.DeliverService { 138 return deliverservice.NewDeliverService(&deliverservice.Config{ 139 CryptoSvc: mcs, 140 Gossip: g, 141 Signer: df.signer, 142 DeliverGRPCClient: df.deliverGRPCClient, 143 DeliverServiceConfig: df.deliverServiceConfig, 144 OrdererSource: ordererSource, 145 }) 146 } 147 148 type privateHandler struct { 149 support Support 150 coordinator gossipprivdata.Coordinator 151 distributor gossipprivdata.PvtDataDistributor 152 reconciler gossipprivdata.PvtDataReconciler 153 } 154 155 func (p privateHandler) close() { 156 p.coordinator.Close() 157 p.reconciler.Stop() 158 } 159 160 type GossipService struct { 161 gossipSvc 162 privateHandlers map[string]privateHandler 163 chains map[string]state.GossipStateProvider 164 leaderElection map[string]election.LeaderElectionService 165 deliveryService map[string]deliverservice.DeliverService 166 deliveryFactory DeliveryServiceFactory 167 lock sync.RWMutex 168 mcs api.MessageCryptoService 169 peerIdentity []byte 170 secAdv api.SecurityAdvisor 171 metrics *gossipmetrics.GossipMetrics 172 serviceConfig *ServiceConfig 173 } 174 175 // This is an implementation of api.JoinChannelMessage. 176 type joinChannelMessage struct { 177 seqNum uint64 178 members2AnchorPeers map[string][]api.AnchorPeer 179 } 180 181 func (jcm *joinChannelMessage) SequenceNumber() uint64 { 182 return jcm.seqNum 183 } 184 185 // Members returns the organizations of the channel 186 func (jcm *joinChannelMessage) Members() []api.OrgIdentityType { 187 members := make([]api.OrgIdentityType, 0, len(jcm.members2AnchorPeers)) 188 for org := range jcm.members2AnchorPeers { 189 members = append(members, api.OrgIdentityType(org)) 190 } 191 return members 192 } 193 194 // AnchorPeersOf returns the anchor peers of the given organization 195 func (jcm *joinChannelMessage) AnchorPeersOf(org api.OrgIdentityType) []api.AnchorPeer { 196 return jcm.members2AnchorPeers[string(org)] 197 } 198 199 var logger = util.GetLogger(util.ServiceLogger, "") 200 201 // New creates the gossip service. 202 func New( 203 peerIdentity identity.SignerSerializer, 204 gossipMetrics *gossipmetrics.GossipMetrics, 205 endpoint string, 206 s *grpc.Server, 207 mcs api.MessageCryptoService, 208 secAdv api.SecurityAdvisor, 209 secureDialOpts api.PeerSecureDialOpts, 210 credSupport *corecomm.CredentialSupport, 211 deliverGRPCClient *corecomm.GRPCClient, 212 gossipConfig *gossip.Config, 213 serviceConfig *ServiceConfig, 214 deliverServiceConfig *deliverservice.DeliverServiceConfig, 215 ) (*GossipService, error) { 216 serializedIdentity, err := peerIdentity.Serialize() 217 if err != nil { 218 return nil, err 219 } 220 221 logger.Infof("Initialize gossip with endpoint %s", endpoint) 222 223 gossipComponent := gossip.New( 224 gossipConfig, 225 s, 226 secAdv, 227 mcs, 228 serializedIdentity, 229 secureDialOpts, 230 gossipMetrics, 231 ) 232 233 return &GossipService{ 234 gossipSvc: gossipComponent, 235 mcs: mcs, 236 privateHandlers: make(map[string]privateHandler), 237 chains: make(map[string]state.GossipStateProvider), 238 leaderElection: make(map[string]election.LeaderElectionService), 239 deliveryService: make(map[string]deliverservice.DeliverService), 240 deliveryFactory: &deliveryFactoryImpl{ 241 signer: peerIdentity, 242 credentialSupport: credSupport, 243 deliverGRPCClient: deliverGRPCClient, 244 deliverServiceConfig: deliverServiceConfig, 245 }, 246 peerIdentity: serializedIdentity, 247 secAdv: secAdv, 248 metrics: gossipMetrics, 249 serviceConfig: serviceConfig, 250 }, nil 251 } 252 253 // DistributePrivateData distribute private read write set inside the channel based on the collections policies 254 func (g *GossipService) DistributePrivateData(channelID string, txID string, privData *tspb.TxPvtReadWriteSetWithConfigInfo, blkHt uint64) error { 255 g.lock.RLock() 256 handler, exists := g.privateHandlers[channelID] 257 g.lock.RUnlock() 258 if !exists { 259 return errors.Errorf("No private data handler for %s", channelID) 260 } 261 262 if err := handler.distributor.Distribute(txID, privData, blkHt); err != nil { 263 logger.Error("Failed to distributed private collection, txID", txID, "channel", channelID, "due to", err) 264 return err 265 } 266 267 if err := handler.coordinator.StorePvtData(txID, privData, blkHt); err != nil { 268 logger.Error("Failed to store private data into transient store, txID", 269 txID, "channel", channelID, "due to", err) 270 return err 271 } 272 return nil 273 } 274 275 // NewConfigEventer creates a ConfigProcessor which the channelconfig.BundleSource can ultimately route config updates to 276 func (g *GossipService) NewConfigEventer() ConfigProcessor { 277 return newConfigEventer(g) 278 } 279 280 // Support aggregates functionality of several 281 // interfaces required by gossip service 282 type Support struct { 283 Validator txvalidator.Validator 284 Committer committer.Committer 285 CollectionStore privdata.CollectionStore 286 IdDeserializeFactory gossipprivdata.IdentityDeserializerFactory 287 CapabilityProvider gossipprivdata.CapabilityProvider 288 } 289 290 // InitializeChannel allocates the state provider and should be invoked once per channel per execution 291 func (g *GossipService) InitializeChannel(channelID string, ordererSource *orderers.ConnectionSource, store *transientstore.Store, support Support) { 292 g.lock.Lock() 293 defer g.lock.Unlock() 294 // Initialize new state provider for given committer 295 logger.Debug("Creating state provider for channelID", channelID) 296 servicesAdapter := &state.ServicesMediator{GossipAdapter: g, MCSAdapter: g.mcs} 297 298 // Initialize private data fetcher 299 dataRetriever := gossipprivdata.NewDataRetriever(store, support.Committer) 300 collectionAccessFactory := gossipprivdata.NewCollectionAccessFactory(support.IdDeserializeFactory) 301 fetcher := gossipprivdata.NewPuller(g.metrics.PrivdataMetrics, support.CollectionStore, g.gossipSvc, dataRetriever, 302 collectionAccessFactory, channelID, g.serviceConfig.BtlPullMargin) 303 304 coordinatorConfig := gossipprivdata.CoordinatorConfig{ 305 TransientBlockRetention: g.serviceConfig.TransientstoreMaxBlockRetention, 306 PullRetryThreshold: g.serviceConfig.PvtDataPullRetryThreshold, 307 SkipPullingInvalidTransactions: g.serviceConfig.SkipPullingInvalidTransactionsDuringCommit, 308 } 309 coordinator := gossipprivdata.NewCoordinator(gossipprivdata.Support{ 310 ChainID: channelID, 311 CollectionStore: support.CollectionStore, 312 Validator: support.Validator, 313 Committer: support.Committer, 314 Fetcher: fetcher, 315 CapabilityProvider: support.CapabilityProvider, 316 }, store, g.createSelfSignedData(), g.metrics.PrivdataMetrics, coordinatorConfig, 317 support.IdDeserializeFactory) 318 319 privdataConfig := gossipprivdata.GlobalConfig() 320 var reconciler gossipprivdata.PvtDataReconciler 321 322 if privdataConfig.ReconciliationEnabled { 323 reconciler = gossipprivdata.NewReconciler(channelID, g.metrics.PrivdataMetrics, 324 support.Committer, fetcher, privdataConfig) 325 } else { 326 reconciler = &gossipprivdata.NoOpReconciler{} 327 } 328 329 pushAckTimeout := g.serviceConfig.PvtDataPushAckTimeout 330 g.privateHandlers[channelID] = privateHandler{ 331 support: support, 332 coordinator: coordinator, 333 distributor: gossipprivdata.NewDistributor(channelID, g, collectionAccessFactory, g.metrics.PrivdataMetrics, pushAckTimeout), 334 reconciler: reconciler, 335 } 336 g.privateHandlers[channelID].reconciler.Start() 337 338 blockingMode := !g.serviceConfig.NonBlockingCommitMode 339 stateConfig := state.GlobalConfig() 340 g.chains[channelID] = state.NewGossipStateProvider( 341 channelID, 342 servicesAdapter, 343 coordinator, 344 g.metrics.StateMetrics, 345 blockingMode, 346 stateConfig) 347 if g.deliveryService[channelID] == nil { 348 g.deliveryService[channelID] = g.deliveryFactory.Service(g, ordererSource, g.mcs) 349 } 350 351 // Delivery service might be nil only if it was not able to get connected 352 // to the ordering service 353 if g.deliveryService[channelID] != nil { 354 // Parameters: 355 // - peer.gossip.useLeaderElection 356 // - peer.gossip.orgLeader 357 // 358 // are mutual exclusive, setting both to true is not defined, hence 359 // peer will panic and terminate 360 leaderElection := g.serviceConfig.UseLeaderElection 361 isStaticOrgLeader := g.serviceConfig.OrgLeader 362 363 if leaderElection && isStaticOrgLeader { 364 logger.Panic("Setting both orgLeader and useLeaderElection to true isn't supported, aborting execution") 365 } 366 367 if leaderElection { 368 logger.Debug("Delivery uses dynamic leader election mechanism, channel", channelID) 369 g.leaderElection[channelID] = g.newLeaderElectionComponent(channelID, g.onStatusChangeFactory(channelID, 370 support.Committer), g.metrics.ElectionMetrics) 371 } else if isStaticOrgLeader { 372 logger.Debug("This peer is configured to connect to ordering service for blocks delivery, channel", channelID) 373 g.deliveryService[channelID].StartDeliverForChannel(channelID, support.Committer, func() {}) 374 } else { 375 logger.Debug("This peer is not configured to connect to ordering service for blocks delivery, channel", channelID) 376 } 377 } else { 378 logger.Warning("Delivery client is down won't be able to pull blocks for chain", channelID) 379 } 380 381 } 382 383 func (g *GossipService) createSelfSignedData() protoutil.SignedData { 384 msg := make([]byte, 32) 385 sig, err := g.mcs.Sign(msg) 386 if err != nil { 387 logger.Panicf("Failed creating self signed data because message signing failed: %v", err) 388 } 389 return protoutil.SignedData{ 390 Data: msg, 391 Signature: sig, 392 Identity: g.peerIdentity, 393 } 394 } 395 396 // updateAnchors constructs a joinChannelMessage and sends it to the gossipSvc 397 func (g *GossipService) updateAnchors(config Config) { 398 myOrg := string(g.secAdv.OrgByPeerIdentity(api.PeerIdentityType(g.peerIdentity))) 399 if !g.amIinChannel(myOrg, config) { 400 logger.Error("Tried joining channel", config.ChannelID(), "but our org(", myOrg, "), isn't "+ 401 "among the orgs of the channel:", orgListFromConfig(config), ", aborting.") 402 return 403 } 404 jcm := &joinChannelMessage{seqNum: config.Sequence(), members2AnchorPeers: map[string][]api.AnchorPeer{}} 405 for _, appOrg := range config.Organizations() { 406 logger.Debug(appOrg.MSPID(), "anchor peers:", appOrg.AnchorPeers()) 407 jcm.members2AnchorPeers[appOrg.MSPID()] = []api.AnchorPeer{} 408 for _, ap := range appOrg.AnchorPeers() { 409 anchorPeer := api.AnchorPeer{ 410 Host: ap.Host, 411 Port: int(ap.Port), 412 } 413 jcm.members2AnchorPeers[appOrg.MSPID()] = append(jcm.members2AnchorPeers[appOrg.MSPID()], anchorPeer) 414 } 415 } 416 417 // Initialize new state provider for given committer 418 logger.Debug("Creating state provider for channelID", config.ChannelID()) 419 g.JoinChan(jcm, gossipcommon.ChannelID(config.ChannelID())) 420 } 421 422 // AddPayload appends message payload to for given chain 423 func (g *GossipService) AddPayload(channelID string, payload *gproto.Payload) error { 424 g.lock.RLock() 425 defer g.lock.RUnlock() 426 return g.chains[channelID].AddPayload(payload) 427 } 428 429 // Stop stops the gossip component 430 func (g *GossipService) Stop() { 431 g.lock.Lock() 432 defer g.lock.Unlock() 433 434 for chainID := range g.chains { 435 logger.Info("Stopping chain", chainID) 436 if le, exists := g.leaderElection[chainID]; exists { 437 logger.Infof("Stopping leader election for %s", chainID) 438 le.Stop() 439 } 440 g.chains[chainID].Stop() 441 g.privateHandlers[chainID].close() 442 443 if g.deliveryService[chainID] != nil { 444 g.deliveryService[chainID].Stop() 445 } 446 } 447 g.gossipSvc.Stop() 448 } 449 450 func (g *GossipService) newLeaderElectionComponent(channelID string, callback func(bool), 451 electionMetrics *gossipmetrics.ElectionMetrics) election.LeaderElectionService { 452 PKIid := g.mcs.GetPKIidOfCert(g.peerIdentity) 453 adapter := election.NewAdapter(g, PKIid, gossipcommon.ChannelID(channelID), electionMetrics) 454 config := election.ElectionConfig{ 455 StartupGracePeriod: g.serviceConfig.ElectionStartupGracePeriod, 456 MembershipSampleInterval: g.serviceConfig.ElectionMembershipSampleInterval, 457 LeaderAliveThreshold: g.serviceConfig.ElectionLeaderAliveThreshold, 458 LeaderElectionDuration: g.serviceConfig.ElectionLeaderElectionDuration, 459 } 460 return election.NewLeaderElectionService(adapter, string(PKIid), callback, config) 461 } 462 463 func (g *GossipService) amIinChannel(myOrg string, config Config) bool { 464 for _, orgName := range orgListFromConfig(config) { 465 if orgName == myOrg { 466 return true 467 } 468 } 469 return false 470 } 471 472 func (g *GossipService) onStatusChangeFactory(channelID string, committer blocksprovider.LedgerInfo) func(bool) { 473 return func(isLeader bool) { 474 if isLeader { 475 yield := func() { 476 g.lock.RLock() 477 le := g.leaderElection[channelID] 478 g.lock.RUnlock() 479 le.Yield() 480 } 481 logger.Info("Elected as a leader, starting delivery service for channel", channelID) 482 if err := g.deliveryService[channelID].StartDeliverForChannel(channelID, committer, yield); err != nil { 483 logger.Errorf("Delivery service is not able to start blocks delivery for chain, due to %+v", err) 484 } 485 } else { 486 logger.Info("Renounced leadership, stopping delivery service for channel", channelID) 487 if err := g.deliveryService[channelID].StopDeliverForChannel(channelID); err != nil { 488 logger.Errorf("Delivery service is not able to stop blocks delivery for chain, due to %+v", err) 489 } 490 } 491 } 492 } 493 494 func orgListFromConfig(config Config) []string { 495 var orgList []string 496 for _, appOrg := range config.Organizations() { 497 orgList = append(orgList, appOrg.MSPID()) 498 } 499 return orgList 500 }