github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/committer/txvalidator/v14/validator.go (about)

     1  /*
     2  Copyright hechain. 2022 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package txvalidator
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  	"time"
    13  
    14  	"github.com/golang/protobuf/proto"
    15  	"github.com/hechain20/hechain/bccsp"
    16  	"github.com/hechain20/hechain/common/channelconfig"
    17  	"github.com/hechain20/hechain/common/configtx"
    18  	commonerrors "github.com/hechain20/hechain/common/errors"
    19  	"github.com/hechain20/hechain/common/flogging"
    20  	"github.com/hechain20/hechain/core/committer/txvalidator/plugin"
    21  	"github.com/hechain20/hechain/core/common/sysccprovider"
    22  	"github.com/hechain20/hechain/core/common/validation"
    23  	"github.com/hechain20/hechain/core/ledger"
    24  	"github.com/hechain20/hechain/internal/pkg/txflags"
    25  	"github.com/hechain20/hechain/msp"
    26  	"github.com/hechain20/hechain/protoutil"
    27  	"github.com/hyperledger/fabric-protos-go/common"
    28  	mspprotos "github.com/hyperledger/fabric-protos-go/msp"
    29  	"github.com/hyperledger/fabric-protos-go/peer"
    30  	"github.com/pkg/errors"
    31  )
    32  
    33  // Semaphore provides to the validator means for synchronisation
    34  type Semaphore interface {
    35  	// Acquire implements semaphore-like acquire semantics
    36  	Acquire(ctx context.Context) error
    37  
    38  	// Release implements semaphore-like release semantics
    39  	Release()
    40  }
    41  
    42  // ChannelResources provides access to channel artefacts or
    43  // functions to interact with them
    44  type ChannelResources interface {
    45  	// Ledger returns the ledger associated with this validator
    46  	Ledger() ledger.PeerLedger
    47  
    48  	// MSPManager returns the MSP manager for this channel
    49  	MSPManager() msp.MSPManager
    50  
    51  	// Apply attempts to apply a configtx to become the new config
    52  	Apply(configtx *common.ConfigEnvelope) error
    53  
    54  	// GetMSPIDs returns the IDs for the application MSPs
    55  	// that have been defined in the channel
    56  	GetMSPIDs() []string
    57  
    58  	// Capabilities defines the capabilities for the application portion of this channel
    59  	Capabilities() channelconfig.ApplicationCapabilities
    60  }
    61  
    62  // private interface to decouple tx validator
    63  // and vscc execution, in order to increase
    64  // testability of TxValidator
    65  type vsccValidator interface {
    66  	VSCCValidateTx(seq int, payload *common.Payload, envBytes []byte, block *common.Block) (peer.TxValidationCode, error)
    67  }
    68  
    69  // implementation of Validator interface, keeps
    70  // reference to the ledger to enable tx simulation
    71  // and execution of vscc
    72  type TxValidator struct {
    73  	ChannelID        string
    74  	Semaphore        Semaphore
    75  	ChannelResources ChannelResources
    76  	Vscc             vsccValidator
    77  	CryptoProvider   bccsp.BCCSP
    78  }
    79  
    80  var logger = flogging.MustGetLogger("committer.txvalidator")
    81  
    82  type blockValidationRequest struct {
    83  	block *common.Block
    84  	d     []byte
    85  	tIdx  int
    86  }
    87  
    88  type blockValidationResult struct {
    89  	tIdx                 int
    90  	validationCode       peer.TxValidationCode
    91  	txsChaincodeName     *sysccprovider.ChaincodeInstance
    92  	txsUpgradedChaincode *sysccprovider.ChaincodeInstance
    93  	err                  error
    94  	txid                 string
    95  }
    96  
    97  // NewTxValidator creates new transactions validator
    98  func NewTxValidator(channelID string, sem Semaphore, cr ChannelResources, pm plugin.Mapper, cryptoProvider bccsp.BCCSP) *TxValidator {
    99  	// Encapsulates interface implementation
   100  	pluginValidator := NewPluginValidator(pm, cr.Ledger(), &dynamicDeserializer{cr: cr}, &dynamicCapabilities{cr: cr})
   101  	return &TxValidator{
   102  		ChannelID:        channelID,
   103  		Semaphore:        sem,
   104  		ChannelResources: cr,
   105  		Vscc:             newVSCCValidator(channelID, cr, pluginValidator),
   106  		CryptoProvider:   cryptoProvider,
   107  	}
   108  }
   109  
   110  func (v *TxValidator) chainExists(chain string) bool {
   111  	// TODO: implement this function!
   112  	return true
   113  }
   114  
   115  // Validate performs the validation of a block. The validation
   116  // of each transaction in the block is performed in parallel.
   117  // The approach is as follows: the committer thread starts the
   118  // tx validation function in a goroutine (using a semaphore to cap
   119  // the number of concurrent validating goroutines). The committer
   120  // thread then reads results of validation (in orderer of completion
   121  // of the goroutines) from the results channel. The goroutines
   122  // perform the validation of the txs in the block and enqueue the
   123  // validation result in the results channel. A few note-worthy facts:
   124  // 1) to keep the approach simple, the committer thread enqueues
   125  //    all transactions in the block and then moves on to reading the
   126  //    results.
   127  // 2) for parallel validation to work, it is important that the
   128  //    validation function does not change the state of the system.
   129  //    Otherwise the order in which validation is perform matters
   130  //    and we have to resort to sequential validation (or some locking).
   131  //    This is currently true, because the only function that affects
   132  //    state is when a config transaction is received, but they are
   133  //    guaranteed to be alone in the block. If/when this assumption
   134  //    is violated, this code must be changed.
   135  func (v *TxValidator) Validate(block *common.Block) error {
   136  	var err error
   137  	var errPos int
   138  
   139  	startValidation := time.Now() // timer to log Validate block duration
   140  	logger.Debugf("[%s] START Block Validation for block [%d]", v.ChannelID, block.Header.Number)
   141  
   142  	// Initialize trans as not_validated here, then set invalidation reason code upon invalidation below
   143  	txsfltr := txflags.New(len(block.Data.Data))
   144  	// txsChaincodeNames records all the invoked chaincodes by tx in a block
   145  	txsChaincodeNames := make(map[int]*sysccprovider.ChaincodeInstance)
   146  	// upgradedChaincodes records all the chaincodes that are upgraded in a block
   147  	txsUpgradedChaincodes := make(map[int]*sysccprovider.ChaincodeInstance)
   148  	// array of txids
   149  	txidArray := make([]string, len(block.Data.Data))
   150  
   151  	results := make(chan *blockValidationResult)
   152  	go func() {
   153  		for tIdx, d := range block.Data.Data {
   154  			// ensure that we don't have too many concurrent validation workers
   155  			v.Semaphore.Acquire(context.Background())
   156  
   157  			go func(index int, data []byte) {
   158  				defer v.Semaphore.Release()
   159  
   160  				v.validateTx(&blockValidationRequest{
   161  					d:     data,
   162  					block: block,
   163  					tIdx:  index,
   164  				}, results)
   165  			}(tIdx, d)
   166  		}
   167  	}()
   168  
   169  	logger.Debugf("expecting %d block validation responses", len(block.Data.Data))
   170  
   171  	// now we read responses in the order in which they come back
   172  	for i := 0; i < len(block.Data.Data); i++ {
   173  		res := <-results
   174  
   175  		if res.err != nil {
   176  			// if there is an error, we buffer its value, wait for
   177  			// all workers to complete validation and then return
   178  			// the error from the first tx in this block that returned an error
   179  			logger.Debugf("got terminal error %s for idx %d", res.err, res.tIdx)
   180  
   181  			if err == nil || res.tIdx < errPos {
   182  				err = res.err
   183  				errPos = res.tIdx
   184  			}
   185  		} else {
   186  			// if there was no error, we set the txsfltr and we set the
   187  			// txsChaincodeNames and txsUpgradedChaincodes maps
   188  			logger.Debugf("got result for idx %d, code %d", res.tIdx, res.validationCode)
   189  
   190  			txsfltr.SetFlag(res.tIdx, res.validationCode)
   191  
   192  			if res.validationCode == peer.TxValidationCode_VALID {
   193  				if res.txsChaincodeName != nil {
   194  					txsChaincodeNames[res.tIdx] = res.txsChaincodeName
   195  				}
   196  				if res.txsUpgradedChaincode != nil {
   197  					txsUpgradedChaincodes[res.tIdx] = res.txsUpgradedChaincode
   198  				}
   199  				txidArray[res.tIdx] = res.txid
   200  			}
   201  		}
   202  	}
   203  
   204  	// if we're here, all workers have completed the validation.
   205  	// If there was an error we return the error from the first
   206  	// tx in this block that returned an error
   207  	if err != nil {
   208  		return err
   209  	}
   210  
   211  	// if we operate with this capability, we mark invalid any transaction that has a txid
   212  	// which is equal to that of a previous tx in this block
   213  	if v.ChannelResources.Capabilities().ForbidDuplicateTXIdInBlock() {
   214  		markTXIdDuplicates(txidArray, txsfltr)
   215  	}
   216  
   217  	// if we're here, all workers have completed validation and
   218  	// no error was reported; we set the tx filter and return
   219  	// success
   220  	v.invalidTXsForUpgradeCC(txsChaincodeNames, txsUpgradedChaincodes, txsfltr)
   221  
   222  	// make sure no transaction has skipped validation
   223  	err = v.allValidated(txsfltr, block)
   224  	if err != nil {
   225  		return err
   226  	}
   227  
   228  	// Initialize metadata structure
   229  	protoutil.InitBlockMetadata(block)
   230  
   231  	block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsfltr
   232  
   233  	elapsedValidation := time.Since(startValidation) / time.Millisecond // duration in ms
   234  	logger.Infof("[%s] Validated block [%d] in %dms", v.ChannelID, block.Header.Number, elapsedValidation)
   235  
   236  	return nil
   237  }
   238  
   239  // allValidated returns error if some of the validation flags have not been set
   240  // during validation
   241  func (v *TxValidator) allValidated(txsfltr txflags.ValidationFlags, block *common.Block) error {
   242  	for id, f := range txsfltr {
   243  		if peer.TxValidationCode(f) == peer.TxValidationCode_NOT_VALIDATED {
   244  			return errors.Errorf("transaction %d in block %d has skipped validation", id, block.Header.Number)
   245  		}
   246  	}
   247  
   248  	return nil
   249  }
   250  
   251  func markTXIdDuplicates(txids []string, txsfltr txflags.ValidationFlags) {
   252  	txidMap := make(map[string]struct{})
   253  
   254  	for id, txid := range txids {
   255  		if txid == "" {
   256  			continue
   257  		}
   258  
   259  		_, in := txidMap[txid]
   260  		if in {
   261  			logger.Error("Duplicate txid", txid, "found, skipping")
   262  			txsfltr.SetFlag(id, peer.TxValidationCode_DUPLICATE_TXID)
   263  		} else {
   264  			txidMap[txid] = struct{}{}
   265  		}
   266  	}
   267  }
   268  
   269  func (v *TxValidator) validateTx(req *blockValidationRequest, results chan<- *blockValidationResult) {
   270  	block := req.block
   271  	d := req.d
   272  	tIdx := req.tIdx
   273  	txID := ""
   274  
   275  	if d == nil {
   276  		results <- &blockValidationResult{
   277  			tIdx: tIdx,
   278  		}
   279  		return
   280  	}
   281  
   282  	if env, err := protoutil.GetEnvelopeFromBlock(d); err != nil {
   283  		logger.Warningf("Error getting tx from block: %+v", err)
   284  		results <- &blockValidationResult{
   285  			tIdx:           tIdx,
   286  			validationCode: peer.TxValidationCode_INVALID_OTHER_REASON,
   287  		}
   288  		return
   289  	} else if env != nil {
   290  		// validate the transaction: here we check that the transaction
   291  		// is properly formed, properly signed and that the security
   292  		// chain binding proposal to endorsements to tx holds. We do
   293  		// NOT check the validity of endorsements, though. That's a
   294  		// job for VSCC below
   295  		logger.Debugf("[%s] validateTx starts for block %p env %p txn %d", v.ChannelID, block, env, tIdx)
   296  		defer logger.Debugf("[%s] validateTx completes for block %p env %p txn %d", v.ChannelID, block, env, tIdx)
   297  		var payload *common.Payload
   298  		var err error
   299  		var txResult peer.TxValidationCode
   300  		var txsChaincodeName *sysccprovider.ChaincodeInstance
   301  		var txsUpgradedChaincode *sysccprovider.ChaincodeInstance
   302  
   303  		if payload, txResult = validation.ValidateTransaction(env, v.CryptoProvider); txResult != peer.TxValidationCode_VALID {
   304  			logger.Errorf("Invalid transaction with index %d", tIdx)
   305  			results <- &blockValidationResult{
   306  				tIdx:           tIdx,
   307  				validationCode: txResult,
   308  			}
   309  			return
   310  		}
   311  
   312  		chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   313  		if err != nil {
   314  			logger.Warningf("Could not unmarshal channel header, err %s, skipping", err)
   315  			results <- &blockValidationResult{
   316  				tIdx:           tIdx,
   317  				validationCode: peer.TxValidationCode_INVALID_OTHER_REASON,
   318  			}
   319  			return
   320  		}
   321  
   322  		channel := chdr.ChannelId
   323  		logger.Debugf("Transaction is for channel %s", channel)
   324  
   325  		if !v.chainExists(channel) {
   326  			logger.Errorf("Dropping transaction for non-existent channel %s", channel)
   327  			results <- &blockValidationResult{
   328  				tIdx:           tIdx,
   329  				validationCode: peer.TxValidationCode_TARGET_CHAIN_NOT_FOUND,
   330  			}
   331  			return
   332  		}
   333  
   334  		if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
   335  
   336  			txID = chdr.TxId
   337  
   338  			// Check duplicate transactions
   339  			erroneousResultEntry := v.checkTxIdDupsLedger(tIdx, chdr, v.ChannelResources.Ledger())
   340  			if erroneousResultEntry != nil {
   341  				results <- erroneousResultEntry
   342  				return
   343  			}
   344  
   345  			// Validate tx with vscc and policy
   346  			logger.Debug("Validating transaction vscc tx validate")
   347  			cde, err := v.Vscc.VSCCValidateTx(tIdx, payload, d, block)
   348  			if err != nil {
   349  				logger.Errorf("VSCCValidateTx for transaction txId = %s returned error: %s", txID, err)
   350  				switch err.(type) {
   351  				case *commonerrors.VSCCExecutionFailureError:
   352  					results <- &blockValidationResult{
   353  						tIdx: tIdx,
   354  						err:  err,
   355  					}
   356  					return
   357  				case *commonerrors.VSCCInfoLookupFailureError:
   358  					results <- &blockValidationResult{
   359  						tIdx: tIdx,
   360  						err:  err,
   361  					}
   362  					return
   363  				default:
   364  					results <- &blockValidationResult{
   365  						tIdx:           tIdx,
   366  						validationCode: cde,
   367  					}
   368  					return
   369  				}
   370  			}
   371  
   372  			invokeCC, upgradeCC, err := v.getTxCCInstance(payload)
   373  			if err != nil {
   374  				logger.Errorf("Get chaincode instance from transaction txId = %s returned error: %+v", txID, err)
   375  				results <- &blockValidationResult{
   376  					tIdx:           tIdx,
   377  					validationCode: peer.TxValidationCode_INVALID_OTHER_REASON,
   378  				}
   379  				return
   380  			}
   381  			txsChaincodeName = invokeCC
   382  			if upgradeCC != nil {
   383  				logger.Infof("Find chaincode upgrade transaction for chaincode %s on channel %s with new version %s", upgradeCC.ChaincodeName, upgradeCC.ChannelID, upgradeCC.ChaincodeVersion)
   384  				txsUpgradedChaincode = upgradeCC
   385  			}
   386  		} else if common.HeaderType(chdr.Type) == common.HeaderType_CONFIG {
   387  			configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
   388  			if err != nil {
   389  				err = errors.WithMessage(err, "error unmarshalling config which passed initial validity checks")
   390  				logger.Criticalf("%+v", err)
   391  				results <- &blockValidationResult{
   392  					tIdx: tIdx,
   393  					err:  err,
   394  				}
   395  				return
   396  			}
   397  
   398  			if err := v.ChannelResources.Apply(configEnvelope); err != nil {
   399  				err = errors.WithMessage(err, "error validating config which passed initial validity checks")
   400  				logger.Criticalf("%+v", err)
   401  				results <- &blockValidationResult{
   402  					tIdx: tIdx,
   403  					err:  err,
   404  				}
   405  				return
   406  			}
   407  			logger.Debugf("config transaction received for chain %s", channel)
   408  		} else {
   409  			logger.Warningf("Unknown transaction type [%s] in block number [%d] transaction index [%d]",
   410  				common.HeaderType(chdr.Type), block.Header.Number, tIdx)
   411  			results <- &blockValidationResult{
   412  				tIdx:           tIdx,
   413  				validationCode: peer.TxValidationCode_UNKNOWN_TX_TYPE,
   414  			}
   415  			return
   416  		}
   417  
   418  		if _, err := proto.Marshal(env); err != nil {
   419  			logger.Warningf("Cannot marshal transaction: %s", err)
   420  			results <- &blockValidationResult{
   421  				tIdx:           tIdx,
   422  				validationCode: peer.TxValidationCode_MARSHAL_TX_ERROR,
   423  			}
   424  			return
   425  		}
   426  		// Succeeded to pass down here, transaction is valid
   427  		results <- &blockValidationResult{
   428  			tIdx:                 tIdx,
   429  			txsChaincodeName:     txsChaincodeName,
   430  			txsUpgradedChaincode: txsUpgradedChaincode,
   431  			validationCode:       peer.TxValidationCode_VALID,
   432  			txid:                 txID,
   433  		}
   434  		return
   435  	} else {
   436  		logger.Warning("Nil tx from block")
   437  		results <- &blockValidationResult{
   438  			tIdx:           tIdx,
   439  			validationCode: peer.TxValidationCode_NIL_ENVELOPE,
   440  		}
   441  		return
   442  	}
   443  }
   444  
   445  // CheckTxIdDupsLedger returns a vlockValidationResult enhanced with the respective
   446  // error codes if and only if there is transaction with the same transaction identifier
   447  // in the ledger or no decision can be made for whether such transaction exists;
   448  // the function returns nil if it has ensured that there is no such duplicate, such
   449  // that its consumer can proceed with the transaction processing
   450  func (v *TxValidator) checkTxIdDupsLedger(tIdx int, chdr *common.ChannelHeader, ldgr ledger.PeerLedger) *blockValidationResult {
   451  	// Retrieve the transaction identifier of the input header
   452  	txID := chdr.TxId
   453  
   454  	// Look for a transaction with the same identifier inside the ledger
   455  	exists, err := ldgr.TxIDExists(txID)
   456  	if err != nil {
   457  		logger.Errorf("Ledger failure while attempting to detect duplicate status for txid %s: %s", txID, err)
   458  		return &blockValidationResult{
   459  			tIdx: tIdx,
   460  			err:  err,
   461  		}
   462  	}
   463  
   464  	if exists {
   465  		logger.Error("Duplicate transaction found, ", txID, ", skipping")
   466  		return &blockValidationResult{
   467  			tIdx:           tIdx,
   468  			validationCode: peer.TxValidationCode_DUPLICATE_TXID,
   469  		}
   470  	}
   471  
   472  	return nil
   473  }
   474  
   475  // generateCCKey generates a unique identifier for chaincode in specific channel
   476  func (v *TxValidator) generateCCKey(ccName, chainID string) string {
   477  	return fmt.Sprintf("%s/%s", ccName, chainID)
   478  }
   479  
   480  // invalidTXsForUpgradeCC invalid all txs that should be invalided because of chaincode upgrade txs
   481  func (v *TxValidator) invalidTXsForUpgradeCC(txsChaincodeNames map[int]*sysccprovider.ChaincodeInstance, txsUpgradedChaincodes map[int]*sysccprovider.ChaincodeInstance, txsfltr txflags.ValidationFlags) {
   482  	if len(txsUpgradedChaincodes) == 0 {
   483  		return
   484  	}
   485  
   486  	// Invalid former cc upgrade txs if there're two or more txs upgrade the same cc
   487  	finalValidUpgradeTXs := make(map[string]int)
   488  	upgradedChaincodes := make(map[string]*sysccprovider.ChaincodeInstance)
   489  	for tIdx, cc := range txsUpgradedChaincodes {
   490  		if cc == nil {
   491  			continue
   492  		}
   493  		upgradedCCKey := v.generateCCKey(cc.ChaincodeName, cc.ChannelID)
   494  
   495  		if finalIdx, exist := finalValidUpgradeTXs[upgradedCCKey]; !exist {
   496  			finalValidUpgradeTXs[upgradedCCKey] = tIdx
   497  			upgradedChaincodes[upgradedCCKey] = cc
   498  		} else if finalIdx < tIdx {
   499  			logger.Infof("Invalid transaction with index %d: chaincode was upgraded by latter tx", finalIdx)
   500  			txsfltr.SetFlag(finalIdx, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT)
   501  
   502  			// record latter cc upgrade tx info
   503  			finalValidUpgradeTXs[upgradedCCKey] = tIdx
   504  			upgradedChaincodes[upgradedCCKey] = cc
   505  		} else {
   506  			logger.Infof("Invalid transaction with index %d: chaincode was upgraded by latter tx", tIdx)
   507  			txsfltr.SetFlag(tIdx, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT)
   508  		}
   509  	}
   510  
   511  	// invalid txs which invoke the upgraded chaincodes
   512  	for tIdx, cc := range txsChaincodeNames {
   513  		if cc == nil {
   514  			continue
   515  		}
   516  		ccKey := v.generateCCKey(cc.ChaincodeName, cc.ChannelID)
   517  		if _, exist := upgradedChaincodes[ccKey]; exist {
   518  			if txsfltr.IsValid(tIdx) {
   519  				logger.Infof("Invalid transaction with index %d: chaincode was upgraded in the same block", tIdx)
   520  				txsfltr.SetFlag(tIdx, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT)
   521  			}
   522  		}
   523  	}
   524  }
   525  
   526  func (v *TxValidator) getTxCCInstance(payload *common.Payload) (invokeCCIns, upgradeCCIns *sysccprovider.ChaincodeInstance, err error) {
   527  	// This is duplicated unpacking work, but make test easier.
   528  	chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   529  	if err != nil {
   530  		return nil, nil, err
   531  	}
   532  
   533  	// Channel ID
   534  	channelID := chdr.ChannelId // it is guaranteed to be an existing channel by now
   535  
   536  	// ChaincodeID
   537  	hdrExt, err := protoutil.UnmarshalChaincodeHeaderExtension(chdr.Extension)
   538  	if err != nil {
   539  		return nil, nil, err
   540  	}
   541  	invokeCC := hdrExt.ChaincodeId
   542  	invokeIns := &sysccprovider.ChaincodeInstance{ChannelID: channelID, ChaincodeName: invokeCC.Name, ChaincodeVersion: invokeCC.Version}
   543  
   544  	// Transaction
   545  	tx, err := protoutil.UnmarshalTransaction(payload.Data)
   546  	if err != nil {
   547  		logger.Errorf("GetTransaction failed: %+v", err)
   548  		return invokeIns, nil, nil
   549  	}
   550  
   551  	// ChaincodeActionPayload
   552  	cap, err := protoutil.UnmarshalChaincodeActionPayload(tx.Actions[0].Payload)
   553  	if err != nil {
   554  		logger.Errorf("GetChaincodeActionPayload failed: %+v", err)
   555  		return invokeIns, nil, nil
   556  	}
   557  
   558  	// ChaincodeProposalPayload
   559  	cpp, err := protoutil.UnmarshalChaincodeProposalPayload(cap.ChaincodeProposalPayload)
   560  	if err != nil {
   561  		logger.Errorf("GetChaincodeProposalPayload failed: %+v", err)
   562  		return invokeIns, nil, nil
   563  	}
   564  
   565  	// ChaincodeInvocationSpec
   566  	cis := &peer.ChaincodeInvocationSpec{}
   567  	err = proto.Unmarshal(cpp.Input, cis)
   568  	if err != nil {
   569  		logger.Errorf("GetChaincodeInvokeSpec failed: %+v", err)
   570  		return invokeIns, nil, nil
   571  	}
   572  
   573  	if invokeCC.Name == "lscc" {
   574  		if string(cis.ChaincodeSpec.Input.Args[0]) == "upgrade" {
   575  			upgradeIns, err := v.getUpgradeTxInstance(channelID, cis.ChaincodeSpec.Input.Args[2])
   576  			if err != nil {
   577  				return invokeIns, nil, nil
   578  			}
   579  			return invokeIns, upgradeIns, nil
   580  		}
   581  	}
   582  
   583  	return invokeIns, nil, nil
   584  }
   585  
   586  func (v *TxValidator) getUpgradeTxInstance(channelID string, cdsBytes []byte) (*sysccprovider.ChaincodeInstance, error) {
   587  	cds, err := protoutil.UnmarshalChaincodeDeploymentSpec(cdsBytes)
   588  	if err != nil {
   589  		return nil, err
   590  	}
   591  
   592  	if cds.ChaincodeSpec.Type.String() != "GOLANG" {
   593  		return nil, errors.Errorf("unexpected chaincode type: %s", cds.ChaincodeSpec.Type.String())
   594  	}
   595  
   596  	return &sysccprovider.ChaincodeInstance{
   597  		ChannelID:        channelID,
   598  		ChaincodeName:    cds.ChaincodeSpec.ChaincodeId.Name,
   599  		ChaincodeVersion: cds.ChaincodeSpec.ChaincodeId.Version,
   600  	}, nil
   601  }
   602  
   603  type dynamicDeserializer struct {
   604  	cr ChannelResources
   605  }
   606  
   607  func (ds *dynamicDeserializer) DeserializeIdentity(serializedIdentity []byte) (msp.Identity, error) {
   608  	return ds.cr.MSPManager().DeserializeIdentity(serializedIdentity)
   609  }
   610  
   611  func (ds *dynamicDeserializer) IsWellFormed(identity *mspprotos.SerializedIdentity) error {
   612  	return ds.cr.MSPManager().IsWellFormed(identity)
   613  }
   614  
   615  type dynamicCapabilities struct {
   616  	cr ChannelResources
   617  }
   618  
   619  func (ds *dynamicCapabilities) ACLs() bool {
   620  	return ds.cr.Capabilities().ACLs()
   621  }
   622  
   623  func (ds *dynamicCapabilities) CollectionUpgrade() bool {
   624  	return ds.cr.Capabilities().CollectionUpgrade()
   625  }
   626  
   627  func (ds *dynamicCapabilities) StorePvtDataOfInvalidTx() bool {
   628  	return ds.cr.Capabilities().StorePvtDataOfInvalidTx()
   629  }
   630  
   631  func (ds *dynamicCapabilities) ForbidDuplicateTXIdInBlock() bool {
   632  	return ds.cr.Capabilities().ForbidDuplicateTXIdInBlock()
   633  }
   634  
   635  func (ds *dynamicCapabilities) KeyLevelEndorsement() bool {
   636  	return ds.cr.Capabilities().KeyLevelEndorsement()
   637  }
   638  
   639  func (ds *dynamicCapabilities) MetadataLifecycle() bool {
   640  	// This capability no longer exists and should not be referenced in validation anyway
   641  	return false
   642  }
   643  
   644  func (ds *dynamicCapabilities) PrivateChannelData() bool {
   645  	return ds.cr.Capabilities().PrivateChannelData()
   646  }
   647  
   648  func (ds *dynamicCapabilities) Supported() error {
   649  	return ds.cr.Capabilities().Supported()
   650  }
   651  
   652  func (ds *dynamicCapabilities) V1_1Validation() bool {
   653  	return ds.cr.Capabilities().V1_1Validation()
   654  }
   655  
   656  func (ds *dynamicCapabilities) V1_2Validation() bool {
   657  	return ds.cr.Capabilities().V1_2Validation()
   658  }
   659  
   660  func (ds *dynamicCapabilities) V1_3Validation() bool {
   661  	return ds.cr.Capabilities().V1_3Validation()
   662  }
   663  
   664  func (ds *dynamicCapabilities) V2_0Validation() bool {
   665  	return ds.cr.Capabilities().V2_0Validation()
   666  }