docs: async def create_cred(
              self,
              cred_offer_json,
              cred_req_json: str,
              cred_attrs: dict,
              rr_size: int = None) -> (str, str):
          """
          Create credential as Issuer out of credential request and dict of key:value (raw, unencoded)
          entries for attributes.
  
          Return credential json, and if cred def supports revocation, credential revocation identifier.
          Raise WalletState for closed wallet.
  
          If the credential definition supports revocation, and the current revocation registry is full,
          the processing creates a new revocation registry en passant. Depending on the revocation
          registry size (by default starting at 64 and doubling iteratively through a maximum of 100000)
          and the revocation registry builder posture (see RevRegBuilder.__init__()), this operation may
          delay credential creation by several seconds. The use of an external revocation registry builder
          runs a parallel process, skirting this delay, but is more costly at initialization.
  
          :param cred_offer_json: credential offer json as created by Issuer
          :param cred_req_json: credential request json as created by HolderProver
          :param cred_attrs: dict mapping each attribute to its original value (the operation encodes it); e.g.,
  
          ::
  
              {
                  'favourite_drink': 'martini',
                  'height': 180,
                  'last_visit_date': '2017-12-31',
                  'weaknesses': None
              }
  
          :param rr_size: size of new revocation registry (default as per RevRegBuilder.create_rev_reg()) if necessary
          :return: tuple with newly issued credential json, credential revocation identifier (if cred def
              supports revocation, None otherwise).
          """
  
          LOGGER.debug(
              'Issuer.create_cred >>> cred_offer_json: %s, cred_req_json: %s, cred_attrs: %s, rr_size: %s',
              cred_offer_json,
              cred_req_json,
              cred_attrs,
              rr_size)
  
          if not self.wallet.handle:
              LOGGER.debug('Issuer.create_cred <!< Wallet %s is closed', self.name)
              raise WalletState('Wallet {} is closed'.format(self.name))
  
          cd_id = json.loads(cred_offer_json)['cred_def_id']
          if not ok_cred_def_id(cd_id):
              LOGGER.debug('Issuer.create_cred <!< Bad cred def id %s', cd_id)
              raise BadIdentifier('Bad cred def id {}'.format(cd_id))
  
          cred_def = json.loads(await self.get_cred_def(cd_id))  # ensure cred def is in cache
  
          if 'revocation' in cred_def['value']:
              with REVO_CACHE.lock:
                  rr_id = Tails.current_rev_reg_id(self.dir_tails, cd_id)
                  tails = REVO_CACHE[rr_id].tails
                  assert tails  # at (re)start, at cred def, Issuer sync_revoc_for_issue() sets this index in revo cache
  
                  try:
                      (cred_json, cred_revoc_id, _) = await anoncreds.issuer_create_credential(  # issue by default to rr
                          self.wallet.handle,
                          cred_offer_json,
                          cred_req_json,
                          json.dumps({k: cred_attr_value(cred_attrs[k]) for k in cred_attrs}),
                          rr_id,
                          tails.reader_handle)
                      rv = (cred_json, cred_revoc_id)
  
                  except IndyError as x_indy:
                      if x_indy.error_code == ErrorCode.AnoncredsRevocationRegistryFullError:
                          (tag, rr_size_suggested) = Tails.next_tag(self.dir_tails, cd_id)
                          rr_id = rev_reg_id(cd_id, tag)
                          if self.rrbx:
                              await self._set_rev_reg(rr_id, rr_size)
                          else:
                              await self.rrb.create_rev_reg(rr_id, rr_size or rr_size_suggested)
                              await self._send_rev_reg_def(rr_id)
  
                          REVO_CACHE[rr_id].tails = await Tails(self.dir_tails, cd_id).open()  # symlink OK now
                          return await self.create_cred(cred_offer_json, cred_req_json, cred_attrs)
  
                      LOGGER.debug('Issuer.create_cred <!< cannot create cred, indy error code %s', x_indy.error_code)
                      raise
          else:
              try:
                  (cred_json, _, _) = await anoncreds.issuer_create_credential(
                      self.wallet.handle,
                      cred_offer_json,
                      cred_req_json,
                      json.dumps({k: cred_attr_value(cred_attrs[k]) for k in cred_attrs}),
                      None,
                      None)
                  rv = (cred_json, None)
              except IndyError as x_indy:
                  LOGGER.debug('Issuer.create_cred <!< cannot create cred, indy error code %s', x_indy.error_code)
                  raise
  
          LOGGER.debug('Issuer.create_cred <<< %s', rv)
          return rv