// 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
}
Example #2
0
// 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
}