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