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  }