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 }