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