github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/gossip/service/gossip_service.go (about) 1 /* 2 Copyright hechain. 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 "github.com/hechain20/hechain/common/flogging" 14 "github.com/hechain20/hechain/core/committer" 15 "github.com/hechain20/hechain/core/committer/txvalidator" 16 "github.com/hechain20/hechain/core/common/privdata" 17 "github.com/hechain20/hechain/core/deliverservice" 18 "github.com/hechain20/hechain/core/transientstore" 19 "github.com/hechain20/hechain/gossip/api" 20 "github.com/hechain20/hechain/gossip/comm" 21 "github.com/hechain20/hechain/gossip/common" 22 "github.com/hechain20/hechain/gossip/discovery" 23 "github.com/hechain20/hechain/gossip/election" 24 "github.com/hechain20/hechain/gossip/filter" 25 "github.com/hechain20/hechain/gossip/gossip" 26 gossipmetrics "github.com/hechain20/hechain/gossip/metrics" 27 gossipprivdata "github.com/hechain20/hechain/gossip/privdata" 28 "github.com/hechain20/hechain/gossip/protoext" 29 "github.com/hechain20/hechain/gossip/state" 30 "github.com/hechain20/hechain/gossip/util" 31 corecomm "github.com/hechain20/hechain/internal/pkg/comm" 32 "github.com/hechain20/hechain/internal/pkg/identity" 33 "github.com/hechain20/hechain/internal/pkg/peer/blocksprovider" 34 "github.com/hechain20/hechain/internal/pkg/peer/orderers" 35 "github.com/hechain20/hechain/protoutil" 36 gproto "github.com/hyperledger/fabric-protos-go/gossip" 37 tspb "github.com/hyperledger/fabric-protos-go/transientstore" 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(common.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 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 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 // GossipService handles the interaction between gossip service and peer 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 privdataConfig *gossipprivdata.PrivdataConfig 175 anchorPeerTracker *anchorPeerTracker 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 // anchorPeerTracker maintains anchor peer endpoints for all the channels. 203 type anchorPeerTracker struct { 204 // allEndpoints contains anchor peer endpoints for all the channels, 205 // its key is channel name, value is map of anchor peer endpoints 206 allEndpoints map[string]map[string]struct{} 207 mutex sync.RWMutex 208 } 209 210 // update overwrites the anchor peer endpoints for the channel 211 func (t *anchorPeerTracker) update(channelName string, endpoints map[string]struct{}) { 212 t.mutex.Lock() 213 defer t.mutex.Unlock() 214 t.allEndpoints[channelName] = endpoints 215 } 216 217 // IsAnchorPeer checks if an endpoint is an anchor peer in any channel 218 func (t *anchorPeerTracker) IsAnchorPeer(endpoint string) bool { 219 t.mutex.RLock() 220 defer t.mutex.RUnlock() 221 for _, endpointsForChannel := range t.allEndpoints { 222 if _, ok := endpointsForChannel[endpoint]; ok { 223 return true 224 } 225 } 226 return false 227 } 228 229 var logger = util.GetLogger(util.ServiceLogger, "") 230 231 // New creates the gossip service. 232 func New( 233 peerIdentity identity.SignerSerializer, 234 gossipMetrics *gossipmetrics.GossipMetrics, 235 endpoint string, 236 s *grpc.Server, 237 mcs api.MessageCryptoService, 238 secAdv api.SecurityAdvisor, 239 secureDialOpts api.PeerSecureDialOpts, 240 credSupport *corecomm.CredentialSupport, 241 gossipConfig *gossip.Config, 242 serviceConfig *ServiceConfig, 243 privdataConfig *gossipprivdata.PrivdataConfig, 244 deliverServiceConfig *deliverservice.DeliverServiceConfig, 245 ) (*GossipService, error) { 246 serializedIdentity, err := peerIdentity.Serialize() 247 if err != nil { 248 return nil, err 249 } 250 251 logger.Infof("Initialize gossip with endpoint %s", endpoint) 252 253 anchorPeerTracker := &anchorPeerTracker{allEndpoints: map[string]map[string]struct{}{}} 254 gossipComponent := gossip.New( 255 gossipConfig, 256 s, 257 secAdv, 258 mcs, 259 serializedIdentity, 260 secureDialOpts, 261 gossipMetrics, 262 anchorPeerTracker, 263 ) 264 265 return &GossipService{ 266 gossipSvc: gossipComponent, 267 mcs: mcs, 268 privateHandlers: make(map[string]privateHandler), 269 chains: make(map[string]state.GossipStateProvider), 270 leaderElection: make(map[string]election.LeaderElectionService), 271 deliveryService: make(map[string]deliverservice.DeliverService), 272 deliveryFactory: &deliveryFactoryImpl{ 273 signer: peerIdentity, 274 credentialSupport: credSupport, 275 deliverServiceConfig: deliverServiceConfig, 276 }, 277 peerIdentity: serializedIdentity, 278 secAdv: secAdv, 279 metrics: gossipMetrics, 280 serviceConfig: serviceConfig, 281 privdataConfig: privdataConfig, 282 anchorPeerTracker: anchorPeerTracker, 283 }, nil 284 } 285 286 // DistributePrivateData distribute private read write set inside the channel based on the collections policies 287 func (g *GossipService) DistributePrivateData(channelID string, txID string, privData *tspb.TxPvtReadWriteSetWithConfigInfo, blkHt uint64) error { 288 g.lock.RLock() 289 handler, exists := g.privateHandlers[channelID] 290 g.lock.RUnlock() 291 if !exists { 292 return errors.Errorf("No private data handler for %s", channelID) 293 } 294 295 if err := handler.distributor.Distribute(txID, privData, blkHt); err != nil { 296 err := errors.WithMessagef(err, "failed to distribute private collection, txID %s, channel %s", txID, channelID) 297 logger.Error(err) 298 return err 299 } 300 301 if err := handler.coordinator.StorePvtData(txID, privData, blkHt); err != nil { 302 logger.Error("Failed to store private data into transient store, txID", 303 txID, "channel", channelID, "due to", err) 304 return err 305 } 306 return nil 307 } 308 309 // NewConfigEventer creates a ConfigProcessor which the channelconfig.BundleSource can ultimately route config updates to 310 func (g *GossipService) NewConfigEventer() ConfigProcessor { 311 return newConfigEventer(g) 312 } 313 314 // Support aggregates functionality of several 315 // interfaces required by gossip service 316 type Support struct { 317 Validator txvalidator.Validator 318 Committer committer.Committer 319 CollectionStore privdata.CollectionStore 320 IdDeserializeFactory gossipprivdata.IdentityDeserializerFactory 321 CapabilityProvider gossipprivdata.CapabilityProvider 322 } 323 324 // InitializeChannel allocates the state provider and should be invoked once per channel per execution 325 func (g *GossipService) InitializeChannel(channelID string, ordererSource *orderers.ConnectionSource, store *transientstore.Store, support Support) { 326 g.lock.Lock() 327 defer g.lock.Unlock() 328 // Initialize new state provider for given committer 329 logger.Debug("Creating state provider for channelID", channelID) 330 servicesAdapter := &state.ServicesMediator{GossipAdapter: g, MCSAdapter: g.mcs} 331 332 // Initialize private data fetcher 333 dataRetriever := gossipprivdata.NewDataRetriever(channelID, store, support.Committer) 334 collectionAccessFactory := gossipprivdata.NewCollectionAccessFactory(support.IdDeserializeFactory) 335 fetcher := gossipprivdata.NewPuller(g.metrics.PrivdataMetrics, support.CollectionStore, g.gossipSvc, dataRetriever, 336 collectionAccessFactory, channelID, g.serviceConfig.BtlPullMargin) 337 338 coordinatorConfig := gossipprivdata.CoordinatorConfig{ 339 TransientBlockRetention: g.serviceConfig.TransientstoreMaxBlockRetention, 340 PullRetryThreshold: g.serviceConfig.PvtDataPullRetryThreshold, 341 SkipPullingInvalidTransactions: g.serviceConfig.SkipPullingInvalidTransactionsDuringCommit, 342 } 343 selfSignedData := g.createSelfSignedData() 344 mspID := string(g.secAdv.OrgByPeerIdentity(selfSignedData.Identity)) 345 coordinator := gossipprivdata.NewCoordinator(mspID, gossipprivdata.Support{ 346 ChainID: channelID, 347 CollectionStore: support.CollectionStore, 348 Validator: support.Validator, 349 Committer: support.Committer, 350 Fetcher: fetcher, 351 CapabilityProvider: support.CapabilityProvider, 352 }, store, selfSignedData, g.metrics.PrivdataMetrics, coordinatorConfig, 353 support.IdDeserializeFactory) 354 355 var reconciler gossipprivdata.PvtDataReconciler 356 357 if g.privdataConfig.ReconciliationEnabled { 358 reconciler = gossipprivdata.NewReconciler(channelID, g.metrics.PrivdataMetrics, 359 support.Committer, fetcher, g.privdataConfig) 360 } else { 361 reconciler = &gossipprivdata.NoOpReconciler{} 362 } 363 364 pushAckTimeout := g.serviceConfig.PvtDataPushAckTimeout 365 g.privateHandlers[channelID] = privateHandler{ 366 support: support, 367 coordinator: coordinator, 368 distributor: gossipprivdata.NewDistributor(channelID, g, collectionAccessFactory, g.metrics.PrivdataMetrics, pushAckTimeout), 369 reconciler: reconciler, 370 } 371 g.privateHandlers[channelID].reconciler.Start() 372 373 blockingMode := !g.serviceConfig.NonBlockingCommitMode 374 stateConfig := state.GlobalConfig() 375 g.chains[channelID] = state.NewGossipStateProvider( 376 flogging.MustGetLogger(util.StateLogger), 377 channelID, 378 servicesAdapter, 379 coordinator, 380 g.metrics.StateMetrics, 381 blockingMode, 382 stateConfig) 383 if g.deliveryService[channelID] == nil { 384 g.deliveryService[channelID] = g.deliveryFactory.Service(g, ordererSource, g.mcs, g.serviceConfig.OrgLeader) 385 } 386 387 // Delivery service might be nil only if it was not able to get connected 388 // to the ordering service 389 if g.deliveryService[channelID] != nil { 390 // Parameters: 391 // - peer.gossip.useLeaderElection 392 // - peer.gossip.orgLeader 393 // 394 // are mutual exclusive, setting both to true is not defined, hence 395 // peer will panic and terminate 396 leaderElection := g.serviceConfig.UseLeaderElection 397 isStaticOrgLeader := g.serviceConfig.OrgLeader 398 399 if leaderElection && isStaticOrgLeader { 400 logger.Panic("Setting both orgLeader and useLeaderElection to true isn't supported, aborting execution") 401 } 402 403 if leaderElection { 404 logger.Debug("Delivery uses dynamic leader election mechanism, channel", channelID) 405 g.leaderElection[channelID] = g.newLeaderElectionComponent(channelID, g.onStatusChangeFactory(channelID, 406 support.Committer), g.metrics.ElectionMetrics) 407 } else if isStaticOrgLeader { 408 logger.Debug("This peer is configured to connect to ordering service for blocks delivery, channel", channelID) 409 g.deliveryService[channelID].StartDeliverForChannel(channelID, support.Committer, func() {}) 410 } else { 411 logger.Debug("This peer is not configured to connect to ordering service for blocks delivery, channel", channelID) 412 } 413 } else { 414 logger.Warning("Delivery client is down won't be able to pull blocks for chain", channelID) 415 } 416 } 417 418 func (g *GossipService) createSelfSignedData() protoutil.SignedData { 419 msg := make([]byte, 32) 420 sig, err := g.mcs.Sign(msg) 421 if err != nil { 422 logger.Panicf("Failed creating self signed data because message signing failed: %v", err) 423 } 424 return protoutil.SignedData{ 425 Data: msg, 426 Signature: sig, 427 Identity: g.peerIdentity, 428 } 429 } 430 431 // updateAnchors constructs a joinChannelMessage and sends it to the gossipSvc 432 func (g *GossipService) updateAnchors(configUpdate ConfigUpdate) { 433 myOrg := string(g.secAdv.OrgByPeerIdentity(api.PeerIdentityType(g.peerIdentity))) 434 if !g.amIinChannel(myOrg, configUpdate) { 435 logger.Error("Tried joining channel", configUpdate.ChannelID, "but our org(", myOrg, "), isn't "+ 436 "among the orgs of the channel:", orgListFromConfigUpdate(configUpdate), ", aborting.") 437 return 438 } 439 jcm := &joinChannelMessage{seqNum: configUpdate.Sequence, members2AnchorPeers: map[string][]api.AnchorPeer{}} 440 anchorPeerEndpoints := map[string]struct{}{} 441 for _, appOrg := range configUpdate.Organizations { 442 logger.Debug(appOrg.MSPID(), "anchor peers:", appOrg.AnchorPeers()) 443 jcm.members2AnchorPeers[appOrg.MSPID()] = []api.AnchorPeer{} 444 for _, ap := range appOrg.AnchorPeers() { 445 anchorPeer := api.AnchorPeer{ 446 Host: ap.Host, 447 Port: int(ap.Port), 448 } 449 jcm.members2AnchorPeers[appOrg.MSPID()] = append(jcm.members2AnchorPeers[appOrg.MSPID()], anchorPeer) 450 anchorPeerEndpoints[fmt.Sprintf("%s:%d", ap.Host, ap.Port)] = struct{}{} 451 } 452 } 453 g.anchorPeerTracker.update(configUpdate.ChannelID, anchorPeerEndpoints) 454 455 // Initialize new state provider for given committer 456 logger.Debug("Creating state provider for channelID", configUpdate.ChannelID) 457 g.JoinChan(jcm, common.ChannelID(configUpdate.ChannelID)) 458 } 459 460 // AddPayload appends message payload to for given chain 461 func (g *GossipService) AddPayload(channelID string, payload *gproto.Payload) error { 462 g.lock.RLock() 463 defer g.lock.RUnlock() 464 return g.chains[channelID].AddPayload(payload) 465 } 466 467 // Stop stops the gossip component 468 func (g *GossipService) Stop() { 469 g.lock.Lock() 470 defer g.lock.Unlock() 471 472 for chainID := range g.chains { 473 logger.Info("Stopping chain", chainID) 474 if le, exists := g.leaderElection[chainID]; exists { 475 logger.Infof("Stopping leader election for %s", chainID) 476 le.Stop() 477 } 478 g.chains[chainID].Stop() 479 g.privateHandlers[chainID].close() 480 481 if g.deliveryService[chainID] != nil { 482 g.deliveryService[chainID].Stop() 483 } 484 } 485 g.gossipSvc.Stop() 486 } 487 488 func (g *GossipService) newLeaderElectionComponent(channelID string, callback func(bool), 489 electionMetrics *gossipmetrics.ElectionMetrics) election.LeaderElectionService { 490 PKIid := g.mcs.GetPKIidOfCert(g.peerIdentity) 491 adapter := election.NewAdapter(g, PKIid, common.ChannelID(channelID), electionMetrics) 492 config := election.ElectionConfig{ 493 StartupGracePeriod: g.serviceConfig.ElectionStartupGracePeriod, 494 MembershipSampleInterval: g.serviceConfig.ElectionMembershipSampleInterval, 495 LeaderAliveThreshold: g.serviceConfig.ElectionLeaderAliveThreshold, 496 LeaderElectionDuration: g.serviceConfig.ElectionLeaderElectionDuration, 497 } 498 return election.NewLeaderElectionService(adapter, string(PKIid), callback, config) 499 } 500 501 func (g *GossipService) amIinChannel(myOrg string, configUpdate ConfigUpdate) bool { 502 for _, orgName := range orgListFromConfigUpdate(configUpdate) { 503 if orgName == myOrg { 504 return true 505 } 506 } 507 return false 508 } 509 510 func (g *GossipService) onStatusChangeFactory(channelID string, committer blocksprovider.LedgerInfo) func(bool) { 511 return func(isLeader bool) { 512 if isLeader { 513 yield := func() { 514 g.lock.RLock() 515 le := g.leaderElection[channelID] 516 g.lock.RUnlock() 517 le.Yield() 518 } 519 logger.Info("Elected as a leader, starting delivery service for channel", channelID) 520 if err := g.deliveryService[channelID].StartDeliverForChannel(channelID, committer, yield); err != nil { 521 logger.Errorf("Delivery service is not able to start blocks delivery for chain, due to %+v", err) 522 } 523 } else { 524 logger.Info("Renounced leadership, stopping delivery service for channel", channelID) 525 if err := g.deliveryService[channelID].StopDeliverForChannel(channelID); err != nil { 526 logger.Errorf("Delivery service is not able to stop blocks delivery for chain, due to %+v", err) 527 } 528 } 529 } 530 } 531 532 func orgListFromConfigUpdate(config ConfigUpdate) []string { 533 var orgList []string 534 for _, appOrg := range config.Organizations { 535 orgList = append(orgList, appOrg.MSPID()) 536 } 537 return orgList 538 }