async def get_cred_def(self, cd_id: str) -> str:
        LOGGER.debug('_BaseAgent.get_cred_def >>> cd_id: %s', cd_id)
        rv_json = json.dumps({})
        with CRED_DEF_CACHE.lock:
            if cd_id in CRED_DEF_CACHE:
                LOGGER.info('_BaseAgent.get_cred_def: got cred def for %s from cache', cd_id)
                rv_json = json.dumps(CRED_DEF_CACHE[cd_id])
                LOGGER.debug('_BaseAgent.get_cred_def <<< %s', rv_json)
                return rv_json
            req_json = await ledger.build_get_cred_def_request(self.did, cd_id)
            resp_json = await self._submit(req_json)
            resp = json.loads(resp_json)
            if not ('result' in resp and resp['result'].get('data', None)):
                LOGGER.debug('_BaseAgent.get_cred_def: <!< no cred def exists on %s', cd_id)
                raise AbsentCredDef('No cred def exists on {}'.format(cd_id))
            try:
                (_, rv_json) = await ledger.parse_get_cred_def_response(resp_json)
            except IndyError:
                LOGGER.debug('_BaseAgent.get_cred_def: <!< no cred def exists on %s', cd_id)
                raise AbsentCredDef('No cred def exists on {}'.format(cd_id))
            CRED_DEF_CACHE[cd_id] = json.loads(rv_json)
            LOGGER.info('_BaseAgent.get_cred_def: got cred def %s from ledger', cd_id)
        LOGGER.debug('_BaseAgent.get_cred_def <<< %s', rv_json)
        return rv_json