github.com/ewagmig/fabric@v2.1.1+incompatible/common/deliver/deliver.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package deliver 8 9 import ( 10 "context" 11 "io" 12 "math" 13 "strconv" 14 "time" 15 16 "github.com/golang/protobuf/proto" 17 cb "github.com/hyperledger/fabric-protos-go/common" 18 ab "github.com/hyperledger/fabric-protos-go/orderer" 19 "github.com/hyperledger/fabric/common/crypto" 20 "github.com/hyperledger/fabric/common/flogging" 21 "github.com/hyperledger/fabric/common/ledger/blockledger" 22 "github.com/hyperledger/fabric/common/policies" 23 "github.com/hyperledger/fabric/common/util" 24 "github.com/hyperledger/fabric/internal/pkg/comm" 25 "github.com/hyperledger/fabric/protoutil" 26 "github.com/pkg/errors" 27 ) 28 29 var logger = flogging.MustGetLogger("common.deliver") 30 31 //go:generate counterfeiter -o mock/chain_manager.go -fake-name ChainManager . ChainManager 32 33 // ChainManager provides a way for the Handler to look up the Chain. 34 type ChainManager interface { 35 GetChain(chainID string) Chain 36 } 37 38 //go:generate counterfeiter -o mock/chain.go -fake-name Chain . Chain 39 40 // Chain encapsulates chain operations and data. 41 type Chain interface { 42 // Sequence returns the current config sequence number, can be used to detect config changes 43 Sequence() uint64 44 45 // PolicyManager returns the current policy manager as specified by the chain configuration 46 PolicyManager() policies.Manager 47 48 // Reader returns the chain Reader for the chain 49 Reader() blockledger.Reader 50 51 // Errored returns a channel which closes when the backing consenter has errored 52 Errored() <-chan struct{} 53 } 54 55 //go:generate counterfeiter -o mock/policy_checker.go -fake-name PolicyChecker . PolicyChecker 56 57 // PolicyChecker checks the envelope against the policy logic supplied by the 58 // function. 59 type PolicyChecker interface { 60 CheckPolicy(envelope *cb.Envelope, channelID string) error 61 } 62 63 // The PolicyCheckerFunc is an adapter that allows the use of an ordinary 64 // function as a PolicyChecker. 65 type PolicyCheckerFunc func(envelope *cb.Envelope, channelID string) error 66 67 // CheckPolicy calls pcf(envelope, channelID) 68 func (pcf PolicyCheckerFunc) CheckPolicy(envelope *cb.Envelope, channelID string) error { 69 return pcf(envelope, channelID) 70 } 71 72 //go:generate counterfeiter -o mock/inspector.go -fake-name Inspector . Inspector 73 74 // Inspector verifies an appropriate binding between the message and the context. 75 type Inspector interface { 76 Inspect(context.Context, proto.Message) error 77 } 78 79 // The InspectorFunc is an adapter that allows the use of an ordinary 80 // function as an Inspector. 81 type InspectorFunc func(context.Context, proto.Message) error 82 83 // Inspect calls inspector(ctx, p) 84 func (inspector InspectorFunc) Inspect(ctx context.Context, p proto.Message) error { 85 return inspector(ctx, p) 86 } 87 88 // Handler handles server requests. 89 type Handler struct { 90 ExpirationCheckFunc func(identityBytes []byte) time.Time 91 ChainManager ChainManager 92 TimeWindow time.Duration 93 BindingInspector Inspector 94 Metrics *Metrics 95 } 96 97 //go:generate counterfeiter -o mock/receiver.go -fake-name Receiver . Receiver 98 99 // Receiver is used to receive enveloped seek requests. 100 type Receiver interface { 101 Recv() (*cb.Envelope, error) 102 } 103 104 //go:generate counterfeiter -o mock/response_sender.go -fake-name ResponseSender . ResponseSender 105 106 // ResponseSender defines the interface a handler must implement to send 107 // responses. 108 type ResponseSender interface { 109 // SendStatusResponse sends completion status to the client. 110 SendStatusResponse(status cb.Status) error 111 // SendBlockResponse sends the block and optionally private data to the client. 112 SendBlockResponse(data *cb.Block, channelID string, chain Chain, signedData *protoutil.SignedData) error 113 // DataType returns the data type sent by the sender 114 DataType() string 115 } 116 117 // Filtered is a marker interface that indicates a response sender 118 // is configured to send filtered blocks 119 // Note: this is replaced by "data_type" label. Keep it for now until we decide how to take care of compatibility issue. 120 type Filtered interface { 121 IsFiltered() bool 122 } 123 124 // Server is a polymorphic structure to support generalization of this handler 125 // to be able to deliver different type of responses. 126 type Server struct { 127 Receiver 128 PolicyChecker 129 ResponseSender 130 } 131 132 // ExtractChannelHeaderCertHash extracts the TLS cert hash from a channel header. 133 func ExtractChannelHeaderCertHash(msg proto.Message) []byte { 134 chdr, isChannelHeader := msg.(*cb.ChannelHeader) 135 if !isChannelHeader || chdr == nil { 136 return nil 137 } 138 return chdr.TlsCertHash 139 } 140 141 // NewHandler creates an implementation of the Handler interface. 142 func NewHandler(cm ChainManager, timeWindow time.Duration, mutualTLS bool, metrics *Metrics, expirationCheckDisabled bool) *Handler { 143 expirationCheck := crypto.ExpiresAt 144 if expirationCheckDisabled { 145 expirationCheck = noExpiration 146 } 147 return &Handler{ 148 ChainManager: cm, 149 TimeWindow: timeWindow, 150 BindingInspector: InspectorFunc(comm.NewBindingInspector(mutualTLS, ExtractChannelHeaderCertHash)), 151 Metrics: metrics, 152 ExpirationCheckFunc: expirationCheck, 153 } 154 } 155 156 // Handle receives incoming deliver requests. 157 func (h *Handler) Handle(ctx context.Context, srv *Server) error { 158 addr := util.ExtractRemoteAddress(ctx) 159 logger.Debugf("Starting new deliver loop for %s", addr) 160 h.Metrics.StreamsOpened.Add(1) 161 defer h.Metrics.StreamsClosed.Add(1) 162 for { 163 logger.Debugf("Attempting to read seek info message from %s", addr) 164 envelope, err := srv.Recv() 165 if err == io.EOF { 166 logger.Debugf("Received EOF from %s, hangup", addr) 167 return nil 168 } 169 if err != nil { 170 logger.Warningf("Error reading from %s: %s", addr, err) 171 return err 172 } 173 174 status, err := h.deliverBlocks(ctx, srv, envelope) 175 if err != nil { 176 return err 177 } 178 179 err = srv.SendStatusResponse(status) 180 if status != cb.Status_SUCCESS { 181 return err 182 } 183 if err != nil { 184 logger.Warningf("Error sending to %s: %s", addr, err) 185 return err 186 } 187 188 logger.Debugf("Waiting for new SeekInfo from %s", addr) 189 } 190 } 191 192 func isFiltered(srv *Server) bool { 193 if filtered, ok := srv.ResponseSender.(Filtered); ok { 194 return filtered.IsFiltered() 195 } 196 return false 197 } 198 199 func (h *Handler) deliverBlocks(ctx context.Context, srv *Server, envelope *cb.Envelope) (status cb.Status, err error) { 200 addr := util.ExtractRemoteAddress(ctx) 201 payload, chdr, shdr, err := h.parseEnvelope(ctx, envelope) 202 if err != nil { 203 logger.Warningf("error parsing envelope from %s: %s", addr, err) 204 return cb.Status_BAD_REQUEST, nil 205 } 206 207 chain := h.ChainManager.GetChain(chdr.ChannelId) 208 if chain == nil { 209 // Note, we log this at DEBUG because SDKs will poll waiting for channels to be created 210 // So we would expect our log to be somewhat flooded with these 211 logger.Debugf("Rejecting deliver for %s because channel %s not found", addr, chdr.ChannelId) 212 return cb.Status_NOT_FOUND, nil 213 } 214 215 labels := []string{ 216 "channel", chdr.ChannelId, 217 "filtered", strconv.FormatBool(isFiltered(srv)), 218 "data_type", srv.DataType(), 219 } 220 h.Metrics.RequestsReceived.With(labels...).Add(1) 221 defer func() { 222 labels := append(labels, "success", strconv.FormatBool(status == cb.Status_SUCCESS)) 223 h.Metrics.RequestsCompleted.With(labels...).Add(1) 224 }() 225 226 seekInfo := &ab.SeekInfo{} 227 if err = proto.Unmarshal(payload.Data, seekInfo); err != nil { 228 logger.Warningf("[channel: %s] Received a signed deliver request from %s with malformed seekInfo payload: %s", chdr.ChannelId, addr, err) 229 return cb.Status_BAD_REQUEST, nil 230 } 231 232 erroredChan := chain.Errored() 233 if seekInfo.ErrorResponse == ab.SeekInfo_BEST_EFFORT { 234 // In a 'best effort' delivery of blocks, we should ignore consenter errors 235 // and continue to deliver blocks according to the client's request. 236 erroredChan = nil 237 } 238 select { 239 case <-erroredChan: 240 logger.Warningf("[channel: %s] Rejecting deliver request for %s because of consenter error", chdr.ChannelId, addr) 241 return cb.Status_SERVICE_UNAVAILABLE, nil 242 default: 243 } 244 245 accessControl, err := NewSessionAC(chain, envelope, srv.PolicyChecker, chdr.ChannelId, h.ExpirationCheckFunc) 246 if err != nil { 247 logger.Warningf("[channel: %s] failed to create access control object due to %s", chdr.ChannelId, err) 248 return cb.Status_BAD_REQUEST, nil 249 } 250 251 if err := accessControl.Evaluate(); err != nil { 252 logger.Warningf("[channel: %s] Client authorization revoked for deliver request from %s: %s", chdr.ChannelId, addr, err) 253 return cb.Status_FORBIDDEN, nil 254 } 255 256 if seekInfo.Start == nil || seekInfo.Stop == nil { 257 logger.Warningf("[channel: %s] Received seekInfo message from %s with missing start or stop %v, %v", chdr.ChannelId, addr, seekInfo.Start, seekInfo.Stop) 258 return cb.Status_BAD_REQUEST, nil 259 } 260 261 logger.Debugf("[channel: %s] Received seekInfo (%p) %v from %s", chdr.ChannelId, seekInfo, seekInfo, addr) 262 263 cursor, number := chain.Reader().Iterator(seekInfo.Start) 264 defer cursor.Close() 265 var stopNum uint64 266 switch stop := seekInfo.Stop.Type.(type) { 267 case *ab.SeekPosition_Oldest: 268 stopNum = number 269 case *ab.SeekPosition_Newest: 270 // when seeking only the newest block (i.e. starting 271 // and stopping at newest), don't reevaluate the ledger 272 // height as this can lead to multiple blocks being 273 // sent when only one is expected 274 if proto.Equal(seekInfo.Start, seekInfo.Stop) { 275 stopNum = number 276 break 277 } 278 stopNum = chain.Reader().Height() - 1 279 case *ab.SeekPosition_Specified: 280 stopNum = stop.Specified.Number 281 if stopNum < number { 282 logger.Warningf("[channel: %s] Received invalid seekInfo message from %s: start number %d greater than stop number %d", chdr.ChannelId, addr, number, stopNum) 283 return cb.Status_BAD_REQUEST, nil 284 } 285 } 286 287 for { 288 if seekInfo.Behavior == ab.SeekInfo_FAIL_IF_NOT_READY { 289 if number > chain.Reader().Height()-1 { 290 return cb.Status_NOT_FOUND, nil 291 } 292 } 293 294 var block *cb.Block 295 var status cb.Status 296 297 iterCh := make(chan struct{}) 298 go func() { 299 block, status = cursor.Next() 300 close(iterCh) 301 }() 302 303 select { 304 case <-ctx.Done(): 305 logger.Debugf("Context canceled, aborting wait for next block") 306 return cb.Status_INTERNAL_SERVER_ERROR, errors.Wrapf(ctx.Err(), "context finished before block retrieved") 307 case <-erroredChan: 308 // TODO, today, the only user of the errorChan is the orderer consensus implementations. If the peer ever reports 309 // this error, we will need to update this error message, possibly finding a way to signal what error text to return. 310 logger.Warningf("Aborting deliver for request because the backing consensus implementation indicates an error") 311 return cb.Status_SERVICE_UNAVAILABLE, nil 312 case <-iterCh: 313 // Iterator has set the block and status vars 314 } 315 316 if status != cb.Status_SUCCESS { 317 logger.Errorf("[channel: %s] Error reading from channel, cause was: %v", chdr.ChannelId, status) 318 return status, nil 319 } 320 321 // increment block number to support FAIL_IF_NOT_READY deliver behavior 322 number++ 323 324 if err := accessControl.Evaluate(); err != nil { 325 logger.Warningf("[channel: %s] Client authorization revoked for deliver request from %s: %s", chdr.ChannelId, addr, err) 326 return cb.Status_FORBIDDEN, nil 327 } 328 329 logger.Debugf("[channel: %s] Delivering block [%d] for (%p) for %s", chdr.ChannelId, block.Header.Number, seekInfo, addr) 330 331 signedData := &protoutil.SignedData{Data: envelope.Payload, Identity: shdr.Creator, Signature: envelope.Signature} 332 if err := srv.SendBlockResponse(block, chdr.ChannelId, chain, signedData); err != nil { 333 logger.Warningf("[channel: %s] Error sending to %s: %s", chdr.ChannelId, addr, err) 334 return cb.Status_INTERNAL_SERVER_ERROR, err 335 } 336 337 h.Metrics.BlocksSent.With(labels...).Add(1) 338 339 if stopNum == block.Header.Number { 340 break 341 } 342 } 343 344 logger.Debugf("[channel: %s] Done delivering to %s for (%p)", chdr.ChannelId, addr, seekInfo) 345 346 return cb.Status_SUCCESS, nil 347 } 348 349 func (h *Handler) parseEnvelope(ctx context.Context, envelope *cb.Envelope) (*cb.Payload, *cb.ChannelHeader, *cb.SignatureHeader, error) { 350 payload, err := protoutil.UnmarshalPayload(envelope.Payload) 351 if err != nil { 352 return nil, nil, nil, err 353 } 354 355 if payload.Header == nil { 356 return nil, nil, nil, errors.New("envelope has no header") 357 } 358 359 chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader) 360 if err != nil { 361 return nil, nil, nil, err 362 } 363 364 shdr, err := protoutil.UnmarshalSignatureHeader(payload.Header.SignatureHeader) 365 if err != nil { 366 return nil, nil, nil, err 367 } 368 369 err = h.validateChannelHeader(ctx, chdr) 370 if err != nil { 371 return nil, nil, nil, err 372 } 373 374 return payload, chdr, shdr, nil 375 } 376 377 func (h *Handler) validateChannelHeader(ctx context.Context, chdr *cb.ChannelHeader) error { 378 if chdr.GetTimestamp() == nil { 379 err := errors.New("channel header in envelope must contain timestamp") 380 return err 381 } 382 383 envTime := time.Unix(chdr.GetTimestamp().Seconds, int64(chdr.GetTimestamp().Nanos)).UTC() 384 serverTime := time.Now() 385 386 if math.Abs(float64(serverTime.UnixNano()-envTime.UnixNano())) > float64(h.TimeWindow.Nanoseconds()) { 387 err := errors.Errorf("envelope timestamp %s is more than %s apart from current server time %s", envTime, h.TimeWindow, serverTime) 388 return err 389 } 390 391 err := h.BindingInspector.Inspect(ctx, chdr) 392 if err != nil { 393 return err 394 } 395 396 return nil 397 } 398 399 func noExpiration(_ []byte) time.Time { 400 return time.Time{} 401 }