github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/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  	"github.com/golang/protobuf/proto"
    22  	"github.com/inklabsfoundation/inkchain/common/configtx"
    23  	"github.com/inklabsfoundation/inkchain/common/flogging"
    24  	coreUtil "github.com/inklabsfoundation/inkchain/common/util"
    25  	"github.com/inklabsfoundation/inkchain/core/chaincode/shim"
    26  	"github.com/inklabsfoundation/inkchain/core/common/ccprovider"
    27  	"github.com/inklabsfoundation/inkchain/core/common/sysccprovider"
    28  	"github.com/inklabsfoundation/inkchain/core/common/validation"
    29  	"github.com/inklabsfoundation/inkchain/core/ledger"
    30  	ledgerUtil "github.com/inklabsfoundation/inkchain/core/ledger/util"
    31  	"github.com/inklabsfoundation/inkchain/msp"
    32  
    33  	"github.com/inklabsfoundation/inkchain/protos/common"
    34  	"github.com/inklabsfoundation/inkchain/protos/peer"
    35  	"github.com/inklabsfoundation/inkchain/protos/utils"
    36  	"github.com/op/go-logging"
    37  
    38  	"github.com/inklabsfoundation/inkchain/common/cauthdsl"
    39  	"github.com/inklabsfoundation/inkchain/core/ledger/kvledger/txmgmt/ledgerutil"
    40  	"github.com/inklabsfoundation/inkchain/core/wallet"
    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  	/// ascc
   407  	if ccID != "lscc" && ccID != "ascc" {
   408  		// when we are validating any chaincode other than
   409  		// LSCC, we need to ask LSCC to give us the name
   410  		// of VSCC and of the policy that should be used
   411  
   412  		// obtain name of the VSCC and the policy from LSCC
   413  		cd, err := v.getCDataForCC(ccID)
   414  		if err != nil {
   415  			msg := fmt.Sprintf("Unable to get chaincode data from ledger for txid %s, due to %s", txid, err)
   416  			logger.Errorf(msg)
   417  			return nil, nil, nil, err
   418  		}
   419  		cc.ChaincodeName = cd.Name
   420  		cc.ChaincodeVersion = cd.Version
   421  		vscc.ChaincodeName = cd.Vscc
   422  		policy = cd.Policy
   423  	} else {
   424  		// TBD
   425  		// when we are validating LSCC and ascc, we use the default
   426  		// VSCC and a defaudoklt policy that requires one signature
   427  		// from any of the members of the channel
   428  		cc.ChaincodeName = ccID
   429  		cc.ChaincodeVersion = coreUtil.GetSysCCVersion()
   430  		vscc.ChaincodeName = "vscc"
   431  		var p *common.SignaturePolicyEnvelope
   432  		p = cauthdsl.SignedByAnyMember(v.support.GetMSPIDs(chID))
   433  
   434  		policy, err = utils.Marshal(p)
   435  		if err != nil {
   436  			return nil, nil, nil, err
   437  		}
   438  	}
   439  
   440  	// Get vscc version
   441  	vscc.ChaincodeVersion = coreUtil.GetSysCCVersion()
   442  
   443  	return cc, vscc, policy, nil
   444  }
   445  
   446  func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []byte, env *common.Envelope) (error, peer.TxValidationCode) {
   447  	// get header extensions so we have the chaincode ID
   448  	hdrExt, err := utils.GetChaincodeHeaderExtension(payload.Header)
   449  	if err != nil {
   450  		return err, peer.TxValidationCode_BAD_HEADER_EXTENSION
   451  	}
   452  
   453  	// get channel header
   454  	chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   455  	if err != nil {
   456  		return err, peer.TxValidationCode_BAD_CHANNEL_HEADER
   457  	}
   458  
   459  	/* obtain the list of namespaces we're writing stuff to;
   460  	   at first, we establish a few facts about this invocation:
   461  	   1) which namespaces does it write to?
   462  	   2) does it write to LSCC's namespace?
   463  	   3) does it write to any cc that cannot be invoked? */
   464  	wrNamespace := []string{}
   465  	writesToLSCC := false
   466  	writesToNonInvokableSCC := false
   467  	_, respPayload, err := utils.GetActionFromEnvelope(envBytes)
   468  	if err != nil {
   469  		return fmt.Errorf("GetActionFromEnvelope failed, error %s", err), peer.TxValidationCode_BAD_RESPONSE_PAYLOAD
   470  	}
   471  	ledgerSet := &ledgerutil.LedgerSet{}
   472  	if err = ledgerSet.FromProtoBytes(respPayload.Results); err != nil {
   473  		return fmt.Errorf("ledgerSet.FromProtoBytes failed, error %s", err), peer.TxValidationCode_BAD_RWSET
   474  	}
   475  	txRWSet := ledgerSet.TxRwSet
   476  	for _, ns := range txRWSet.NsRwSets {
   477  		if len(ns.KvRwSet.Writes) > 0 {
   478  			wrNamespace = append(wrNamespace, ns.NameSpace)
   479  
   480  			if !writesToLSCC && ns.NameSpace == "lscc" {
   481  				writesToLSCC = true
   482  			}
   483  
   484  			if !writesToNonInvokableSCC && v.sccprovider.IsSysCCAndNotInvokableCC2CC(ns.NameSpace) {
   485  				writesToNonInvokableSCC = true
   486  			}
   487  
   488  			if !writesToNonInvokableSCC && v.sccprovider.IsSysCCAndNotInvokableExternal(ns.NameSpace) {
   489  				writesToNonInvokableSCC = true
   490  			}
   491  		}
   492  	}
   493  
   494  	// get name and version of the cc we invoked
   495  	ccID := hdrExt.ChaincodeId.Name
   496  	ccVer := respPayload.ChaincodeId.Version
   497  
   498  	// sanity check on ccID
   499  	if ccID == "" {
   500  		err := fmt.Errorf("invalid chaincode ID")
   501  		logger.Errorf("%s", err)
   502  		return err, peer.TxValidationCode_INVALID_OTHER_REASON
   503  	}
   504  	if ccID != respPayload.ChaincodeId.Name {
   505  		err := fmt.Errorf("inconsistent ccid info (%s/%s)", ccID, respPayload.ChaincodeId.Name)
   506  		logger.Errorf("%s", err)
   507  		return err, peer.TxValidationCode_INVALID_OTHER_REASON
   508  	}
   509  	// sanity check on ccver
   510  	if ccVer == "" {
   511  		err := fmt.Errorf("invalid chaincode version")
   512  		logger.Errorf("%s", err)
   513  		return err, peer.TxValidationCode_INVALID_OTHER_REASON
   514  	}
   515  
   516  	// we've gathered all the info required to proceed to validation;
   517  	// validation will behave differently depending on the type of
   518  	// chaincode (system vs. application)
   519  
   520  	if !v.sccprovider.IsSysCC(ccID) {
   521  		// if we're here, we know this is an invocation of an application chaincode;
   522  		// first of all, we make sure that:
   523  		// 1) we don't write to LSCC - an application chaincode is free to invoke LSCC
   524  		//    for instance to get information about itself or another chaincode; however
   525  		//    these legitimate invocations only ready from LSCC's namespace; currently
   526  		//    only two functions of LSCC write to its namespace: deploy and upgrade and
   527  		//    neither should be used by an application chaincode
   528  		if writesToLSCC {
   529  			return fmt.Errorf("Chaincode %s attempted to write to the namespace of LSCC", ccID),
   530  				peer.TxValidationCode_ILLEGAL_WRITESET
   531  		}
   532  		// 2) we don't write to the namespace of a chaincode that we cannot invoke - if
   533  		//    the chaincode cannot be invoked in the first place, there's no legitimate
   534  		//    way in which a transaction has a write set that writes to it; additionally
   535  		//    we don't have any means of verifying whether the transaction had the rights
   536  		//    to perform that write operation because in v1, system chaincodes do not have
   537  		//    any endorsement policies to speak of. So if the chaincode can't be invoked
   538  		//    it can't be written to by an invocation of an application chaincode
   539  		if writesToNonInvokableSCC {
   540  			return fmt.Errorf("Chaincode %s attempted to write to the namespace of a system chaincode that cannot be invoked", ccID),
   541  				peer.TxValidationCode_ILLEGAL_WRITESET
   542  		}
   543  
   544  		// validate *EACH* read write set according to its chaincode's endorsement policy
   545  		for _, ns := range wrNamespace {
   546  			//******************************inkchain
   547  			if ns == wallet.WALLET_NAMESPACE {
   548  				continue
   549  			}
   550  			//******************************
   551  			// Get latest chaincode version, vscc and validate policy
   552  			txcc, vscc, policy, err := v.GetInfoForValidate(chdr.TxId, chdr.ChannelId, ns)
   553  			if err != nil {
   554  				logger.Errorf("GetInfoForValidate for txId = %s returned error %s", chdr.TxId, err)
   555  				return err, peer.TxValidationCode_INVALID_OTHER_REASON
   556  			}
   557  
   558  			// if the namespace corresponds to the cc that was originally
   559  			// invoked, we check that the version of the cc that was
   560  			// invoked corresponds to the version that lscc has returned
   561  			if ns == ccID && txcc.ChaincodeVersion != ccVer {
   562  				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)
   563  				logger.Errorf(err.Error())
   564  				return err, peer.TxValidationCode_EXPIRED_CHAINCODE
   565  			}
   566  
   567  			// do VSCC validation
   568  			if err = v.VSCCValidateTxForCC(envBytes, chdr.TxId, chdr.ChannelId, vscc.ChaincodeName, vscc.ChaincodeVersion, policy); err != nil {
   569  				switch err.(type) {
   570  				case *VSCCEndorsementPolicyError:
   571  					return err, peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE
   572  				default:
   573  					return err, peer.TxValidationCode_INVALID_OTHER_REASON
   574  				}
   575  			}
   576  		}
   577  	} else {
   578  		// make sure that we can invoke this system chaincode - if the chaincode
   579  		// cannot be invoked through a proposal to this peer, we have to drop the
   580  		// transaction; if we didn't, we wouldn't know how to decide whether it's
   581  		// valid or not because in v1, system chaincodes have no endorsement policy
   582  		//****************************** inkchain
   583  		if ccID == wallet.WALLET_NAMESPACE {
   584  			return nil, peer.TxValidationCode_VALID
   585  		}
   586  		//******************************
   587  		if v.sccprovider.IsSysCCAndNotInvokableExternal(ccID) {
   588  			return fmt.Errorf("Committing an invocation of cc %s is illegal", ccID),
   589  				peer.TxValidationCode_ILLEGAL_WRITESET
   590  		}
   591  
   592  		// Get latest chaincode version, vscc and validate policy
   593  		_, vscc, policy, err := v.GetInfoForValidate(chdr.TxId, chdr.ChannelId, ccID)
   594  		if err != nil {
   595  			logger.Errorf("GetInfoForValidate for txId = %s returned error %s", chdr.TxId, err)
   596  			return err, peer.TxValidationCode_INVALID_OTHER_REASON
   597  		}
   598  
   599  		// validate the transaction as an invocation of this system chaincode;
   600  		// vscc will have to do custom validation for this system chaincode
   601  		// currently, VSCC does custom validation for LSCC only; if an hlf
   602  		// user creates a new system chaincode which is invokable from the outside
   603  		// they have to modify VSCC to provide appropriate validation
   604  		if err = v.VSCCValidateTxForCC(envBytes, chdr.TxId, vscc.ChainID, vscc.ChaincodeName, vscc.ChaincodeVersion, policy); err != nil {
   605  			switch err.(type) {
   606  			case *VSCCEndorsementPolicyError:
   607  				return err, peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE
   608  			default:
   609  				return err, peer.TxValidationCode_INVALID_OTHER_REASON
   610  			}
   611  		}
   612  	}
   613  
   614  	return nil, peer.TxValidationCode_VALID
   615  }
   616  
   617  func (v *vsccValidatorImpl) VSCCValidateTxForCC(envBytes []byte, txid, chid, vsccName, vsccVer string, policy []byte) error {
   618  	ctxt, err := v.ccprovider.GetContext(v.support.Ledger())
   619  	if err != nil {
   620  		msg := fmt.Sprintf("Cannot obtain context for txid=%s, err %s", txid, err)
   621  		logger.Errorf(msg)
   622  		return &VSCCExecutionFailureError{msg}
   623  	}
   624  	defer v.ccprovider.ReleaseContext()
   625  
   626  	// build arguments for VSCC invocation
   627  	// args[0] - function name (not used now)
   628  	// args[1] - serialized Envelope
   629  	// args[2] - serialized policy
   630  	args := [][]byte{[]byte(""), envBytes, policy}
   631  
   632  	// get context to invoke VSCC
   633  	vscctxid := coreUtil.GenerateUUID()
   634  	cccid := v.ccprovider.GetCCContext(chid, vsccName, vsccVer, vscctxid, true, nil, nil)
   635  
   636  	// invoke VSCC
   637  	logger.Debug("Invoking VSCC txid", txid, "chaindID", chid)
   638  	res, _, err := v.ccprovider.ExecuteChaincode(ctxt, cccid, args)
   639  	if err != nil {
   640  		msg := fmt.Sprintf("Invoke VSCC failed for transaction txid=%s, error %s", txid, err)
   641  		logger.Errorf(msg)
   642  		return &VSCCExecutionFailureError{msg}
   643  	}
   644  	if res.Status != shim.OK {
   645  		logger.Errorf("VSCC check failed for transaction txid=%s, error %s", txid, res.Message)
   646  		return &VSCCEndorsementPolicyError{fmt.Sprintf("%s", res.Message)}
   647  	}
   648  
   649  	return nil
   650  }
   651  
   652  func (v *vsccValidatorImpl) getCDataForCC(ccid string) (*ccprovider.ChaincodeData, error) {
   653  	l := v.support.Ledger()
   654  	if l == nil {
   655  		return nil, fmt.Errorf("nil ledger instance")
   656  	}
   657  
   658  	qe, err := l.NewQueryExecutor()
   659  	if err != nil {
   660  		return nil, fmt.Errorf("Could not retrieve QueryExecutor, error %s", err)
   661  	}
   662  	defer qe.Done()
   663  
   664  	bytes, err := qe.GetState("lscc", ccid)
   665  	if err != nil {
   666  		return nil, &VSCCInfoLookupFailureError{fmt.Sprintf("Could not retrieve state for chaincode %s, error %s", ccid, err)}
   667  	}
   668  
   669  	if bytes == nil {
   670  		return nil, fmt.Errorf("lscc's state for [%s] not found.", ccid)
   671  	}
   672  
   673  	cd := &ccprovider.ChaincodeData{}
   674  	err = proto.Unmarshal(bytes, cd)
   675  	if err != nil {
   676  		return nil, fmt.Errorf("Unmarshalling ChaincodeQueryResponse failed, error %s", err)
   677  	}
   678  
   679  	if cd.Vscc == "" {
   680  		return nil, fmt.Errorf("lscc's state for [%s] is invalid, vscc field must be set.", ccid)
   681  	}
   682  
   683  	if len(cd.Policy) == 0 {
   684  		return nil, fmt.Errorf("lscc's state for [%s] is invalid, policy field must be set.", ccid)
   685  	}
   686  
   687  	return cd, err
   688  }