github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/core/committer/txvalidator/validator.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8                   http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package txvalidator
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/golang/protobuf/proto"
    23  	"github.com/hyperledger/fabric/common/configtx"
    24  	"github.com/hyperledger/fabric/common/flogging"
    25  	coreUtil "github.com/hyperledger/fabric/common/util"
    26  	"github.com/hyperledger/fabric/core/chaincode/shim"
    27  	"github.com/hyperledger/fabric/core/common/ccprovider"
    28  	"github.com/hyperledger/fabric/core/common/sysccprovider"
    29  	"github.com/hyperledger/fabric/core/common/validation"
    30  	"github.com/hyperledger/fabric/core/ledger"
    31  	ledgerUtil "github.com/hyperledger/fabric/core/ledger/util"
    32  	"github.com/hyperledger/fabric/msp"
    33  
    34  	"github.com/hyperledger/fabric/protos/common"
    35  	"github.com/hyperledger/fabric/protos/peer"
    36  	"github.com/hyperledger/fabric/protos/utils"
    37  	"github.com/op/go-logging"
    38  
    39  	"github.com/hyperledger/fabric/common/cauthdsl"
    40  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    41  )
    42  
    43  // Support provides all of the needed to evaluate the VSCC
    44  type Support interface {
    45  	// Ledger returns the ledger associated with this validator
    46  	Ledger() ledger.PeerLedger
    47  
    48  	// MSPManager returns the MSP manager for this chain
    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(cid string) []string
    57  }
    58  
    59  //Validator interface which defines API to validate block transactions
    60  // and return the bit array mask indicating invalid transactions which
    61  // didn't pass validation.
    62  type Validator interface {
    63  	Validate(block *common.Block) error
    64  }
    65  
    66  // private interface to decouple tx validator
    67  // and vscc execution, in order to increase
    68  // testability of txValidator
    69  type vsccValidator interface {
    70  	VSCCValidateTx(payload *common.Payload, envBytes []byte, env *common.Envelope) (error, peer.TxValidationCode)
    71  }
    72  
    73  // vsccValidator implementation which used to call
    74  // vscc chaincode and validate block transactions
    75  type vsccValidatorImpl struct {
    76  	support     Support
    77  	ccprovider  ccprovider.ChaincodeProvider
    78  	sccprovider sysccprovider.SystemChaincodeProvider
    79  }
    80  
    81  // implementation of Validator interface, keeps
    82  // reference to the ledger to enable tx simulation
    83  // and execution of vscc
    84  type txValidator struct {
    85  	support Support
    86  	vscc    vsccValidator
    87  }
    88  
    89  var logger *logging.Logger // package-level logger
    90  
    91  func init() {
    92  	// Init logger with module name
    93  	logger = flogging.MustGetLogger("txvalidator")
    94  }
    95  
    96  // NewTxValidator creates new transactions validator
    97  func NewTxValidator(support Support) Validator {
    98  	// Encapsulates interface implementation
    99  	return &txValidator{support,
   100  		&vsccValidatorImpl{
   101  			support:     support,
   102  			ccprovider:  ccprovider.GetChaincodeProvider(),
   103  			sccprovider: sysccprovider.GetSystemChaincodeProvider()}}
   104  }
   105  
   106  func (v *txValidator) chainExists(chain string) bool {
   107  	// TODO: implement this function!
   108  	return true
   109  }
   110  
   111  func (v *txValidator) Validate(block *common.Block) error {
   112  	logger.Debug("START Block Validation")
   113  	defer logger.Debug("END Block Validation")
   114  	// Initialize trans as valid here, then set invalidation reason code upon invalidation below
   115  	txsfltr := ledgerUtil.NewTxValidationFlags(len(block.Data.Data))
   116  	// txsChaincodeNames records all the invoked chaincodes by tx in a block
   117  	txsChaincodeNames := make(map[int]*sysccprovider.ChaincodeInstance)
   118  	// upgradedChaincodes records all the chaincodes that are upgrded in a block
   119  	txsUpgradedChaincodes := make(map[int]*sysccprovider.ChaincodeInstance)
   120  	for tIdx, d := range block.Data.Data {
   121  		if d != nil {
   122  			if env, err := utils.GetEnvelopeFromBlock(d); err != nil {
   123  				logger.Warningf("Error getting tx from block(%s)", err)
   124  				txsfltr.SetFlag(tIdx, peer.TxValidationCode_INVALID_OTHER_REASON)
   125  			} else if env != nil {
   126  				// validate the transaction: here we check that the transaction
   127  				// is properly formed, properly signed and that the security
   128  				// chain binding proposal to endorsements to tx holds. We do
   129  				// NOT check the validity of endorsements, though. That's a
   130  				// job for VSCC below
   131  				logger.Debug("Validating transaction peer.ValidateTransaction()")
   132  				var payload *common.Payload
   133  				var err error
   134  				var txResult peer.TxValidationCode
   135  
   136  				if payload, txResult = validation.ValidateTransaction(env); txResult != peer.TxValidationCode_VALID {
   137  					logger.Errorf("Invalid transaction with index %d", tIdx)
   138  					txsfltr.SetFlag(tIdx, txResult)
   139  					continue
   140  				}
   141  
   142  				chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   143  				if err != nil {
   144  					logger.Warningf("Could not unmarshal channel header, err %s, skipping", err)
   145  					txsfltr.SetFlag(tIdx, peer.TxValidationCode_INVALID_OTHER_REASON)
   146  					continue
   147  				}
   148  
   149  				channel := chdr.ChannelId
   150  				logger.Debugf("Transaction is for chain %s", channel)
   151  
   152  				if !v.chainExists(channel) {
   153  					logger.Errorf("Dropping transaction for non-existent chain %s", channel)
   154  					txsfltr.SetFlag(tIdx, peer.TxValidationCode_TARGET_CHAIN_NOT_FOUND)
   155  					continue
   156  				}
   157  
   158  				if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
   159  					// Check duplicate transactions
   160  					txID := chdr.TxId
   161  					if _, err := v.support.Ledger().GetTransactionByID(txID); err == nil {
   162  						logger.Error("Duplicate transaction found, ", txID, ", skipping")
   163  						txsfltr.SetFlag(tIdx, peer.TxValidationCode_DUPLICATE_TXID)
   164  						continue
   165  					}
   166  
   167  					// Validate tx with vscc and policy
   168  					logger.Debug("Validating transaction vscc tx validate")
   169  					err, cde := v.vscc.VSCCValidateTx(payload, d, env)
   170  					if err != nil {
   171  						txID := txID
   172  						logger.Errorf("VSCCValidateTx for transaction txId = %s returned error %s", txID, err)
   173  						txsfltr.SetFlag(tIdx, cde)
   174  						continue
   175  					}
   176  
   177  					invokeCC, upgradeCC, err := v.getTxCCInstance(payload)
   178  					if err != nil {
   179  						logger.Errorf("Get chaincode instance from transaction txId = %s returned error %s", txID, err)
   180  						txsfltr.SetFlag(tIdx, peer.TxValidationCode_INVALID_OTHER_REASON)
   181  						continue
   182  					}
   183  					txsChaincodeNames[tIdx] = invokeCC
   184  					if upgradeCC != nil {
   185  						logger.Infof("Find chaincode upgrade transaction for chaincode %s on chain %s with new version %s", upgradeCC.ChaincodeName, upgradeCC.ChainID, upgradeCC.ChaincodeVersion)
   186  						txsUpgradedChaincodes[tIdx] = upgradeCC
   187  					}
   188  				} else if common.HeaderType(chdr.Type) == common.HeaderType_CONFIG {
   189  					configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
   190  					if err != nil {
   191  						err := fmt.Errorf("Error unmarshaling config which passed initial validity checks: %s", err)
   192  						logger.Critical(err)
   193  						return err
   194  					}
   195  
   196  					if err := v.support.Apply(configEnvelope); err != nil {
   197  						err := fmt.Errorf("Error validating config which passed initial validity checks: %s", err)
   198  						logger.Critical(err)
   199  						return err
   200  					}
   201  					logger.Debugf("config transaction received for chain %s", channel)
   202  				} else {
   203  					logger.Warningf("Unknown transaction type [%s] in block number [%d] transaction index [%d]",
   204  						common.HeaderType(chdr.Type), block.Header.Number, tIdx)
   205  					txsfltr.SetFlag(tIdx, peer.TxValidationCode_UNKNOWN_TX_TYPE)
   206  					continue
   207  				}
   208  
   209  				if _, err := proto.Marshal(env); err != nil {
   210  					logger.Warningf("Cannot marshal transaction due to %s", err)
   211  					txsfltr.SetFlag(tIdx, peer.TxValidationCode_MARSHAL_TX_ERROR)
   212  					continue
   213  				}
   214  				// Succeeded to pass down here, transaction is valid
   215  				txsfltr.SetFlag(tIdx, peer.TxValidationCode_VALID)
   216  			} else {
   217  				logger.Warning("Nil tx from block")
   218  				txsfltr.SetFlag(tIdx, peer.TxValidationCode_NIL_ENVELOPE)
   219  			}
   220  		}
   221  	}
   222  
   223  	txsfltr = v.invalidTXsForUpgradeCC(txsChaincodeNames, txsUpgradedChaincodes, txsfltr)
   224  
   225  	// Initialize metadata structure
   226  	utils.InitBlockMetadata(block)
   227  
   228  	block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsfltr
   229  
   230  	return nil
   231  }
   232  
   233  // generateCCKey generates a unique identifier for chaincode in specific chain
   234  func (v *txValidator) generateCCKey(ccName, chainID string) string {
   235  	return fmt.Sprintf("%s/%s", ccName, chainID)
   236  }
   237  
   238  // invalidTXsForUpgradeCC invalid all txs that should be invalided because of chaincode upgrade txs
   239  func (v *txValidator) invalidTXsForUpgradeCC(txsChaincodeNames map[int]*sysccprovider.ChaincodeInstance, txsUpgradedChaincodes map[int]*sysccprovider.ChaincodeInstance, txsfltr ledgerUtil.TxValidationFlags) ledgerUtil.TxValidationFlags {
   240  	if len(txsUpgradedChaincodes) == 0 {
   241  		return txsfltr
   242  	}
   243  
   244  	// Invalid former cc upgrade txs if there're two or more txs upgrade the same cc
   245  	finalValidUpgradeTXs := make(map[string]int)
   246  	upgradedChaincodes := make(map[string]*sysccprovider.ChaincodeInstance)
   247  	for tIdx, cc := range txsUpgradedChaincodes {
   248  		if cc == nil {
   249  			continue
   250  		}
   251  		upgradedCCKey := v.generateCCKey(cc.ChaincodeName, cc.ChainID)
   252  
   253  		if finalIdx, exist := finalValidUpgradeTXs[upgradedCCKey]; !exist {
   254  			finalValidUpgradeTXs[upgradedCCKey] = tIdx
   255  			upgradedChaincodes[upgradedCCKey] = cc
   256  		} else if finalIdx < tIdx {
   257  			logger.Infof("Invalid transaction with index %d: chaincode was upgraded by latter tx", finalIdx)
   258  			txsfltr.SetFlag(finalIdx, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT)
   259  
   260  			// record latter cc upgrade tx info
   261  			finalValidUpgradeTXs[upgradedCCKey] = tIdx
   262  			upgradedChaincodes[upgradedCCKey] = cc
   263  		} else {
   264  			logger.Infof("Invalid transaction with index %d: chaincode was upgraded by latter tx", tIdx)
   265  			txsfltr.SetFlag(tIdx, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT)
   266  		}
   267  	}
   268  
   269  	// invalid txs which invoke the upgraded chaincodes
   270  	for tIdx, cc := range txsChaincodeNames {
   271  		if cc == nil {
   272  			continue
   273  		}
   274  		ccKey := v.generateCCKey(cc.ChaincodeName, cc.ChainID)
   275  		if _, exist := upgradedChaincodes[ccKey]; exist {
   276  			if txsfltr.IsValid(tIdx) {
   277  				logger.Infof("Invalid transaction with index %d: chaincode was upgraded in the same block", tIdx)
   278  				txsfltr.SetFlag(tIdx, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT)
   279  			}
   280  		}
   281  	}
   282  
   283  	return txsfltr
   284  }
   285  
   286  func (v *txValidator) getTxCCInstance(payload *common.Payload) (invokeCCIns, upgradeCCIns *sysccprovider.ChaincodeInstance, err error) {
   287  	// This is duplicated unpacking work, but make test easier.
   288  	chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   289  	if err != nil {
   290  		return nil, nil, err
   291  	}
   292  
   293  	// Chain ID
   294  	chainID := chdr.ChannelId // it is guaranteed to be an existing channel by now
   295  
   296  	// ChaincodeID
   297  	hdrExt, err := utils.GetChaincodeHeaderExtension(payload.Header)
   298  	if err != nil {
   299  		return nil, nil, err
   300  	}
   301  	invokeCC := hdrExt.ChaincodeId
   302  	invokeIns := &sysccprovider.ChaincodeInstance{ChainID: chainID, ChaincodeName: invokeCC.Name, ChaincodeVersion: invokeCC.Version}
   303  
   304  	// Transaction
   305  	tx, err := utils.GetTransaction(payload.Data)
   306  	if err != nil {
   307  		logger.Errorf("GetTransaction failed: %s", err)
   308  		return invokeIns, nil, nil
   309  	}
   310  
   311  	// ChaincodeActionPayload
   312  	cap, err := utils.GetChaincodeActionPayload(tx.Actions[0].Payload)
   313  	if err != nil {
   314  		logger.Errorf("GetChaincodeActionPayload failed: %s", err)
   315  		return invokeIns, nil, nil
   316  	}
   317  
   318  	// ChaincodeProposalPayload
   319  	cpp, err := utils.GetChaincodeProposalPayload(cap.ChaincodeProposalPayload)
   320  	if err != nil {
   321  		logger.Errorf("GetChaincodeProposalPayload failed: %s", err)
   322  		return invokeIns, nil, nil
   323  	}
   324  
   325  	// ChaincodeInvocationSpec
   326  	cis := &peer.ChaincodeInvocationSpec{}
   327  	err = proto.Unmarshal(cpp.Input, cis)
   328  	if err != nil {
   329  		logger.Errorf("GetChaincodeInvokeSpec failed: %s", err)
   330  		return invokeIns, nil, nil
   331  	}
   332  
   333  	if invokeCC.Name == "lscc" {
   334  		if string(cis.ChaincodeSpec.Input.Args[0]) == "upgrade" {
   335  			upgradeIns, err := v.getUpgradeTxInstance(chainID, cis.ChaincodeSpec.Input.Args[2])
   336  			if err != nil {
   337  				return invokeIns, nil, nil
   338  			}
   339  			return invokeIns, upgradeIns, nil
   340  		}
   341  	}
   342  
   343  	return invokeIns, nil, nil
   344  }
   345  
   346  func (v *txValidator) getUpgradeTxInstance(chainID string, cdsBytes []byte) (*sysccprovider.ChaincodeInstance, error) {
   347  	cds, err := utils.GetChaincodeDeploymentSpec(cdsBytes)
   348  	if err != nil {
   349  		return nil, err
   350  	}
   351  
   352  	return &sysccprovider.ChaincodeInstance{
   353  		ChainID:          chainID,
   354  		ChaincodeName:    cds.ChaincodeSpec.ChaincodeId.Name,
   355  		ChaincodeVersion: cds.ChaincodeSpec.ChaincodeId.Version,
   356  	}, nil
   357  }
   358  
   359  // GetInfoForValidate gets the ChaincodeInstance(with latest version) of tx, vscc and policy from lscc
   360  func (v *vsccValidatorImpl) GetInfoForValidate(txid, chID, ccID string) (*sysccprovider.ChaincodeInstance, *sysccprovider.ChaincodeInstance, []byte, error) {
   361  	cc := &sysccprovider.ChaincodeInstance{ChainID: chID}
   362  	vscc := &sysccprovider.ChaincodeInstance{ChainID: chID}
   363  	var policy []byte
   364  	var err error
   365  	if ccID != "lscc" {
   366  		// when we are validating any chaincode other than
   367  		// LSCC, we need to ask LSCC to give us the name
   368  		// of VSCC and of the policy that should be used
   369  
   370  		// obtain name of the VSCC and the policy from LSCC
   371  		cd, err := v.getCDataForCC(ccID)
   372  		if err != nil {
   373  			logger.Errorf("Unable to get chaincode data from ledger for txid %s, due to %s", txid, err)
   374  			return nil, nil, nil, err
   375  		}
   376  		cc.ChaincodeName = cd.Name
   377  		cc.ChaincodeVersion = cd.Version
   378  		vscc.ChaincodeName = cd.Vscc
   379  		policy = cd.Policy
   380  	} else {
   381  		// when we are validating LSCC, we use the default
   382  		// VSCC and a default policy that requires one signature
   383  		// from any of the members of the channel
   384  		cc.ChaincodeName = "lscc"
   385  		cc.ChaincodeVersion = coreUtil.GetSysCCVersion()
   386  		vscc.ChaincodeName = "vscc"
   387  		p := cauthdsl.SignedByAnyMember(v.support.GetMSPIDs(chID))
   388  		policy, err = utils.Marshal(p)
   389  		if err != nil {
   390  			return nil, nil, nil, err
   391  		}
   392  	}
   393  
   394  	// Get vscc version
   395  	vscc.ChaincodeVersion = coreUtil.GetSysCCVersion()
   396  
   397  	return cc, vscc, policy, nil
   398  }
   399  
   400  func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []byte, env *common.Envelope) (error, peer.TxValidationCode) {
   401  	// get header extensions so we have the chaincode ID
   402  	hdrExt, err := utils.GetChaincodeHeaderExtension(payload.Header)
   403  	if err != nil {
   404  		return err, peer.TxValidationCode_BAD_HEADER_EXTENSION
   405  	}
   406  
   407  	// get channel header
   408  	chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   409  	if err != nil {
   410  		return err, peer.TxValidationCode_BAD_CHANNEL_HEADER
   411  	}
   412  
   413  	/* obtain the list of namespaces we're writing stuff to;
   414  	   at first, we establish a few facts about this invocation:
   415  	   1) which namespaces does it write to?
   416  	   2) does it write to LSCC's namespace?
   417  	   3) does it write to any cc that cannot be invoked? */
   418  	wrNamespace := []string{}
   419  	writesToLSCC := false
   420  	writesToNonInvokableSCC := false
   421  	respPayload, err := utils.GetActionFromEnvelope(envBytes)
   422  	if err != nil {
   423  		return fmt.Errorf("GetActionFromEnvelope failed, error %s", err), peer.TxValidationCode_BAD_RESPONSE_PAYLOAD
   424  	}
   425  	txRWSet := &rwsetutil.TxRwSet{}
   426  	if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil {
   427  		return fmt.Errorf("txRWSet.FromProtoBytes failed, error %s", err), peer.TxValidationCode_BAD_RWSET
   428  	}
   429  	for _, ns := range txRWSet.NsRwSets {
   430  		if len(ns.KvRwSet.Writes) > 0 {
   431  			wrNamespace = append(wrNamespace, ns.NameSpace)
   432  
   433  			if !writesToLSCC && ns.NameSpace == "lscc" {
   434  				writesToLSCC = true
   435  			}
   436  
   437  			if !writesToNonInvokableSCC && v.sccprovider.IsSysCCAndNotInvokableCC2CC(ns.NameSpace) {
   438  				writesToNonInvokableSCC = true
   439  			}
   440  
   441  			if !writesToNonInvokableSCC && v.sccprovider.IsSysCCAndNotInvokableExternal(ns.NameSpace) {
   442  				writesToNonInvokableSCC = true
   443  			}
   444  		}
   445  	}
   446  
   447  	// get name and version of the cc we invoked
   448  	ccID := hdrExt.ChaincodeId.Name
   449  	ccVer := respPayload.ChaincodeId.Version
   450  
   451  	// sanity check on ccID
   452  	if ccID == "" {
   453  		err := fmt.Errorf("invalid chaincode ID")
   454  		logger.Errorf("%s", err)
   455  		return err, peer.TxValidationCode_INVALID_OTHER_REASON
   456  	}
   457  	if ccID != respPayload.ChaincodeId.Name {
   458  		err := fmt.Errorf("inconsistent ccid info (%s/%s)", ccID, respPayload.ChaincodeId.Name)
   459  		logger.Errorf("%s", err)
   460  		return err, peer.TxValidationCode_INVALID_OTHER_REASON
   461  	}
   462  	// sanity check on ccver
   463  	if ccVer == "" {
   464  		err := fmt.Errorf("invalid chaincode version")
   465  		logger.Errorf("%s", err)
   466  		return err, peer.TxValidationCode_INVALID_OTHER_REASON
   467  	}
   468  
   469  	// we've gathered all the info required to proceed to validation;
   470  	// validation will behave differently depending on the type of
   471  	// chaincode (system vs. application)
   472  
   473  	if !v.sccprovider.IsSysCC(ccID) {
   474  		// if we're here, we know this is an invocation of an application chaincode;
   475  		// first of all, we make sure that:
   476  		// 1) we don't write to LSCC - an application chaincode is free to invoke LSCC
   477  		//    for instance to get information about itself or another chaincode; however
   478  		//    these legitimate invocations only ready from LSCC's namespace; currently
   479  		//    only two functions of LSCC write to its namespace: deploy and upgrade and
   480  		//    neither should be used by an application chaincode
   481  		if writesToLSCC {
   482  			return fmt.Errorf("Chaincode %s attempted to write to the namespace of LSCC", ccID),
   483  				peer.TxValidationCode_ILLEGAL_WRITESET
   484  		}
   485  		// 2) we don't write to the namespace of a chaincode that we cannot invoke - if
   486  		//    the chaincode cannot be invoked in the first place, there's no legitimate
   487  		//    way in which a transaction has a write set that writes to it; additionally
   488  		//    we don't have any means of verifying whether the transaction had the rights
   489  		//    to perform that write operation because in v1, system chaincodes do not have
   490  		//    any endorsement policies to speak of. So if the chaincode can't be invoked
   491  		//    it can't be written to by an invocation of an application chaincode
   492  		if writesToNonInvokableSCC {
   493  			return fmt.Errorf("Chaincode %s attempted to write to the namespace of a system chaincode that cannot be invoked", ccID),
   494  				peer.TxValidationCode_ILLEGAL_WRITESET
   495  		}
   496  
   497  		// validate *EACH* read write set according to its chaincode's endorsement policy
   498  		for _, ns := range wrNamespace {
   499  			// Get latest chaincode version, vscc and validate policy
   500  			txcc, vscc, policy, err := v.GetInfoForValidate(chdr.TxId, chdr.ChannelId, ns)
   501  			if err != nil {
   502  				logger.Errorf("GetInfoForValidate for txId = %s returned error %s", chdr.TxId, err)
   503  				return err, peer.TxValidationCode_INVALID_OTHER_REASON
   504  			}
   505  
   506  			// if the namespace corresponds to the cc that was originally
   507  			// invoked, we check that the version of the cc that was
   508  			// invoked corresponds to the version that lscc has returned
   509  			if ns == ccID && txcc.ChaincodeVersion != ccVer {
   510  				err := fmt.Errorf("Chaincode %s:%s/%s didn't match %s:%s/%s in lscc", ccID, ccVer, chdr.ChannelId, txcc.ChaincodeName, txcc.ChaincodeVersion, chdr.ChannelId)
   511  				logger.Errorf(err.Error())
   512  				return err, peer.TxValidationCode_EXPIRED_CHAINCODE
   513  			}
   514  
   515  			// do VSCC validation
   516  			if err = v.VSCCValidateTxForCC(envBytes, chdr.TxId, chdr.ChannelId, vscc.ChaincodeName, vscc.ChaincodeVersion, policy); err != nil {
   517  				return fmt.Errorf("VSCCValidateTxForCC failed for cc %s, error %s", ccID, err),
   518  					peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE
   519  			}
   520  		}
   521  	} else {
   522  		// make sure that we can invoke this system chaincode - if the chaincode
   523  		// cannot be invoked through a proposal to this peer, we have to drop the
   524  		// transaction; if we didn't, we wouldn't know how to decide whether it's
   525  		// valid or not because in v1, system chaincodes have no endorsement policy
   526  		if v.sccprovider.IsSysCCAndNotInvokableExternal(ccID) {
   527  			return fmt.Errorf("Committing an invocation of cc %s is illegal", ccID),
   528  				peer.TxValidationCode_ILLEGAL_WRITESET
   529  		}
   530  
   531  		// Get latest chaincode version, vscc and validate policy
   532  		_, vscc, policy, err := v.GetInfoForValidate(chdr.TxId, chdr.ChannelId, ccID)
   533  		if err != nil {
   534  			logger.Errorf("GetInfoForValidate for txId = %s returned error %s", chdr.TxId, err)
   535  			return err, peer.TxValidationCode_INVALID_OTHER_REASON
   536  		}
   537  
   538  		// validate the transaction as an invocation of this system chaincode;
   539  		// vscc will have to do custom validation for this system chaincode
   540  		// currently, VSCC does custom validation for LSCC only; if an hlf
   541  		// user creates a new system chaincode which is invokable from the outside
   542  		// they have to modify VSCC to provide appropriate validation
   543  		if err = v.VSCCValidateTxForCC(envBytes, chdr.TxId, vscc.ChainID, vscc.ChaincodeName, vscc.ChaincodeVersion, policy); err != nil {
   544  			return fmt.Errorf("VSCCValidateTxForCC failed for cc %s, error %s", ccID, err),
   545  				peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE
   546  		}
   547  	}
   548  
   549  	return nil, peer.TxValidationCode_VALID
   550  }
   551  
   552  func (v *vsccValidatorImpl) VSCCValidateTxForCC(envBytes []byte, txid, chid, vsccName, vsccVer string, policy []byte) error {
   553  	ctxt, err := v.ccprovider.GetContext(v.support.Ledger())
   554  	if err != nil {
   555  		logger.Errorf("Cannot obtain context for txid=%s, err %s", txid, err)
   556  		return err
   557  	}
   558  	defer v.ccprovider.ReleaseContext()
   559  
   560  	// build arguments for VSCC invocation
   561  	// args[0] - function name (not used now)
   562  	// args[1] - serialized Envelope
   563  	// args[2] - serialized policy
   564  	args := [][]byte{[]byte(""), envBytes, policy}
   565  
   566  	// get context to invoke VSCC
   567  	vscctxid := coreUtil.GenerateUUID()
   568  	cccid := v.ccprovider.GetCCContext(chid, vsccName, vsccVer, vscctxid, true, nil, nil)
   569  
   570  	// invoke VSCC
   571  	logger.Debug("Invoking VSCC txid", txid, "chaindID", chid)
   572  	res, _, err := v.ccprovider.ExecuteChaincode(ctxt, cccid, args)
   573  	if err != nil {
   574  		logger.Errorf("Invoke VSCC failed for transaction txid=%s, error %s", txid, err)
   575  		return err
   576  	}
   577  	if res.Status != shim.OK {
   578  		logger.Errorf("VSCC check failed for transaction txid=%s, error %s", txid, res.Message)
   579  		return fmt.Errorf("%s", res.Message)
   580  	}
   581  
   582  	return nil
   583  }
   584  
   585  func (v *vsccValidatorImpl) getCDataForCC(ccid string) (*ccprovider.ChaincodeData, error) {
   586  	l := v.support.Ledger()
   587  	if l == nil {
   588  		return nil, fmt.Errorf("nil ledger instance")
   589  	}
   590  
   591  	qe, err := l.NewQueryExecutor()
   592  	if err != nil {
   593  		return nil, fmt.Errorf("Could not retrieve QueryExecutor, error %s", err)
   594  	}
   595  	defer qe.Done()
   596  
   597  	bytes, err := qe.GetState("lscc", ccid)
   598  	if err != nil {
   599  		return nil, fmt.Errorf("Could not retrieve state for chaincode %s, error %s", ccid, err)
   600  	}
   601  
   602  	if bytes == nil {
   603  		return nil, fmt.Errorf("lscc's state for [%s] not found.", ccid)
   604  	}
   605  
   606  	cd := &ccprovider.ChaincodeData{}
   607  	err = proto.Unmarshal(bytes, cd)
   608  	if err != nil {
   609  		return nil, fmt.Errorf("Unmarshalling ChaincodeQueryResponse failed, error %s", err)
   610  	}
   611  
   612  	if cd.Vscc == "" {
   613  		return nil, fmt.Errorf("lscc's state for [%s] is invalid, vscc field must be set.", ccid)
   614  	}
   615  
   616  	if len(cd.Policy) == 0 {
   617  		return nil, fmt.Errorf("lscc's state for [%s] is invalid, policy field must be set.", ccid)
   618  	}
   619  
   620  	return cd, err
   621  }