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  }