code: func createProposalFromCDS(chainID string, msg proto.Message, creator []byte, propType string, args ...[]byte) (*peer.Proposal, string, error) {
  	// in the new mode, cds will be nil, "deploy" and "upgrade" are instantiates.
  	var ccinp *peer.ChaincodeInput
  	var b []byte
  	var err error
  	if msg != nil {
  		b, err = proto.Marshal(msg)
  		if err != nil {
  			return nil, "", err
  		}
  	}
  	switch propType {
  	case "deploy":
  		fallthrough
  	case "upgrade":
  		cds, ok := msg.(*peer.ChaincodeDeploymentSpec)
  		if !ok || cds == nil {
  			return nil, "", errors.New("invalid message for creating lifecycle chaincode proposal")
  		}
  		Args := [][]byte{[]byte(propType), []byte(chainID), b}
  		Args = append(Args, args...)
  
  		ccinp = &peer.ChaincodeInput{Args: Args}
  	case "install":
  		ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), b}}
  	}
  
  	// wrap the deployment in an invocation spec to lscc...
  	lsccSpec := &peer.ChaincodeInvocationSpec{
  		ChaincodeSpec: &peer.ChaincodeSpec{
  			Type:        peer.ChaincodeSpec_GOLANG,
  			ChaincodeId: &peer.ChaincodeID{Name: "lscc"},
  			Input:       ccinp,
  		},
  	}
  
  	// ...and get the proposal for it
  	return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, chainID, lsccSpec, creator)
  }
docs: // createProposalFromCDS returns a deploy or upgrade proposal given a
  // serialized identity and a ChaincodeDeploymentSpec