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  }