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