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  }