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