github.com/kaituanwang/hyperledger@v2.0.1+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, 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 err := errors.WithMessagef(err, "failed to distribute private collection, txID %s, channel %s", txID, channelID) 265 logger.Error(err) 266 return err 267 } 268 269 if err := handler.coordinator.StorePvtData(txID, privData, blkHt); err != nil { 270 logger.Error("Failed to store private data into transient store, txID", 271 txID, "channel", channelID, "due to", err) 272 return err 273 } 274 return nil 275 } 276 277 // NewConfigEventer creates a ConfigProcessor which the channelconfig.BundleSource can ultimately route config updates to 278 func (g *GossipService) NewConfigEventer() ConfigProcessor { 279 return newConfigEventer(g) 280 } 281 282 // Support aggregates functionality of several 283 // interfaces required by gossip service 284 type Support struct { 285 Validator txvalidator.Validator 286 Committer committer.Committer 287 CollectionStore privdata.CollectionStore 288 IdDeserializeFactory gossipprivdata.IdentityDeserializerFactory 289 CapabilityProvider gossipprivdata.CapabilityProvider 290 } 291 292 // InitializeChannel allocates the state provider and should be invoked once per channel per execution 293 func (g *GossipService) InitializeChannel(channelID string, ordererSource *orderers.ConnectionSource, store *transientstore.Store, support Support) { 294 g.lock.Lock() 295 defer g.lock.Unlock() 296 // Initialize new state provider for given committer 297 logger.Debug("Creating state provider for channelID", channelID) 298 servicesAdapter := &state.ServicesMediator{GossipAdapter: g, MCSAdapter: g.mcs} 299 300 // Initialize private data fetcher 301 dataRetriever := gossipprivdata.NewDataRetriever(store, support.Committer) 302 collectionAccessFactory := gossipprivdata.NewCollectionAccessFactory(support.IdDeserializeFactory) 303 fetcher := gossipprivdata.NewPuller(g.metrics.PrivdataMetrics, support.CollectionStore, g.gossipSvc, dataRetriever, 304 collectionAccessFactory, channelID, g.serviceConfig.BtlPullMargin) 305 306 coordinatorConfig := gossipprivdata.CoordinatorConfig{ 307 TransientBlockRetention: g.serviceConfig.TransientstoreMaxBlockRetention, 308 PullRetryThreshold: g.serviceConfig.PvtDataPullRetryThreshold, 309 SkipPullingInvalidTransactions: g.serviceConfig.SkipPullingInvalidTransactionsDuringCommit, 310 } 311 selfSignedData := g.createSelfSignedData() 312 mspID := string(g.secAdv.OrgByPeerIdentity(selfSignedData.Identity)) 313 coordinator := gossipprivdata.NewCoordinator(mspID, gossipprivdata.Support{ 314 ChainID: channelID, 315 CollectionStore: support.CollectionStore, 316 Validator: support.Validator, 317 Committer: support.Committer, 318 Fetcher: fetcher, 319 CapabilityProvider: support.CapabilityProvider, 320 }, store, selfSignedData, g.metrics.PrivdataMetrics, coordinatorConfig, 321 support.IdDeserializeFactory) 322 323 privdataConfig := gossipprivdata.GlobalConfig() 324 var reconciler gossipprivdata.PvtDataReconciler 325 326 if privdataConfig.ReconciliationEnabled { 327 reconciler = gossipprivdata.NewReconciler(channelID, g.metrics.PrivdataMetrics, 328 support.Committer, fetcher, privdataConfig) 329 } else { 330 reconciler = &gossipprivdata.NoOpReconciler{} 331 } 332 333 pushAckTimeout := g.serviceConfig.PvtDataPushAckTimeout 334 g.privateHandlers[channelID] = privateHandler{ 335 support: support, 336 coordinator: coordinator, 337 distributor: gossipprivdata.NewDistributor(channelID, g, collectionAccessFactory, g.metrics.PrivdataMetrics, pushAckTimeout), 338 reconciler: reconciler, 339 } 340 g.privateHandlers[channelID].reconciler.Start() 341 342 blockingMode := !g.serviceConfig.NonBlockingCommitMode 343 stateConfig := state.GlobalConfig() 344 g.chains[channelID] = state.NewGossipStateProvider( 345 channelID, 346 servicesAdapter, 347 coordinator, 348 g.metrics.StateMetrics, 349 blockingMode, 350 stateConfig) 351 if g.deliveryService[channelID] == nil { 352 g.deliveryService[channelID] = g.deliveryFactory.Service(g, ordererSource, g.mcs, g.serviceConfig.OrgLeader) 353 } 354 355 // Delivery service might be nil only if it was not able to get connected 356 // to the ordering service 357 if g.deliveryService[channelID] != nil { 358 // Parameters: 359 // - peer.gossip.useLeaderElection 360 // - peer.gossip.orgLeader 361 // 362 // are mutual exclusive, setting both to true is not defined, hence 363 // peer will panic and terminate 364 leaderElection := g.serviceConfig.UseLeaderElection 365 isStaticOrgLeader := g.serviceConfig.OrgLeader 366 367 if leaderElection && isStaticOrgLeader { 368 logger.Panic("Setting both orgLeader and useLeaderElection to true isn't supported, aborting execution") 369 } 370 371 if leaderElection { 372 logger.Debug("Delivery uses dynamic leader election mechanism, channel", channelID) 373 g.leaderElection[channelID] = g.newLeaderElectionComponent(channelID, g.onStatusChangeFactory(channelID, 374 support.Committer), g.metrics.ElectionMetrics) 375 } else if isStaticOrgLeader { 376 logger.Debug("This peer is configured to connect to ordering service for blocks delivery, channel", channelID) 377 g.deliveryService[channelID].StartDeliverForChannel(channelID, support.Committer, func() {}) 378 } else { 379 logger.Debug("This peer is not configured to connect to ordering service for blocks delivery, channel", channelID) 380 } 381 } else { 382 logger.Warning("Delivery client is down won't be able to pull blocks for chain", channelID) 383 } 384 385 } 386 387 func (g *GossipService) createSelfSignedData() protoutil.SignedData { 388 msg := make([]byte, 32) 389 sig, err := g.mcs.Sign(msg) 390 if err != nil { 391 logger.Panicf("Failed creating self signed data because message signing failed: %v", err) 392 } 393 return protoutil.SignedData{ 394 Data: msg, 395 Signature: sig, 396 Identity: g.peerIdentity, 397 } 398 } 399 400 // updateAnchors constructs a joinChannelMessage and sends it to the gossipSvc 401 func (g *GossipService) updateAnchors(config Config) { 402 myOrg := string(g.secAdv.OrgByPeerIdentity(api.PeerIdentityType(g.peerIdentity))) 403 if !g.amIinChannel(myOrg, config) { 404 logger.Error("Tried joining channel", config.ChannelID(), "but our org(", myOrg, "), isn't "+ 405 "among the orgs of the channel:", orgListFromConfig(config), ", aborting.") 406 return 407 } 408 jcm := &joinChannelMessage{seqNum: config.Sequence(), members2AnchorPeers: map[string][]api.AnchorPeer{}} 409 for _, appOrg := range config.Organizations() { 410 logger.Debug(appOrg.MSPID(), "anchor peers:", appOrg.AnchorPeers()) 411 jcm.members2AnchorPeers[appOrg.MSPID()] = []api.AnchorPeer{} 412 for _, ap := range appOrg.AnchorPeers() { 413 anchorPeer := api.AnchorPeer{ 414 Host: ap.Host, 415 Port: int(ap.Port), 416 } 417 jcm.members2AnchorPeers[appOrg.MSPID()] = append(jcm.members2AnchorPeers[appOrg.MSPID()], anchorPeer) 418 } 419 } 420 421 // Initialize new state provider for given committer 422 logger.Debug("Creating state provider for channelID", config.ChannelID()) 423 g.JoinChan(jcm, gossipcommon.ChannelID(config.ChannelID())) 424 } 425 426 // AddPayload appends message payload to for given chain 427 func (g *GossipService) AddPayload(channelID string, payload *gproto.Payload) error { 428 g.lock.RLock() 429 defer g.lock.RUnlock() 430 return g.chains[channelID].AddPayload(payload) 431 } 432 433 // Stop stops the gossip component 434 func (g *GossipService) Stop() { 435 g.lock.Lock() 436 defer g.lock.Unlock() 437 438 for chainID := range g.chains { 439 logger.Info("Stopping chain", chainID) 440 if le, exists := g.leaderElection[chainID]; exists { 441 logger.Infof("Stopping leader election for %s", chainID) 442 le.Stop() 443 } 444 g.chains[chainID].Stop() 445 g.privateHandlers[chainID].close() 446 447 if g.deliveryService[chainID] != nil { 448 g.deliveryService[chainID].Stop() 449 } 450 } 451 g.gossipSvc.Stop() 452 } 453 454 func (g *GossipService) newLeaderElectionComponent(channelID string, callback func(bool), 455 electionMetrics *gossipmetrics.ElectionMetrics) election.LeaderElectionService { 456 PKIid := g.mcs.GetPKIidOfCert(g.peerIdentity) 457 adapter := election.NewAdapter(g, PKIid, gossipcommon.ChannelID(channelID), electionMetrics) 458 config := election.ElectionConfig{ 459 StartupGracePeriod: g.serviceConfig.ElectionStartupGracePeriod, 460 MembershipSampleInterval: g.serviceConfig.ElectionMembershipSampleInterval, 461 LeaderAliveThreshold: g.serviceConfig.ElectionLeaderAliveThreshold, 462 LeaderElectionDuration: g.serviceConfig.ElectionLeaderElectionDuration, 463 } 464 return election.NewLeaderElectionService(adapter, string(PKIid), callback, config) 465 } 466 467 func (g *GossipService) amIinChannel(myOrg string, config Config) bool { 468 for _, orgName := range orgListFromConfig(config) { 469 if orgName == myOrg { 470 return true 471 } 472 } 473 return false 474 } 475 476 func (g *GossipService) onStatusChangeFactory(channelID string, committer blocksprovider.LedgerInfo) func(bool) { 477 return func(isLeader bool) { 478 if isLeader { 479 yield := func() { 480 g.lock.RLock() 481 le := g.leaderElection[channelID] 482 g.lock.RUnlock() 483 le.Yield() 484 } 485 logger.Info("Elected as a leader, starting delivery service for channel", channelID) 486 if err := g.deliveryService[channelID].StartDeliverForChannel(channelID, committer, yield); err != nil { 487 logger.Errorf("Delivery service is not able to start blocks delivery for chain, due to %+v", err) 488 } 489 } else { 490 logger.Info("Renounced leadership, stopping delivery service for channel", channelID) 491 if err := g.deliveryService[channelID].StopDeliverForChannel(channelID); err != nil { 492 logger.Errorf("Delivery service is not able to stop blocks delivery for chain, due to %+v", err) 493 } 494 } 495 } 496 } 497 498 func orgListFromConfig(config Config) []string { 499 var orgList []string 500 for _, appOrg := range config.Organizations() { 501 orgList = append(orgList, appOrg.MSPID()) 502 } 503 return orgList 504 }