github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/orderer/common/broadcast/broadcast.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package broadcast
     8  
     9  import (
    10  	"io"
    11  	"time"
    12  
    13  	"github.com/hechain20/hechain/common/flogging"
    14  	"github.com/hechain20/hechain/common/util"
    15  	"github.com/hechain20/hechain/orderer/common/msgprocessor"
    16  	cb "github.com/hyperledger/fabric-protos-go/common"
    17  	ab "github.com/hyperledger/fabric-protos-go/orderer"
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  var logger = flogging.MustGetLogger("orderer.common.broadcast")
    22  
    23  //go:generate counterfeiter -o mock/channel_support_registrar.go --fake-name ChannelSupportRegistrar . ChannelSupportRegistrar
    24  
    25  // ChannelSupportRegistrar provides a way for the Handler to look up the Support for a channel
    26  type ChannelSupportRegistrar interface {
    27  	// BroadcastChannelSupport returns the message channel header, whether the message is a config update
    28  	// and the channel resources for a message or an error if the message is not a message which can
    29  	// be processed directly (like CONFIG and ORDERER_TRANSACTION messages)
    30  	BroadcastChannelSupport(msg *cb.Envelope) (*cb.ChannelHeader, bool, ChannelSupport, error)
    31  }
    32  
    33  //go:generate counterfeiter -o mock/channel_support.go --fake-name ChannelSupport . ChannelSupport
    34  
    35  // ChannelSupport provides the backing resources needed to support broadcast on a channel
    36  type ChannelSupport interface {
    37  	msgprocessor.Processor
    38  	Consenter
    39  }
    40  
    41  // Consenter provides methods to send messages through consensus
    42  type Consenter interface {
    43  	// Order accepts a message or returns an error indicating the cause of failure
    44  	// It ultimately passes through to the consensus.Chain interface
    45  	Order(env *cb.Envelope, configSeq uint64) error
    46  
    47  	// Configure accepts a reconfiguration or returns an error indicating the cause of failure
    48  	// It ultimately passes through to the consensus.Chain interface
    49  	Configure(config *cb.Envelope, configSeq uint64) error
    50  
    51  	// WaitReady blocks waiting for consenter to be ready for accepting new messages.
    52  	// This is useful when consenter needs to temporarily block ingress messages so
    53  	// that in-flight messages can be consumed. It could return error if consenter is
    54  	// in erroneous states. If this blocking behavior is not desired, consenter could
    55  	// simply return nil.
    56  	WaitReady() error
    57  }
    58  
    59  // Handler is designed to handle connections from Broadcast AB gRPC service
    60  type Handler struct {
    61  	SupportRegistrar ChannelSupportRegistrar
    62  	Metrics          *Metrics
    63  }
    64  
    65  // Handle reads requests from a Broadcast stream, processes them, and returns the responses to the stream
    66  func (bh *Handler) Handle(srv ab.AtomicBroadcast_BroadcastServer) error {
    67  	addr := util.ExtractRemoteAddress(srv.Context())
    68  	logger.Debugf("Starting new broadcast loop for %s", addr)
    69  	for {
    70  		msg, err := srv.Recv()
    71  		if err == io.EOF {
    72  			logger.Debugf("Received EOF from %s, hangup", addr)
    73  			return nil
    74  		}
    75  		if err != nil {
    76  			logger.Warningf("Error reading from %s: %s", addr, err)
    77  			return err
    78  		}
    79  
    80  		resp := bh.ProcessMessage(msg, addr)
    81  		err = srv.Send(resp)
    82  		if resp.Status != cb.Status_SUCCESS {
    83  			return err
    84  		}
    85  
    86  		if err != nil {
    87  			logger.Warningf("Error sending to %s: %s", addr, err)
    88  			return err
    89  		}
    90  	}
    91  }
    92  
    93  type MetricsTracker struct {
    94  	ValidateStartTime time.Time
    95  	EnqueueStartTime  time.Time
    96  	ValidateDuration  time.Duration
    97  	ChannelID         string
    98  	TxType            string
    99  	Metrics           *Metrics
   100  }
   101  
   102  func (mt *MetricsTracker) Record(resp *ab.BroadcastResponse) {
   103  	labels := []string{
   104  		"status", resp.Status.String(),
   105  		"channel", mt.ChannelID,
   106  		"type", mt.TxType,
   107  	}
   108  
   109  	if mt.ValidateDuration == 0 {
   110  		mt.EndValidate()
   111  	}
   112  	mt.Metrics.ValidateDuration.With(labels...).Observe(mt.ValidateDuration.Seconds())
   113  
   114  	if mt.EnqueueStartTime != (time.Time{}) {
   115  		enqueueDuration := time.Since(mt.EnqueueStartTime)
   116  		mt.Metrics.EnqueueDuration.With(labels...).Observe(enqueueDuration.Seconds())
   117  	}
   118  
   119  	mt.Metrics.ProcessedCount.With(labels...).Add(1)
   120  }
   121  
   122  func (mt *MetricsTracker) BeginValidate() {
   123  	mt.ValidateStartTime = time.Now()
   124  }
   125  
   126  func (mt *MetricsTracker) EndValidate() {
   127  	mt.ValidateDuration = time.Since(mt.ValidateStartTime)
   128  }
   129  
   130  func (mt *MetricsTracker) BeginEnqueue() {
   131  	mt.EnqueueStartTime = time.Now()
   132  }
   133  
   134  // ProcessMessage validates and enqueues a single message
   135  func (bh *Handler) ProcessMessage(msg *cb.Envelope, addr string) (resp *ab.BroadcastResponse) {
   136  	tracker := &MetricsTracker{
   137  		ChannelID: "unknown",
   138  		TxType:    "unknown",
   139  		Metrics:   bh.Metrics,
   140  	}
   141  	defer func() {
   142  		// This looks a little unnecessary, but if done directly as
   143  		// a defer, resp gets the (always nil) current state of resp
   144  		// and not the return value
   145  		tracker.Record(resp)
   146  	}()
   147  	tracker.BeginValidate()
   148  
   149  	chdr, isConfig, processor, err := bh.SupportRegistrar.BroadcastChannelSupport(msg)
   150  	if chdr != nil {
   151  		tracker.ChannelID = chdr.ChannelId
   152  		tracker.TxType = cb.HeaderType(chdr.Type).String()
   153  	}
   154  	if err != nil {
   155  		logger.Warningf("[channel: %s] Could not get message processor for serving %s: %s", tracker.ChannelID, addr, err)
   156  		return &ab.BroadcastResponse{Status: cb.Status_BAD_REQUEST, Info: err.Error()}
   157  	}
   158  
   159  	if !isConfig {
   160  		logger.Debugf("[channel: %s] Broadcast is processing normal message from %s with txid '%s' of type %s", chdr.ChannelId, addr, chdr.TxId, cb.HeaderType_name[chdr.Type])
   161  
   162  		configSeq, err := processor.ProcessNormalMsg(msg)
   163  		if err != nil {
   164  			logger.Warningf("[channel: %s] Rejecting broadcast of normal message from %s because of error: %s", chdr.ChannelId, addr, err)
   165  			return &ab.BroadcastResponse{Status: ClassifyError(err), Info: err.Error()}
   166  		}
   167  		tracker.EndValidate()
   168  
   169  		tracker.BeginEnqueue()
   170  		if err = processor.WaitReady(); err != nil {
   171  			logger.Warningf("[channel: %s] Rejecting broadcast of message from %s with SERVICE_UNAVAILABLE: rejected by Consenter: %s", chdr.ChannelId, addr, err)
   172  			return &ab.BroadcastResponse{Status: cb.Status_SERVICE_UNAVAILABLE, Info: err.Error()}
   173  		}
   174  
   175  		err = processor.Order(msg, configSeq)
   176  		if err != nil {
   177  			logger.Warningf("[channel: %s] Rejecting broadcast of normal message from %s with SERVICE_UNAVAILABLE: rejected by Order: %s", chdr.ChannelId, addr, err)
   178  			return &ab.BroadcastResponse{Status: cb.Status_SERVICE_UNAVAILABLE, Info: err.Error()}
   179  		}
   180  	} else { // isConfig
   181  		logger.Debugf("[channel: %s] Broadcast is processing config update message from %s", chdr.ChannelId, addr)
   182  
   183  		config, configSeq, err := processor.ProcessConfigUpdateMsg(msg)
   184  		if err != nil {
   185  			logger.Warningf("[channel: %s] Rejecting broadcast of config message from %s because of error: %s", chdr.ChannelId, addr, err)
   186  			return &ab.BroadcastResponse{Status: ClassifyError(err), Info: err.Error()}
   187  		}
   188  		tracker.EndValidate()
   189  
   190  		tracker.BeginEnqueue()
   191  		if err = processor.WaitReady(); err != nil {
   192  			logger.Warningf("[channel: %s] Rejecting broadcast of message from %s with SERVICE_UNAVAILABLE: rejected by Consenter: %s", chdr.ChannelId, addr, err)
   193  			return &ab.BroadcastResponse{Status: cb.Status_SERVICE_UNAVAILABLE, Info: err.Error()}
   194  		}
   195  
   196  		err = processor.Configure(config, configSeq)
   197  		if err != nil {
   198  			logger.Warningf("[channel: %s] Rejecting broadcast of config message from %s with SERVICE_UNAVAILABLE: rejected by Configure: %s", chdr.ChannelId, addr, err)
   199  			return &ab.BroadcastResponse{Status: cb.Status_SERVICE_UNAVAILABLE, Info: err.Error()}
   200  		}
   201  	}
   202  
   203  	logger.Debugf("[channel: %s] Broadcast has successfully enqueued message of type %s from %s", chdr.ChannelId, cb.HeaderType_name[chdr.Type], addr)
   204  
   205  	return &ab.BroadcastResponse{Status: cb.Status_SUCCESS}
   206  }
   207  
   208  // ClassifyError converts an error type into a status code.
   209  func ClassifyError(err error) cb.Status {
   210  	switch errors.Cause(err) {
   211  	case msgprocessor.ErrChannelDoesNotExist:
   212  		return cb.Status_NOT_FOUND
   213  	case msgprocessor.ErrPermissionDenied:
   214  		return cb.Status_FORBIDDEN
   215  	case msgprocessor.ErrMaintenanceMode:
   216  		return cb.Status_SERVICE_UNAVAILABLE
   217  	default:
   218  		return cb.Status_BAD_REQUEST
   219  	}
   220  }