// Invoke is called to validate the specified block of transactions // This validation system chaincode will check the read-write set validity and at least 1 // correct endorsement. Later we can create more validation system // chaincodes to provide more sophisticated policy processing such as enabling // policy specification to be coded as a transaction of the chaincode and the client // selecting which policy to use for validation using parameter function // @return serialized Block of valid and invalid transactions indentified // Note that Peer calls this function with 2 arguments, where args[0] is the // function name and args[1] is the Envelope func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) ([]byte, error) { // args[0] - function name (not used now) // args[1] - serialized Envelope args := stub.GetArgs() if len(args) < 2 { return nil, errors.New("Incorrect number of arguments") } if args[1] == nil { return nil, errors.New("No block to validate") } logger.Infof("VSCC invoked") // get the envelope... env, err := utils.GetEnvelope(args[1]) if err != nil { logger.Errorf("VSCC error: GetEnvelope failed, err %s", err) return nil, err } // ...and the payload... payl, err := utils.GetPayload(env) if err != nil { logger.Errorf("VSCC error: GetPayload failed, err %s", err) return nil, err } // validate the payload type if common.HeaderType(payl.Header.ChainHeader.Type) != common.HeaderType_ENDORSER_TRANSACTION { logger.Errorf("Only Endorser Transactions are supported, provided type %d", payl.Header.ChainHeader.Type) return nil, fmt.Errorf("Only Endorser Transactions are supported, provided type %d", payl.Header.ChainHeader.Type) } // ...and the transaction... tx, err := utils.GetTransaction(payl.Data) if err != nil { logger.Errorf("VSCC error: GetTransaction failed, err %s", err) return nil, err } // loop through each of the actions within for _, act := range tx.Actions { cap, err := utils.GetChaincodeActionPayload(act.Payload) if err != nil { logger.Errorf("VSCC error: GetChaincodeActionPayload failed, err %s", err) return nil, err } // this is what is being signed prespBytes := cap.Action.ProposalResponsePayload // loop through each of the endorsements for _, endorsement := range cap.Action.Endorsements { // extract the identity of the signer end, err := mspmgmt.GetManagerForChain(payl.Header.ChainHeader.ChainID).DeserializeIdentity(endorsement.Endorser) if err != nil { logger.Errorf("VSCC error: DeserializeIdentity failed, err %s", err) return nil, err } // validate it err = end.Validate() if err != nil { return nil, fmt.Errorf("Invalid endorser identity, err %s", err) } // verify the signature err = end.Verify(append(prespBytes, endorsement.Endorser...), endorsement.Signature) if err != nil { return nil, fmt.Errorf("Invalid signature, err %s", err) } } } logger.Infof("VSCC exists successfully") return nil, nil }
// validateEndorserTransaction validates the payload of a // transaction assuming its type is ENDORSER_TRANSACTION func validateEndorserTransaction(data []byte, hdr *common.Header) ([]*pb.TransactionAction, error) { putilsLogger.Infof("validateEndorserTransaction starts for data %p, header %s", data, hdr) // check for nil argument if data == nil || hdr == nil { return nil, fmt.Errorf("Nil arguments") } // if the type is ENDORSER_TRANSACTION we unmarshal a Transaction message tx, err := utils.GetTransaction(data) if err != nil { return nil, err } // check for nil argument if tx == nil { return nil, fmt.Errorf("Nil transaction") } // TODO: validate tx.Version // TODO: validate ChaincodeHeaderExtension if len(tx.Actions) == 0 { return nil, fmt.Errorf("At least one TransactionAction is required") } putilsLogger.Infof("validateEndorserTransaction info: there are %d actions", len(tx.Actions)) for _, act := range tx.Actions { // check for nil argument if act == nil { return nil, fmt.Errorf("Nil action") } // if the type is ENDORSER_TRANSACTION we unmarshal a SignatureHeader sHdr, err := utils.GetSignatureHeader(act.Header) if err != nil { return nil, err } // validate the SignatureHeader - here we actually only // care about the nonce since the creator is in the outer header err = validateSignatureHeader(sHdr) if err != nil { return nil, err } putilsLogger.Infof("validateEndorserTransaction info: signature header is valid") // if the type is ENDORSER_TRANSACTION we unmarshal a ChaincodeActionPayload cap, err := utils.GetChaincodeActionPayload(act.Payload) if err != nil { return nil, err } // extract the proposal response payload prp, err := utils.GetProposalResponsePayload(cap.Action.ProposalResponsePayload) if err != nil { return nil, err } // build the original header by stitching together // the common ChainHeader and the per-action SignatureHeader hdrOrig := &common.Header{ChainHeader: hdr.ChainHeader, SignatureHeader: sHdr} hdrBytes, err := utils.GetBytesHeader(hdrOrig) // FIXME: here we hope that hdrBytes will be the same one that the endorser had if err != nil { return nil, err } // compute proposalHash pHash, err := utils.GetProposalHash2(hdrBytes, cap.ChaincodeProposalPayload) if err != nil { return nil, err } // ensure that the proposal hash matches if bytes.Compare(pHash, prp.ProposalHash) != 0 { return nil, fmt.Errorf("proposal hash does not match") } } return tx.Actions, nil }