github.com/anjalikarhana/fabric@v2.1.1+incompatible/orderer/common/cluster/comm.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package cluster
     8  
     9  import (
    10  	"bytes"
    11  	"context"
    12  	"crypto/x509"
    13  	"encoding/pem"
    14  	"fmt"
    15  	"sync"
    16  	"sync/atomic"
    17  	"time"
    18  
    19  	"github.com/golang/protobuf/proto"
    20  	"github.com/hyperledger/fabric-protos-go/orderer"
    21  	"github.com/hyperledger/fabric/common/flogging"
    22  	"github.com/hyperledger/fabric/internal/pkg/comm"
    23  	"github.com/pkg/errors"
    24  	"go.uber.org/zap"
    25  	"google.golang.org/grpc"
    26  	"google.golang.org/grpc/connectivity"
    27  )
    28  
    29  const (
    30  	// MinimumExpirationWarningInterval is the default minimum time interval
    31  	// between consecutive warnings about certificate expiration.
    32  	MinimumExpirationWarningInterval = time.Minute * 5
    33  )
    34  
    35  var (
    36  	errOverflow = errors.New("send queue overflown")
    37  	errAborted  = errors.New("aborted")
    38  	errTimeout  = errors.New("rpc timeout expired")
    39  )
    40  
    41  // ChannelExtractor extracts the channel of a given message,
    42  // or returns an empty string if that's not possible
    43  type ChannelExtractor interface {
    44  	TargetChannel(message proto.Message) string
    45  }
    46  
    47  //go:generate mockery -dir . -name Handler -case underscore -output ./mocks/
    48  
    49  // Handler handles Step() and Submit() requests and returns a corresponding response
    50  type Handler interface {
    51  	OnConsensus(channel string, sender uint64, req *orderer.ConsensusRequest) error
    52  	OnSubmit(channel string, sender uint64, req *orderer.SubmitRequest) error
    53  }
    54  
    55  // RemoteNode represents a cluster member
    56  type RemoteNode struct {
    57  	// ID is unique among all members, and cannot be 0.
    58  	ID uint64
    59  	// Endpoint is the endpoint of the node, denoted in %s:%d format
    60  	Endpoint string
    61  	// ServerTLSCert is the DER encoded TLS server certificate of the node
    62  	ServerTLSCert []byte
    63  	// ClientTLSCert is the DER encoded TLS client certificate of the node
    64  	ClientTLSCert []byte
    65  }
    66  
    67  // String returns a string representation of this RemoteNode
    68  func (rm RemoteNode) String() string {
    69  	return fmt.Sprintf("ID: %d,\nEndpoint: %s,\nServerTLSCert:%s, ClientTLSCert:%s",
    70  		rm.ID, rm.Endpoint, DERtoPEM(rm.ServerTLSCert), DERtoPEM(rm.ClientTLSCert))
    71  }
    72  
    73  //go:generate mockery -dir . -name Communicator -case underscore -output ./mocks/
    74  
    75  // Communicator defines communication for a consenter
    76  type Communicator interface {
    77  	// Remote returns a RemoteContext for the given RemoteNode ID in the context
    78  	// of the given channel, or error if connection cannot be established, or
    79  	// the channel wasn't configured
    80  	Remote(channel string, id uint64) (*RemoteContext, error)
    81  	// Configure configures the communication to connect to all
    82  	// given members, and disconnect from any members not among the given
    83  	// members.
    84  	Configure(channel string, members []RemoteNode)
    85  	// Shutdown shuts down the communicator
    86  	Shutdown()
    87  }
    88  
    89  // MembersByChannel is a mapping from channel name
    90  // to MemberMapping
    91  type MembersByChannel map[string]MemberMapping
    92  
    93  // Comm implements Communicator
    94  type Comm struct {
    95  	MinimumExpirationWarningInterval time.Duration
    96  	CertExpWarningThreshold          time.Duration
    97  	shutdownSignal                   chan struct{}
    98  	shutdown                         bool
    99  	SendBufferSize                   int
   100  	Lock                             sync.RWMutex
   101  	Logger                           *flogging.FabricLogger
   102  	ChanExt                          ChannelExtractor
   103  	H                                Handler
   104  	Connections                      *ConnectionStore
   105  	Chan2Members                     MembersByChannel
   106  	Metrics                          *Metrics
   107  }
   108  
   109  type requestContext struct {
   110  	channel string
   111  	sender  uint64
   112  }
   113  
   114  // DispatchSubmit identifies the channel and sender of the submit request and passes it
   115  // to the underlying Handler
   116  func (c *Comm) DispatchSubmit(ctx context.Context, request *orderer.SubmitRequest) error {
   117  	reqCtx, err := c.requestContext(ctx, request)
   118  	if err != nil {
   119  		return err
   120  	}
   121  	return c.H.OnSubmit(reqCtx.channel, reqCtx.sender, request)
   122  }
   123  
   124  // DispatchConsensus identifies the channel and sender of the step request and passes it
   125  // to the underlying Handler
   126  func (c *Comm) DispatchConsensus(ctx context.Context, request *orderer.ConsensusRequest) error {
   127  	reqCtx, err := c.requestContext(ctx, request)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	return c.H.OnConsensus(reqCtx.channel, reqCtx.sender, request)
   132  }
   133  
   134  // requestContext identifies the sender and channel of the request and returns
   135  // it wrapped in a requestContext
   136  func (c *Comm) requestContext(ctx context.Context, msg proto.Message) (*requestContext, error) {
   137  	channel := c.ChanExt.TargetChannel(msg)
   138  	if channel == "" {
   139  		return nil, errors.Errorf("badly formatted message, cannot extract channel")
   140  	}
   141  
   142  	c.Lock.RLock()
   143  	mapping, exists := c.Chan2Members[channel]
   144  	c.Lock.RUnlock()
   145  
   146  	if !exists {
   147  		return nil, errors.Errorf("channel %s doesn't exist", channel)
   148  	}
   149  
   150  	cert := comm.ExtractRawCertificateFromContext(ctx)
   151  	if len(cert) == 0 {
   152  		return nil, errors.Errorf("no TLS certificate sent")
   153  	}
   154  
   155  	stub := mapping.LookupByClientCert(cert)
   156  	if stub == nil {
   157  		return nil, errors.Errorf("certificate extracted from TLS connection isn't authorized")
   158  	}
   159  	return &requestContext{
   160  		channel: channel,
   161  		sender:  stub.ID,
   162  	}, nil
   163  }
   164  
   165  // Remote obtains a RemoteContext linked to the destination node on the context
   166  // of a given channel
   167  func (c *Comm) Remote(channel string, id uint64) (*RemoteContext, error) {
   168  	c.Lock.RLock()
   169  	defer c.Lock.RUnlock()
   170  
   171  	if c.shutdown {
   172  		return nil, errors.New("communication has been shut down")
   173  	}
   174  
   175  	mapping, exists := c.Chan2Members[channel]
   176  	if !exists {
   177  		return nil, errors.Errorf("channel %s doesn't exist", channel)
   178  	}
   179  	stub := mapping.ByID(id)
   180  	if stub == nil {
   181  		return nil, errors.Errorf("node %d doesn't exist in channel %s's membership", id, channel)
   182  	}
   183  
   184  	if stub.Active() {
   185  		return stub.RemoteContext, nil
   186  	}
   187  
   188  	err := stub.Activate(c.createRemoteContext(stub, channel))
   189  	if err != nil {
   190  		return nil, errors.WithStack(err)
   191  	}
   192  	return stub.RemoteContext, nil
   193  }
   194  
   195  // Configure configures the channel with the given RemoteNodes
   196  func (c *Comm) Configure(channel string, newNodes []RemoteNode) {
   197  	c.Logger.Infof("Entering, channel: %s, nodes: %v", channel, newNodes)
   198  	defer c.Logger.Infof("Exiting")
   199  
   200  	c.Lock.Lock()
   201  	defer c.Lock.Unlock()
   202  
   203  	c.createShutdownSignalIfNeeded()
   204  
   205  	if c.shutdown {
   206  		return
   207  	}
   208  
   209  	beforeConfigChange := c.serverCertsInUse()
   210  	// Update the channel-scoped mapping with the new nodes
   211  	c.applyMembershipConfig(channel, newNodes)
   212  	// Close connections to nodes that are not present in the new membership
   213  	c.cleanUnusedConnections(beforeConfigChange)
   214  }
   215  
   216  func (c *Comm) createShutdownSignalIfNeeded() {
   217  	if c.shutdownSignal == nil {
   218  		c.shutdownSignal = make(chan struct{})
   219  	}
   220  }
   221  
   222  // Shutdown shuts down the instance
   223  func (c *Comm) Shutdown() {
   224  	c.Lock.Lock()
   225  	defer c.Lock.Unlock()
   226  
   227  	c.createShutdownSignalIfNeeded()
   228  	if !c.shutdown {
   229  		close(c.shutdownSignal)
   230  	}
   231  
   232  	c.shutdown = true
   233  	for _, members := range c.Chan2Members {
   234  		for _, member := range members {
   235  			c.Connections.Disconnect(member.ServerTLSCert)
   236  		}
   237  	}
   238  }
   239  
   240  // cleanUnusedConnections disconnects all connections that are un-used
   241  // at the moment of the invocation
   242  func (c *Comm) cleanUnusedConnections(serverCertsBeforeConfig StringSet) {
   243  	// Scan all nodes after the reconfiguration
   244  	serverCertsAfterConfig := c.serverCertsInUse()
   245  	// Filter out the certificates that remained after the reconfiguration
   246  	serverCertsBeforeConfig.subtract(serverCertsAfterConfig)
   247  	// Close the connections to all these nodes as they shouldn't be in use now
   248  	for serverCertificate := range serverCertsBeforeConfig {
   249  		c.Connections.Disconnect([]byte(serverCertificate))
   250  	}
   251  }
   252  
   253  // serverCertsInUse returns the server certificates that are in use
   254  // represented as strings.
   255  func (c *Comm) serverCertsInUse() StringSet {
   256  	endpointsInUse := make(StringSet)
   257  	for _, mapping := range c.Chan2Members {
   258  		endpointsInUse.union(mapping.ServerCertificates())
   259  	}
   260  	return endpointsInUse
   261  }
   262  
   263  // applyMembershipConfig sets the given RemoteNodes for the given channel
   264  func (c *Comm) applyMembershipConfig(channel string, newNodes []RemoteNode) {
   265  	mapping := c.getOrCreateMapping(channel)
   266  	newNodeIDs := make(map[uint64]struct{})
   267  
   268  	for _, node := range newNodes {
   269  		newNodeIDs[node.ID] = struct{}{}
   270  		c.updateStubInMapping(channel, mapping, node)
   271  	}
   272  
   273  	// Remove all stubs without a corresponding node
   274  	// in the new nodes
   275  	for id, stub := range mapping {
   276  		if _, exists := newNodeIDs[id]; exists {
   277  			c.Logger.Info(id, "exists in both old and new membership for channel", channel, ", skipping its deactivation")
   278  			continue
   279  		}
   280  		c.Logger.Info("Deactivated node", id, "who's endpoint is", stub.Endpoint, "as it's removed from membership")
   281  		delete(mapping, id)
   282  		stub.Deactivate()
   283  	}
   284  }
   285  
   286  // updateStubInMapping updates the given RemoteNode and adds it to the MemberMapping
   287  func (c *Comm) updateStubInMapping(channel string, mapping MemberMapping, node RemoteNode) {
   288  	stub := mapping.ByID(node.ID)
   289  	if stub == nil {
   290  		c.Logger.Info("Allocating a new stub for node", node.ID, "with endpoint of", node.Endpoint, "for channel", channel)
   291  		stub = &Stub{}
   292  	}
   293  
   294  	// Check if the TLS server certificate of the node is replaced
   295  	// and if so - then deactivate the stub, to trigger
   296  	// a re-creation of its gRPC connection
   297  	if !bytes.Equal(stub.ServerTLSCert, node.ServerTLSCert) {
   298  		c.Logger.Info("Deactivating node", node.ID, "in channel", channel,
   299  			"with endpoint of", node.Endpoint, "due to TLS certificate change")
   300  		stub.Deactivate()
   301  	}
   302  
   303  	// Overwrite the stub Node data with the new data
   304  	stub.RemoteNode = node
   305  
   306  	// Put the stub into the mapping
   307  	mapping.Put(stub)
   308  
   309  	// Check if the stub needs activation.
   310  	if stub.Active() {
   311  		return
   312  	}
   313  
   314  	// Activate the stub
   315  	stub.Activate(c.createRemoteContext(stub, channel))
   316  }
   317  
   318  // createRemoteStub returns a function that creates a RemoteContext.
   319  // It is used as a parameter to Stub.Activate() in order to activate
   320  // a stub atomically.
   321  func (c *Comm) createRemoteContext(stub *Stub, channel string) func() (*RemoteContext, error) {
   322  	return func() (*RemoteContext, error) {
   323  		cert, err := x509.ParseCertificate(stub.ServerTLSCert)
   324  		if err != nil {
   325  			pemString := string(pem.EncodeToMemory(&pem.Block{Bytes: stub.ServerTLSCert}))
   326  			c.Logger.Errorf("Invalid DER for channel %s, endpoint %s, ID %d: %v", channel, stub.Endpoint, stub.ID, pemString)
   327  			return nil, errors.Wrap(err, "invalid certificate DER")
   328  		}
   329  
   330  		c.Logger.Debug("Connecting to", stub.RemoteNode, "for channel", channel)
   331  
   332  		conn, err := c.Connections.Connection(stub.Endpoint, stub.ServerTLSCert)
   333  		if err != nil {
   334  			c.Logger.Warningf("Unable to obtain connection to %d(%s) (channel %s): %v", stub.ID, stub.Endpoint, channel, err)
   335  			return nil, err
   336  		}
   337  
   338  		probeConnection := func(conn *grpc.ClientConn) error {
   339  			connState := conn.GetState()
   340  			if connState == connectivity.Connecting {
   341  				return errors.Errorf("connection to %d(%s) is in state %s", stub.ID, stub.Endpoint, connState)
   342  			}
   343  			return nil
   344  		}
   345  
   346  		clusterClient := orderer.NewClusterClient(conn)
   347  
   348  		workerCountReporter := workerCountReporter{
   349  			channel: channel,
   350  		}
   351  
   352  		rc := &RemoteContext{
   353  			expiresAt:                        cert.NotAfter,
   354  			minimumExpirationWarningInterval: c.MinimumExpirationWarningInterval,
   355  			certExpWarningThreshold:          c.CertExpWarningThreshold,
   356  			workerCountReporter:              workerCountReporter,
   357  			Channel:                          channel,
   358  			Metrics:                          c.Metrics,
   359  			SendBuffSize:                     c.SendBufferSize,
   360  			shutdownSignal:                   c.shutdownSignal,
   361  			endpoint:                         stub.Endpoint,
   362  			Logger:                           c.Logger,
   363  			ProbeConn:                        probeConnection,
   364  			conn:                             conn,
   365  			Client:                           clusterClient,
   366  		}
   367  		return rc, nil
   368  	}
   369  }
   370  
   371  // getOrCreateMapping creates a MemberMapping for the given channel
   372  // or returns the existing one.
   373  func (c *Comm) getOrCreateMapping(channel string) MemberMapping {
   374  	// Lazily create a mapping if it doesn't already exist
   375  	mapping, exists := c.Chan2Members[channel]
   376  	if !exists {
   377  		mapping = make(MemberMapping)
   378  		c.Chan2Members[channel] = mapping
   379  	}
   380  	return mapping
   381  }
   382  
   383  // Stub holds all information about the remote node,
   384  // including the RemoteContext for it, and serializes
   385  // some operations on it.
   386  type Stub struct {
   387  	lock sync.RWMutex
   388  	RemoteNode
   389  	*RemoteContext
   390  }
   391  
   392  // Active returns whether the Stub
   393  // is active or not
   394  func (stub *Stub) Active() bool {
   395  	stub.lock.RLock()
   396  	defer stub.lock.RUnlock()
   397  	return stub.isActive()
   398  }
   399  
   400  // Active returns whether the Stub
   401  // is active or not.
   402  func (stub *Stub) isActive() bool {
   403  	return stub.RemoteContext != nil
   404  }
   405  
   406  // Deactivate deactivates the Stub and
   407  // ceases all communication operations
   408  // invoked on it.
   409  func (stub *Stub) Deactivate() {
   410  	stub.lock.Lock()
   411  	defer stub.lock.Unlock()
   412  	if !stub.isActive() {
   413  		return
   414  	}
   415  	stub.RemoteContext.Abort()
   416  	stub.RemoteContext = nil
   417  }
   418  
   419  // Activate creates a remote context with the given function callback
   420  // in an atomic manner - if two parallel invocations are invoked on this Stub,
   421  // only a single invocation of createRemoteStub takes place.
   422  func (stub *Stub) Activate(createRemoteContext func() (*RemoteContext, error)) error {
   423  	stub.lock.Lock()
   424  	defer stub.lock.Unlock()
   425  	// Check if the stub has already been activated while we were waiting for the lock
   426  	if stub.isActive() {
   427  		return nil
   428  	}
   429  	remoteStub, err := createRemoteContext()
   430  	if err != nil {
   431  		return errors.WithStack(err)
   432  	}
   433  
   434  	stub.RemoteContext = remoteStub
   435  	return nil
   436  }
   437  
   438  // RemoteContext interacts with remote cluster
   439  // nodes. Every call can be aborted via call to Abort()
   440  type RemoteContext struct {
   441  	expiresAt                        time.Time
   442  	minimumExpirationWarningInterval time.Duration
   443  	certExpWarningThreshold          time.Duration
   444  	Metrics                          *Metrics
   445  	Channel                          string
   446  	SendBuffSize                     int
   447  	shutdownSignal                   chan struct{}
   448  	Logger                           *flogging.FabricLogger
   449  	endpoint                         string
   450  	Client                           orderer.ClusterClient
   451  	ProbeConn                        func(conn *grpc.ClientConn) error
   452  	conn                             *grpc.ClientConn
   453  	nextStreamID                     uint64
   454  	streamsByID                      streamsMapperReporter
   455  	workerCountReporter              workerCountReporter
   456  }
   457  
   458  // Stream is used to send/receive messages to/from the remote cluster member.
   459  type Stream struct {
   460  	abortChan    <-chan struct{}
   461  	sendBuff     chan *orderer.StepRequest
   462  	commShutdown chan struct{}
   463  	abortReason  *atomic.Value
   464  	metrics      *Metrics
   465  	ID           uint64
   466  	Channel      string
   467  	NodeName     string
   468  	Endpoint     string
   469  	Logger       *flogging.FabricLogger
   470  	Timeout      time.Duration
   471  	orderer.Cluster_StepClient
   472  	Cancel   func(error)
   473  	canceled *uint32
   474  	expCheck *certificateExpirationCheck
   475  }
   476  
   477  // StreamOperation denotes an operation done by a stream, such a Send or Receive.
   478  type StreamOperation func() (*orderer.StepResponse, error)
   479  
   480  // Canceled returns whether the stream was canceled.
   481  func (stream *Stream) Canceled() bool {
   482  	return atomic.LoadUint32(stream.canceled) == uint32(1)
   483  }
   484  
   485  // Send sends the given request to the remote cluster member.
   486  func (stream *Stream) Send(request *orderer.StepRequest) error {
   487  	if stream.Canceled() {
   488  		return errors.New(stream.abortReason.Load().(string))
   489  	}
   490  	var allowDrop bool
   491  	// We want to drop consensus transactions if the remote node cannot keep up with us,
   492  	// otherwise we'll slow down the entire FSM.
   493  	if request.GetConsensusRequest() != nil {
   494  		allowDrop = true
   495  	}
   496  
   497  	return stream.sendOrDrop(request, allowDrop)
   498  }
   499  
   500  // sendOrDrop sends the given request to the remote cluster member, or drops it
   501  // if it is a consensus request and the queue is full.
   502  func (stream *Stream) sendOrDrop(request *orderer.StepRequest, allowDrop bool) error {
   503  	msgType := "transaction"
   504  	if allowDrop {
   505  		msgType = "consensus"
   506  	}
   507  
   508  	stream.metrics.reportQueueOccupancy(stream.Endpoint, msgType, stream.Channel, len(stream.sendBuff), cap(stream.sendBuff))
   509  
   510  	if allowDrop && len(stream.sendBuff) == cap(stream.sendBuff) {
   511  		stream.Cancel(errOverflow)
   512  		stream.metrics.reportMessagesDropped(stream.Endpoint, stream.Channel)
   513  		return errOverflow
   514  	}
   515  
   516  	select {
   517  	case <-stream.abortChan:
   518  		return errors.Errorf("stream %d aborted", stream.ID)
   519  	case stream.sendBuff <- request:
   520  		return nil
   521  	case <-stream.commShutdown:
   522  		return nil
   523  	}
   524  }
   525  
   526  // sendMessage sends the request down the stream
   527  func (stream *Stream) sendMessage(request *orderer.StepRequest) {
   528  	start := time.Now()
   529  	var err error
   530  	defer func() {
   531  		if !stream.Logger.IsEnabledFor(zap.DebugLevel) {
   532  			return
   533  		}
   534  		var result string
   535  		if err != nil {
   536  			result = fmt.Sprintf("but failed due to %s", err.Error())
   537  		}
   538  		stream.Logger.Debugf("Send of %s to %s(%s) took %v %s", requestAsString(request),
   539  			stream.NodeName, stream.Endpoint, time.Since(start), result)
   540  	}()
   541  
   542  	f := func() (*orderer.StepResponse, error) {
   543  		startSend := time.Now()
   544  		stream.expCheck.checkExpiration(startSend, stream.Channel)
   545  		err := stream.Cluster_StepClient.Send(request)
   546  		stream.metrics.reportMsgSendTime(stream.Endpoint, stream.Channel, time.Since(startSend))
   547  		return nil, err
   548  	}
   549  
   550  	_, err = stream.operateWithTimeout(f)
   551  }
   552  
   553  func (stream *Stream) serviceStream() {
   554  	defer stream.Cancel(errAborted)
   555  
   556  	for {
   557  		select {
   558  		case msg := <-stream.sendBuff:
   559  			stream.sendMessage(msg)
   560  		case <-stream.abortChan:
   561  			return
   562  		case <-stream.commShutdown:
   563  			return
   564  		}
   565  	}
   566  }
   567  
   568  // Recv receives a message from a remote cluster member.
   569  func (stream *Stream) Recv() (*orderer.StepResponse, error) {
   570  	start := time.Now()
   571  	defer func() {
   572  		if !stream.Logger.IsEnabledFor(zap.DebugLevel) {
   573  			return
   574  		}
   575  		stream.Logger.Debugf("Receive from %s(%s) took %v", stream.NodeName, stream.Endpoint, time.Since(start))
   576  	}()
   577  
   578  	f := func() (*orderer.StepResponse, error) {
   579  		return stream.Cluster_StepClient.Recv()
   580  	}
   581  
   582  	return stream.operateWithTimeout(f)
   583  }
   584  
   585  // operateWithTimeout performs the given operation on the stream, and blocks until the timeout expires.
   586  func (stream *Stream) operateWithTimeout(invoke StreamOperation) (*orderer.StepResponse, error) {
   587  	timer := time.NewTimer(stream.Timeout)
   588  	defer timer.Stop()
   589  
   590  	var operationEnded sync.WaitGroup
   591  	operationEnded.Add(1)
   592  
   593  	responseChan := make(chan struct {
   594  		res *orderer.StepResponse
   595  		err error
   596  	}, 1)
   597  
   598  	go func() {
   599  		defer operationEnded.Done()
   600  		res, err := invoke()
   601  		responseChan <- struct {
   602  			res *orderer.StepResponse
   603  			err error
   604  		}{res: res, err: err}
   605  	}()
   606  
   607  	select {
   608  	case r := <-responseChan:
   609  		if r.err != nil {
   610  			stream.Cancel(r.err)
   611  		}
   612  		return r.res, r.err
   613  	case <-timer.C:
   614  		stream.Logger.Warningf("Stream %d to %s(%s) was forcibly terminated because timeout (%v) expired",
   615  			stream.ID, stream.NodeName, stream.Endpoint, stream.Timeout)
   616  		stream.Cancel(errTimeout)
   617  		// Wait for the operation goroutine to end
   618  		operationEnded.Wait()
   619  		return nil, errTimeout
   620  	}
   621  }
   622  
   623  func requestAsString(request *orderer.StepRequest) string {
   624  	switch t := request.GetPayload().(type) {
   625  	case *orderer.StepRequest_SubmitRequest:
   626  		if t.SubmitRequest == nil || t.SubmitRequest.Payload == nil {
   627  			return fmt.Sprintf("Empty SubmitRequest: %v", t.SubmitRequest)
   628  		}
   629  		return fmt.Sprintf("SubmitRequest for channel %s with payload of size %d",
   630  			t.SubmitRequest.Channel, len(t.SubmitRequest.Payload.Payload))
   631  	case *orderer.StepRequest_ConsensusRequest:
   632  		return fmt.Sprintf("ConsensusRequest for channel %s with payload of size %d",
   633  			t.ConsensusRequest.Channel, len(t.ConsensusRequest.Payload))
   634  	default:
   635  		return fmt.Sprintf("unknown type: %v", request)
   636  	}
   637  }
   638  
   639  // NewStream creates a new stream.
   640  // It is not thread safe, and Send() or Recv() block only until the timeout expires.
   641  func (rc *RemoteContext) NewStream(timeout time.Duration) (*Stream, error) {
   642  	if err := rc.ProbeConn(rc.conn); err != nil {
   643  		return nil, err
   644  	}
   645  
   646  	ctx, cancel := context.WithCancel(context.TODO())
   647  	stream, err := rc.Client.Step(ctx)
   648  	if err != nil {
   649  		cancel()
   650  		return nil, errors.WithStack(err)
   651  	}
   652  
   653  	streamID := atomic.AddUint64(&rc.nextStreamID, 1)
   654  	nodeName := commonNameFromContext(stream.Context())
   655  
   656  	var canceled uint32
   657  
   658  	abortChan := make(chan struct{})
   659  
   660  	abort := func() {
   661  		cancel()
   662  		rc.streamsByID.Delete(streamID)
   663  		rc.Metrics.reportEgressStreamCount(rc.Channel, atomic.LoadUint32(&rc.streamsByID.size))
   664  		rc.Logger.Debugf("Stream %d to %s(%s) is aborted", streamID, nodeName, rc.endpoint)
   665  		atomic.StoreUint32(&canceled, 1)
   666  		close(abortChan)
   667  	}
   668  
   669  	once := &sync.Once{}
   670  	abortReason := &atomic.Value{}
   671  	cancelWithReason := func(err error) {
   672  		abortReason.Store(err.Error())
   673  		once.Do(abort)
   674  	}
   675  
   676  	logger := flogging.MustGetLogger("orderer.common.cluster.step")
   677  	stepLogger := logger.WithOptions(zap.AddCallerSkip(1))
   678  
   679  	s := &Stream{
   680  		Channel:            rc.Channel,
   681  		metrics:            rc.Metrics,
   682  		abortReason:        abortReason,
   683  		abortChan:          abortChan,
   684  		sendBuff:           make(chan *orderer.StepRequest, rc.SendBuffSize),
   685  		commShutdown:       rc.shutdownSignal,
   686  		NodeName:           nodeName,
   687  		Logger:             stepLogger,
   688  		ID:                 streamID,
   689  		Endpoint:           rc.endpoint,
   690  		Timeout:            timeout,
   691  		Cluster_StepClient: stream,
   692  		Cancel:             cancelWithReason,
   693  		canceled:           &canceled,
   694  	}
   695  
   696  	s.expCheck = &certificateExpirationCheck{
   697  		minimumExpirationWarningInterval: rc.minimumExpirationWarningInterval,
   698  		expirationWarningThreshold:       rc.certExpWarningThreshold,
   699  		expiresAt:                        rc.expiresAt,
   700  		endpoint:                         s.Endpoint,
   701  		nodeName:                         s.NodeName,
   702  		alert: func(template string, args ...interface{}) {
   703  			s.Logger.Warningf(template, args...)
   704  		},
   705  	}
   706  
   707  	rc.Logger.Debugf("Created new stream to %s with ID of %d and buffer size of %d",
   708  		rc.endpoint, streamID, cap(s.sendBuff))
   709  
   710  	rc.streamsByID.Store(streamID, s)
   711  	rc.Metrics.reportEgressStreamCount(rc.Channel, atomic.LoadUint32(&rc.streamsByID.size))
   712  
   713  	go func() {
   714  		rc.workerCountReporter.increment(s.metrics)
   715  		s.serviceStream()
   716  		rc.workerCountReporter.decrement(s.metrics)
   717  	}()
   718  
   719  	return s, nil
   720  }
   721  
   722  // Abort aborts the contexts the RemoteContext uses, thus effectively
   723  // causes all operations that use this RemoteContext to terminate.
   724  func (rc *RemoteContext) Abort() {
   725  	rc.streamsByID.Range(func(_, value interface{}) bool {
   726  		value.(*Stream).Cancel(errAborted)
   727  		return false
   728  	})
   729  }
   730  
   731  func commonNameFromContext(ctx context.Context) string {
   732  	cert := comm.ExtractCertificateFromContext(ctx)
   733  	if cert == nil {
   734  		return "unidentified node"
   735  	}
   736  	return cert.Subject.CommonName
   737  }
   738  
   739  type streamsMapperReporter struct {
   740  	size uint32
   741  	sync.Map
   742  }
   743  
   744  func (smr *streamsMapperReporter) Delete(key interface{}) {
   745  	smr.Map.Delete(key)
   746  	atomic.AddUint32(&smr.size, ^uint32(0))
   747  }
   748  
   749  func (smr *streamsMapperReporter) Store(key, value interface{}) {
   750  	smr.Map.Store(key, value)
   751  	atomic.AddUint32(&smr.size, 1)
   752  }
   753  
   754  type workerCountReporter struct {
   755  	channel     string
   756  	workerCount uint32
   757  }
   758  
   759  func (wcr *workerCountReporter) increment(m *Metrics) {
   760  	count := atomic.AddUint32(&wcr.workerCount, 1)
   761  	m.reportWorkerCount(wcr.channel, count)
   762  }
   763  
   764  func (wcr *workerCountReporter) decrement(m *Metrics) {
   765  	// ^0 flips all zeros to ones, which means
   766  	// 2^32 - 1, and then we add this number wcr.workerCount.
   767  	// It follows from commutativity of the unsigned integers group
   768  	// that wcr.workerCount + 2^32 - 1 = wcr.workerCount - 1 + 2^32
   769  	// which is just wcr.workerCount - 1.
   770  	count := atomic.AddUint32(&wcr.workerCount, ^uint32(0))
   771  	m.reportWorkerCount(wcr.channel, count)
   772  }