func(v *VsccValidatorImpl)VSCCValidateTxForCC(ctx *Context)error { logger.Debug("Validating", ctx, "with plugin") // 使用插件验证交易 err := v.pluginValidator.ValidateWithPlugin(ctx) if err == nil { returnnil } // If the error is a pluggable validation execution error, cast it to the common errors ExecutionFailureError. if e, isExecutionError := err.(*validation.ExecutionFailureError); isExecutionError { return &commonerrors.VSCCExecutionFailureError{Err: e} } // Else, treat it as an endorsement error. return &commonerrors.VSCCEndorsementPolicyError{Err: err} }
// Plugin validates transactions type Plugin interface { // Validate returns nil if the action at the given position inside the transaction // at the given position in the given block is valid, or an error if not. Validate(block *common.Block, namespace string, txPosition int, actionPosition int, contextData ...ContextDatum) error
// Init injects dependencies into the instance of the Plugin Init(dependencies ...Dependency) error }
// 拿到序列化后的policy serializedPolicy, isSerializedPolicy := contextData[0].(SerializedPolicy) if !isSerializedPolicy { logger.Panicf("Expected to receive a serialized policy in the first context data") } if block == nil || block.Data == nil { return errors.New("empty block") } if txPosition >= len(block.Data.Data) { return errors.Errorf("block has only %d transactions, but requested tx at position %d", len(block.Data.Data), txPosition) } if block.Header == nil { return errors.Errorf("no block header") }
// 调用不同版本的validator进行验证 var err error switch { case v.Capabilities.V1_3Validation(): err = v.TxValidatorV1_3.Validate(block, namespace, txPosition, actionPosition, serializedPolicy.Bytes())
// 验证代码使用v2/validation_logic.go中的实现 // Validate validates the given envelope corresponding to a transaction with an endorsement // policy as given in its serialized form func(vscc *Validator)Validate( block *common.Block, namespace string, txPosition int, actionPosition int, policyBytes []byte, )commonerrors.TxValidationError { ... // evaluate the signature set against the policy err = vscc.policyEvaluator.Evaluate(policyBytes, signatureSet) if err != nil { logger.Warningf("Endorsement policy failure for transaction txid=%s, err: %s", chdr.GetTxId(), err.Error()) iflen(signatureSet) < len(cap.Action.Endorsements) { // Warning: duplicated identities exist, endorsement failure might be cause by this reason return policyErr(errors.New(DUPLICATED_IDENTITY_ERROR)) } return policyErr(fmt.Errorf("VSCC error: endorsement policy failure, err: %s", err)) } ... }
// PolicyEvaluator evaluates policies type PolicyEvaluator interface { validation.Dependency
// Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies // the policy with the given bytes Evaluate(policyBytes []byte, signatureSet []*common.SignedData) error }
// Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy func (id *PolicyEvaluator) Evaluate(policyBytes []byte, signatureSet []*common.SignedData) error { pp := cauthdsl.NewPolicyProvider(id.IdentityDeserializer) policy, _, err := pp.NewPolicy(policyBytes) if err != nil { return err } return policy.Evaluate(signatureSet) }
// Policy is used to determine if a signature is valid type Policy interface { // Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy Evaluate(signatureSet []*cb.SignedData) error }
// Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy func (p *policy) Evaluate(signatureSet []*cb.SignedData) error { if p == nil { return fmt.Errorf("No such policy") } idAndS := make([]IdentityAndSignature, len(signatureSet)) for i, sd := range signatureSet { idAndS[i] = &deserializeAndVerify{ signedData: sd, deserializer: p.deserializer, } }
ok := p.evaluator(deduplicate(idAndS), make([]bool, len(signatureSet))) if !ok { return errors.New("signature set did not satisfy policy") } return nil }
// Context defines information about a transaction // that is being validated type Context struct { Seq int Envelope []byte TxID string Channel string VSCCName string Policy []byte // 背书策略 Namespace string Block *common.Block }
// GetInfoForValidate gets the ChaincodeInstance(with latest version) of tx, vscc and policy from lscc func(v *VsccValidatorImpl)GetInfoForValidate(chdr *common.ChannelHeader, ccID string)(*sysccprovider.ChaincodeInstance, *sysccprovider.ChaincodeInstance, []byte, error) { cc := &sysccprovider.ChaincodeInstance{ ChainID: chdr.ChannelId, ChaincodeName: ccID, ChaincodeVersion: coreUtil.GetSysCCVersion(), } vscc := &sysccprovider.ChaincodeInstance{ ChainID: chdr.ChannelId, ChaincodeName: "vscc", // default vscc for system chaincodes ChaincodeVersion: coreUtil.GetSysCCVersion(), // Get vscc version } var policy []byte var err error if !v.sccprovider.IsSysCC(ccID) { // when we are validating a chaincode that is not a // system CC, we need to ask the CC to give us the name // of VSCC and of the policy that should be used
// obtain name of the VSCC and the policy // 获取cc 定义 cd, err := v.getCDataForCC(chdr.ChannelId, ccID) if err != nil { msg := fmt.Sprintf("Unable to get chaincode data from ledger for txid %s, due to %s", chdr.TxId, err) logger.Errorf(msg) returnnil, nil, nil, err } cc.ChaincodeName = cd.CCName() cc.ChaincodeVersion = cd.CCVersion() // 拿到policy vscc.ChaincodeName, policy = cd.Validation() } else { // when we are validating a system CC, we use the default // VSCC and a default policy that requires one signature // from any of the members of the channel p := cauthdsl.SignedByAnyMember(v.support.GetMSPIDs(chdr.ChannelId)) policy, err = utils.Marshal(p) if err != nil { returnnil, nil, nil, err } }
return cc, vscc, policy, nil }
//-------- ChaincodeDefinition - interface for ChaincodeData ------ // ChaincodeDefinition describes all of the necessary information for a peer to decide whether to endorse // a proposal and whether to validate a transaction, for a particular chaincode. type ChaincodeDefinition interface { // CCName returns the name of this chaincode (the name it was put in the ChaincodeRegistry with). CCName() string
// Hash returns the hash of the chaincode. Hash() []byte
// CCVersion returns the version of the chaincode. CCVersion() string
// Validation returns how to validate transactions for this chaincode. // The string returned is the name of the validation method (usually 'vscc') // and the bytes returned are the argument to the validation (in the case of // 'vscc', this is a marshaled pb.VSCCArgs message). Validation() (string, []byte)
// Endorsement returns how to endorse proposals for this chaincode. // The string returns is the name of the endorsement method (usually 'escc'). Endorsement() string }
// Validation returns how to validate transactions for this chaincode. // The string returned is the name of the validation method (usually 'vscc') // and the bytes returned are the argument to the validation (in the case of // 'vscc', this is a marshaled pb.VSCCArgs message). func(cd *ChaincodeData)Validation()(string, []byte) { return cd.Vscc, cd.Policy }
//-------- ChaincodeData is stored on the LSCC -------
// ChaincodeData defines the datastructure for chaincodes to be serialized by proto // Type provides an additional check by directing to use a specific package after instantiation // Data is Type specifc (see CDSPackage and SignedCDSPackage) type ChaincodeData struct { // Name of the chaincode Name string`protobuf:"bytes,1,opt,name=name"`
// Version of the chaincode Version string`protobuf:"bytes,2,opt,name=version"`
// Escc for the chaincode instance Escc string`protobuf:"bytes,3,opt,name=escc"`
// Vscc for the chaincode instance Vscc string`protobuf:"bytes,4,opt,name=vscc"`
// 背书策略 // Policy endorsement policy for the chaincode instance Policy []byte`protobuf:"bytes,5,opt,name=policy,proto3"`
// Data data specific to the package Data []byte`protobuf:"bytes,6,opt,name=data,proto3"`
// Id of the chaincode that's the unique fingerprint for the CC This is not // currently used anywhere but serves as a good eyecatcher Id []byte`protobuf:"bytes,7,opt,name=id,proto3"`
// InstantiationPolicy for the chaincode InstantiationPolicy []byte`protobuf:"bytes,8,opt,name=instantiation_policy,proto3"` }
// executeDeployOrUpgrade routes the code path either to executeDeploy or executeUpgrade // depending on its function argument func(lscc *LifeCycleSysCC)executeDeployOrUpgrade( stub shim.ChaincodeStubInterface, chainname string, cds *pb.ChaincodeDeploymentSpec, policy, escc, vscc, collectionConfigBytes []byte, function string, )(*ccprovider.ChaincodeData, error) {
// Invoke implements lifecycle functions "deploy", "start", "stop", "upgrade". // Deploy's arguments - {[]byte("deploy"), []byte(<chainname>), <unmarshalled pb.ChaincodeDeploymentSpec>} // // Invoke also implements some query-like functions // Get chaincode arguments - {[]byte("getid"), []byte(<chainname>), []byte(<chaincodename>)} func(lscc *LifeCycleSysCC)Invoke(stub shim.ChaincodeStubInterface)pb.Response { ... switch function { case INSTALL: ... case DEPLOY, UPGRADE: // 提取背书策略 // optional arguments here (they can each be nil and may or may not be present) // args[3] is a marshalled SignaturePolicyEnvelope representing the endorsement policy // args[4] is the name of escc // args[5] is the name of vscc // args[6] is a marshalled CollectionConfigPackage struct var EP []byte iflen(args) > 3 && len(args[3]) > 0 { EP = args[3] } else { p := cauthdsl.SignedByAnyMember(peer.GetMSPIDs(channel)) EP, err = utils.Marshal(p) if err != nil { return shim.Error(err.Error()) } } ... cd, err := lscc.executeDeployOrUpgrade(stub, channel, cds, EP, escc, vscc, collectionsConfig, function) ... case ...: ... } }