github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/peer/deliverevents.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package peer
     8  
     9  import (
    10  	"runtime/debug"
    11  
    12  	"github.com/hechain20/hechain/common/deliver"
    13  	"github.com/hechain20/hechain/common/flogging"
    14  	"github.com/hechain20/hechain/core/aclmgmt/resources"
    15  	"github.com/hechain20/hechain/core/common/privdata"
    16  	"github.com/hechain20/hechain/core/ledger"
    17  	"github.com/hechain20/hechain/internal/pkg/txflags"
    18  	"github.com/hechain20/hechain/msp"
    19  	"github.com/hechain20/hechain/msp/mgmt"
    20  	"github.com/hechain20/hechain/protoutil"
    21  	"github.com/hyperledger/fabric-protos-go/common"
    22  	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
    23  	"github.com/hyperledger/fabric-protos-go/peer"
    24  	"github.com/pkg/errors"
    25  )
    26  
    27  var logger = flogging.MustGetLogger("common.deliverevents")
    28  
    29  // PolicyCheckerProvider provides the corresponding policy checker for a
    30  // given resource name
    31  type PolicyCheckerProvider func(resourceName string) deliver.PolicyCheckerFunc
    32  
    33  // DeliverServer holds the dependencies necessary to create a deliver server
    34  type DeliverServer struct {
    35  	DeliverHandler          *deliver.Handler
    36  	PolicyCheckerProvider   PolicyCheckerProvider
    37  	CollectionPolicyChecker CollectionPolicyChecker
    38  	IdentityDeserializerMgr IdentityDeserializerManager
    39  }
    40  
    41  // Chain adds Ledger() to deliver.Chain
    42  type Chain interface {
    43  	deliver.Chain
    44  	Ledger() ledger.PeerLedger
    45  }
    46  
    47  // CollectionPolicyChecker is an interface that encapsulates the CheckCollectionPolicy method
    48  type CollectionPolicyChecker interface {
    49  	CheckCollectionPolicy(blockNum uint64, ccName string, collName string, cfgHistoryRetriever ledger.ConfigHistoryRetriever, deserializer msp.IdentityDeserializer, signedData *protoutil.SignedData) (bool, error)
    50  }
    51  
    52  // IdentityDeserializerManager returns instances of Deserializer
    53  type IdentityDeserializerManager interface {
    54  	// Deserializer returns an instance of transaction.Deserializer for the passed channel
    55  	// if the channel exists
    56  	Deserializer(channel string) (msp.IdentityDeserializer, error)
    57  }
    58  
    59  // blockResponseSender structure used to send block responses
    60  type blockResponseSender struct {
    61  	peer.Deliver_DeliverServer
    62  }
    63  
    64  // SendStatusResponse generates status reply proto message
    65  func (brs *blockResponseSender) SendStatusResponse(status common.Status) error {
    66  	reply := &peer.DeliverResponse{
    67  		Type: &peer.DeliverResponse_Status{Status: status},
    68  	}
    69  	return brs.Send(reply)
    70  }
    71  
    72  // SendBlockResponse generates deliver response with block message.
    73  func (brs *blockResponseSender) SendBlockResponse(
    74  	block *common.Block,
    75  	channelID string,
    76  	chain deliver.Chain,
    77  	signedData *protoutil.SignedData,
    78  ) error {
    79  	// Generates filtered block response
    80  	response := &peer.DeliverResponse{
    81  		Type: &peer.DeliverResponse_Block{Block: block},
    82  	}
    83  	return brs.Send(response)
    84  }
    85  
    86  func (brs *blockResponseSender) DataType() string {
    87  	return "block"
    88  }
    89  
    90  // filteredBlockResponseSender structure used to send filtered block responses
    91  type filteredBlockResponseSender struct {
    92  	peer.Deliver_DeliverFilteredServer
    93  }
    94  
    95  // SendStatusResponse generates status reply proto message
    96  func (fbrs *filteredBlockResponseSender) SendStatusResponse(status common.Status) error {
    97  	response := &peer.DeliverResponse{
    98  		Type: &peer.DeliverResponse_Status{Status: status},
    99  	}
   100  	return fbrs.Send(response)
   101  }
   102  
   103  // IsFiltered is a marker method which indicates that this response sender
   104  // sends filtered blocks.
   105  func (fbrs *filteredBlockResponseSender) IsFiltered() bool {
   106  	return true
   107  }
   108  
   109  // SendBlockResponse generates deliver response with filtered block message
   110  func (fbrs *filteredBlockResponseSender) SendBlockResponse(
   111  	block *common.Block,
   112  	channelID string,
   113  	chain deliver.Chain,
   114  	signedData *protoutil.SignedData,
   115  ) error {
   116  	// Generates filtered block response
   117  	b := blockEvent(*block)
   118  	filteredBlock, err := b.toFilteredBlock()
   119  	if err != nil {
   120  		logger.Warningf("Failed to generate filtered block due to: %s", err)
   121  		return fbrs.SendStatusResponse(common.Status_BAD_REQUEST)
   122  	}
   123  	response := &peer.DeliverResponse{
   124  		Type: &peer.DeliverResponse_FilteredBlock{FilteredBlock: filteredBlock},
   125  	}
   126  	return fbrs.Send(response)
   127  }
   128  
   129  func (fbrs *filteredBlockResponseSender) DataType() string {
   130  	return "filtered_block"
   131  }
   132  
   133  // blockResponseSender structure used to send block responses
   134  type blockAndPrivateDataResponseSender struct {
   135  	peer.Deliver_DeliverWithPrivateDataServer
   136  	CollectionPolicyChecker
   137  	IdentityDeserializerManager
   138  }
   139  
   140  // SendStatusResponse generates status reply proto message
   141  func (bprs *blockAndPrivateDataResponseSender) SendStatusResponse(status common.Status) error {
   142  	reply := &peer.DeliverResponse{
   143  		Type: &peer.DeliverResponse_Status{Status: status},
   144  	}
   145  	return bprs.Send(reply)
   146  }
   147  
   148  // SendBlockResponse gets private data and generates deliver response with both block and private data
   149  func (bprs *blockAndPrivateDataResponseSender) SendBlockResponse(
   150  	block *common.Block,
   151  	channelID string,
   152  	chain deliver.Chain,
   153  	signedData *protoutil.SignedData,
   154  ) error {
   155  	pvtData, err := bprs.getPrivateData(block, chain, channelID, signedData)
   156  	if err != nil {
   157  		return err
   158  	}
   159  
   160  	blockAndPvtData := &peer.BlockAndPrivateData{
   161  		Block:          block,
   162  		PrivateDataMap: pvtData,
   163  	}
   164  	response := &peer.DeliverResponse{
   165  		Type: &peer.DeliverResponse_BlockAndPrivateData{BlockAndPrivateData: blockAndPvtData},
   166  	}
   167  	return bprs.Send(response)
   168  }
   169  
   170  func (bprs *blockAndPrivateDataResponseSender) DataType() string {
   171  	return "block_and_pvtdata"
   172  }
   173  
   174  // getPrivateData returns private data for the block
   175  func (bprs *blockAndPrivateDataResponseSender) getPrivateData(
   176  	block *common.Block,
   177  	chain deliver.Chain,
   178  	channelID string,
   179  	signedData *protoutil.SignedData,
   180  ) (map[uint64]*rwset.TxPvtReadWriteSet, error) {
   181  	channel, ok := chain.(Chain)
   182  	if !ok {
   183  		return nil, errors.New("wrong chain type")
   184  	}
   185  
   186  	pvtData, err := channel.Ledger().GetPvtDataByNum(block.Header.Number, nil)
   187  	if err != nil {
   188  		logger.Errorf("Error getting private data by block number %d on channel %s", block.Header.Number, channelID)
   189  		return nil, errors.Wrapf(err, "error getting private data by block number %d", block.Header.Number)
   190  	}
   191  
   192  	seqs2Namespaces := aggregatedCollections(make(map[seqAndDataModel]map[string][]*rwset.CollectionPvtReadWriteSet))
   193  
   194  	configHistoryRetriever, err := channel.Ledger().GetConfigHistoryRetriever()
   195  	if err != nil {
   196  		return nil, err
   197  	}
   198  
   199  	identityDeserializer, err := bprs.IdentityDeserializerManager.Deserializer(channelID)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  
   204  	// check policy for each collection and add the collection if passing the policy requirement
   205  	for _, item := range pvtData {
   206  		logger.Debugf("Got private data for block number %d, tx sequence %d", block.Header.Number, item.SeqInBlock)
   207  		if item.WriteSet == nil {
   208  			continue
   209  		}
   210  		for _, ns := range item.WriteSet.NsPvtRwset {
   211  			for _, col := range ns.CollectionPvtRwset {
   212  				logger.Debugf("Checking policy for namespace %s, collection %s", ns.Namespace, col.CollectionName)
   213  
   214  				eligible, err := bprs.CollectionPolicyChecker.CheckCollectionPolicy(block.Header.Number,
   215  					ns.Namespace, col.CollectionName, configHistoryRetriever, identityDeserializer, signedData)
   216  				if err != nil {
   217  					return nil, err
   218  				}
   219  
   220  				if eligible {
   221  					logger.Debugf("Adding private data for namespace %s, collection %s", ns.Namespace, col.CollectionName)
   222  					seqs2Namespaces.addCollection(item.SeqInBlock, item.WriteSet.DataModel, ns.Namespace, col)
   223  				}
   224  			}
   225  		}
   226  	}
   227  
   228  	return seqs2Namespaces.asPrivateDataMap(), nil
   229  }
   230  
   231  // transactionActions aliasing for peer.TransactionAction pointers slice
   232  type transactionActions []*peer.TransactionAction
   233  
   234  // blockEvent an alias for common.Block structure, used to
   235  // extend with auxiliary functionality
   236  type blockEvent common.Block
   237  
   238  // DeliverFiltered sends a stream of blocks to a client after commitment
   239  func (s *DeliverServer) DeliverFiltered(srv peer.Deliver_DeliverFilteredServer) error {
   240  	logger.Debugf("Starting new DeliverFiltered handler")
   241  	defer dumpStacktraceOnPanic()
   242  	// getting policy checker based on resources.Event_FilteredBlock resource name
   243  	deliverServer := &deliver.Server{
   244  		Receiver:      srv,
   245  		PolicyChecker: s.PolicyCheckerProvider(resources.Event_FilteredBlock),
   246  		ResponseSender: &filteredBlockResponseSender{
   247  			Deliver_DeliverFilteredServer: srv,
   248  		},
   249  	}
   250  	return s.DeliverHandler.Handle(srv.Context(), deliverServer)
   251  }
   252  
   253  // Deliver sends a stream of blocks to a client after commitment
   254  func (s *DeliverServer) Deliver(srv peer.Deliver_DeliverServer) (err error) {
   255  	logger.Debugf("Starting new Deliver handler")
   256  	defer dumpStacktraceOnPanic()
   257  	// getting policy checker based on resources.Event_Block resource name
   258  	deliverServer := &deliver.Server{
   259  		PolicyChecker: s.PolicyCheckerProvider(resources.Event_Block),
   260  		Receiver:      srv,
   261  		ResponseSender: &blockResponseSender{
   262  			Deliver_DeliverServer: srv,
   263  		},
   264  	}
   265  	return s.DeliverHandler.Handle(srv.Context(), deliverServer)
   266  }
   267  
   268  // DeliverWithPrivateData sends a stream of blocks and pvtdata to a client after commitment
   269  func (s *DeliverServer) DeliverWithPrivateData(srv peer.Deliver_DeliverWithPrivateDataServer) (err error) {
   270  	logger.Debug("Starting new DeliverWithPrivateData handler")
   271  	defer dumpStacktraceOnPanic()
   272  	if s.CollectionPolicyChecker == nil {
   273  		s.CollectionPolicyChecker = &collPolicyChecker{}
   274  	}
   275  	if s.IdentityDeserializerMgr == nil {
   276  		s.IdentityDeserializerMgr = &identityDeserializerMgr{}
   277  	}
   278  	// getting policy checker based on resources.Event_Block resource name
   279  	deliverServer := &deliver.Server{
   280  		PolicyChecker: s.PolicyCheckerProvider(resources.Event_Block),
   281  		Receiver:      srv,
   282  		ResponseSender: &blockAndPrivateDataResponseSender{
   283  			Deliver_DeliverWithPrivateDataServer: srv,
   284  			CollectionPolicyChecker:              s.CollectionPolicyChecker,
   285  			IdentityDeserializerManager:          s.IdentityDeserializerMgr,
   286  		},
   287  	}
   288  	err = s.DeliverHandler.Handle(srv.Context(), deliverServer)
   289  	return err
   290  }
   291  
   292  func (block *blockEvent) toFilteredBlock() (*peer.FilteredBlock, error) {
   293  	filteredBlock := &peer.FilteredBlock{
   294  		Number: block.Header.Number,
   295  	}
   296  
   297  	txsFltr := txflags.ValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   298  	for txIndex, ebytes := range block.Data.Data {
   299  		var env *common.Envelope
   300  		var err error
   301  
   302  		if ebytes == nil {
   303  			logger.Debugf("got nil data bytes for tx index %d, block num %d", txIndex, block.Header.Number)
   304  			continue
   305  		}
   306  
   307  		env, err = protoutil.GetEnvelopeFromBlock(ebytes)
   308  		if err != nil {
   309  			logger.Errorf("error getting tx from block, %s", err)
   310  			continue
   311  		}
   312  
   313  		// get the payload from the envelope
   314  		payload, err := protoutil.UnmarshalPayload(env.Payload)
   315  		if err != nil {
   316  			return nil, errors.WithMessage(err, "could not extract payload from envelope")
   317  		}
   318  
   319  		if payload.Header == nil {
   320  			logger.Debugf("transaction payload header is nil, %d, block num %d", txIndex, block.Header.Number)
   321  			continue
   322  		}
   323  		chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   324  		if err != nil {
   325  			return nil, err
   326  		}
   327  
   328  		filteredBlock.ChannelId = chdr.ChannelId
   329  
   330  		filteredTransaction := &peer.FilteredTransaction{
   331  			Txid:             chdr.TxId,
   332  			Type:             common.HeaderType(chdr.Type),
   333  			TxValidationCode: txsFltr.Flag(txIndex),
   334  		}
   335  
   336  		if filteredTransaction.Type == common.HeaderType_ENDORSER_TRANSACTION {
   337  			tx, err := protoutil.UnmarshalTransaction(payload.Data)
   338  			if err != nil {
   339  				return nil, errors.WithMessage(err, "error unmarshal transaction payload for block event")
   340  			}
   341  
   342  			filteredTransaction.Data, err = transactionActions(tx.Actions).toFilteredActions()
   343  			if err != nil {
   344  				logger.Errorf(err.Error())
   345  				return nil, err
   346  			}
   347  		}
   348  
   349  		filteredBlock.FilteredTransactions = append(filteredBlock.FilteredTransactions, filteredTransaction)
   350  	}
   351  
   352  	return filteredBlock, nil
   353  }
   354  
   355  func (ta transactionActions) toFilteredActions() (*peer.FilteredTransaction_TransactionActions, error) {
   356  	transactionActions := &peer.FilteredTransactionActions{}
   357  	for _, action := range ta {
   358  		chaincodeActionPayload, err := protoutil.UnmarshalChaincodeActionPayload(action.Payload)
   359  		if err != nil {
   360  			return nil, errors.WithMessage(err, "error unmarshal transaction action payload for block event")
   361  		}
   362  
   363  		if chaincodeActionPayload.Action == nil {
   364  			logger.Debugf("chaincode action, the payload action is nil, skipping")
   365  			continue
   366  		}
   367  		propRespPayload, err := protoutil.UnmarshalProposalResponsePayload(chaincodeActionPayload.Action.ProposalResponsePayload)
   368  		if err != nil {
   369  			return nil, errors.WithMessage(err, "error unmarshal proposal response payload for block event")
   370  		}
   371  
   372  		caPayload, err := protoutil.UnmarshalChaincodeAction(propRespPayload.Extension)
   373  		if err != nil {
   374  			return nil, errors.WithMessage(err, "error unmarshal chaincode action for block event")
   375  		}
   376  
   377  		ccEvent, err := protoutil.UnmarshalChaincodeEvents(caPayload.Events)
   378  		if err != nil {
   379  			return nil, errors.WithMessage(err, "error unmarshal chaincode event for block event")
   380  		}
   381  
   382  		if ccEvent.GetChaincodeId() != "" {
   383  			filteredAction := &peer.FilteredChaincodeAction{
   384  				ChaincodeEvent: &peer.ChaincodeEvent{
   385  					TxId:        ccEvent.TxId,
   386  					ChaincodeId: ccEvent.ChaincodeId,
   387  					EventName:   ccEvent.EventName,
   388  				},
   389  			}
   390  			transactionActions.ChaincodeActions = append(transactionActions.ChaincodeActions, filteredAction)
   391  		}
   392  	}
   393  	return &peer.FilteredTransaction_TransactionActions{
   394  		TransactionActions: transactionActions,
   395  	}, nil
   396  }
   397  
   398  func dumpStacktraceOnPanic() {
   399  	func() {
   400  		if r := recover(); r != nil {
   401  			logger.Criticalf("Deliver client triggered panic: %s\n%s", r, debug.Stack())
   402  		}
   403  		logger.Debugf("Closing Deliver stream")
   404  	}()
   405  }
   406  
   407  type seqAndDataModel struct {
   408  	seq       uint64
   409  	dataModel rwset.TxReadWriteSet_DataModel
   410  }
   411  
   412  // Below map temporarily stores the private data that have passed the corresponding collection policy.
   413  // outer map is from seqAndDataModel to inner map,
   414  // and innner map is from namespace to []*rwset.CollectionPvtReadWriteSet
   415  type aggregatedCollections map[seqAndDataModel]map[string][]*rwset.CollectionPvtReadWriteSet
   416  
   417  // addCollection adds private data based on seq, namespace, and collection.
   418  func (ac aggregatedCollections) addCollection(seqInBlock uint64, dm rwset.TxReadWriteSet_DataModel, namespace string, col *rwset.CollectionPvtReadWriteSet) {
   419  	seq := seqAndDataModel{
   420  		dataModel: dm,
   421  		seq:       seqInBlock,
   422  	}
   423  	if _, exists := ac[seq]; !exists {
   424  		ac[seq] = make(map[string][]*rwset.CollectionPvtReadWriteSet)
   425  	}
   426  	ac[seq][namespace] = append(ac[seq][namespace], col)
   427  }
   428  
   429  // asPrivateDataMap converts aggregatedCollections to map[uint64]*rwset.TxPvtReadWriteSet
   430  // as defined in BlockAndPrivateData protobuf message.
   431  func (ac aggregatedCollections) asPrivateDataMap() map[uint64]*rwset.TxPvtReadWriteSet {
   432  	pvtDataMap := make(map[uint64]*rwset.TxPvtReadWriteSet)
   433  	for seq, ns := range ac {
   434  		// create a txPvtReadWriteSet and add collection data to it
   435  		txPvtRWSet := &rwset.TxPvtReadWriteSet{
   436  			DataModel: seq.dataModel,
   437  		}
   438  
   439  		for namespaceName, cols := range ns {
   440  			txPvtRWSet.NsPvtRwset = append(txPvtRWSet.NsPvtRwset, &rwset.NsPvtReadWriteSet{
   441  				Namespace:          namespaceName,
   442  				CollectionPvtRwset: cols,
   443  			})
   444  		}
   445  
   446  		pvtDataMap[seq.seq] = txPvtRWSet
   447  	}
   448  	return pvtDataMap
   449  }
   450  
   451  // identityDeserializerMgr implements an IdentityDeserializerManager
   452  // by routing the call to the msp/mgmt package
   453  type identityDeserializerMgr struct{}
   454  
   455  func (*identityDeserializerMgr) Deserializer(channelID string) (msp.IdentityDeserializer, error) {
   456  	id, ok := mgmt.GetDeserializers()[channelID]
   457  	if !ok {
   458  		return nil, errors.Errorf("channel %s not found", channelID)
   459  	}
   460  	return id, nil
   461  }
   462  
   463  // collPolicyChecker is the default implementation for CollectionPolicyChecker interface
   464  type collPolicyChecker struct{}
   465  
   466  // CheckCollectionPolicy checks if the CollectionCriteria meets the policy requirement
   467  func (cs *collPolicyChecker) CheckCollectionPolicy(
   468  	blockNum uint64,
   469  	ccName string,
   470  	collName string,
   471  	cfgHistoryRetriever ledger.ConfigHistoryRetriever,
   472  	deserializer msp.IdentityDeserializer,
   473  	signedData *protoutil.SignedData,
   474  ) (bool, error) {
   475  	configInfo, err := cfgHistoryRetriever.MostRecentCollectionConfigBelow(blockNum, ccName)
   476  	if err != nil {
   477  		return false, errors.WithMessagef(err, "error getting most recent collection config below block sequence = %d for chaincode %s", blockNum, ccName)
   478  	}
   479  
   480  	staticCollConfig := extractStaticCollectionConfig(configInfo.CollectionConfig, collName)
   481  	if staticCollConfig == nil {
   482  		return false, errors.Errorf("no collection config was found for collection %s for chaincode %s", collName, ccName)
   483  	}
   484  
   485  	if !staticCollConfig.MemberOnlyRead {
   486  		return true, nil
   487  	}
   488  
   489  	// get collection access policy and access filter to check eligibility
   490  	collAP := &privdata.SimpleCollection{}
   491  	err = collAP.Setup(staticCollConfig, deserializer)
   492  	if err != nil {
   493  		return false, errors.WithMessagef(err, "error setting up collection  %s", staticCollConfig.Name)
   494  	}
   495  	logger.Debugf("got collection access policy")
   496  
   497  	collFilter := collAP.AccessFilter()
   498  	if collFilter == nil {
   499  		logger.Debugf("collection %s has no access filter, skipping...", collName)
   500  		return false, nil
   501  	}
   502  
   503  	eligible := collFilter(*signedData)
   504  	return eligible, nil
   505  }
   506  
   507  func extractStaticCollectionConfig(configPackage *peer.CollectionConfigPackage, collectionName string) *peer.StaticCollectionConfig {
   508  	for _, config := range configPackage.Config {
   509  		switch cconf := config.Payload.(type) {
   510  		case *peer.CollectionConfig_StaticCollectionConfig:
   511  			if cconf.StaticCollectionConfig.Name == collectionName {
   512  				return cconf.StaticCollectionConfig
   513  			}
   514  		default:
   515  			return nil
   516  		}
   517  	}
   518  	return nil
   519  }