Build and return indy-sdk requested credentials json from input indy-sdk creds structure
        through specified filter.

        :param creds: indy-sdk creds structure
        :param filt: filter  mapping cred def ids to:
            - (optionally) 'attr-match': dict mapping attributes to values (omit, empty dict, or None to match all);
            - (optionally) 'minima': (pred) integer lower-bounds of interest (omit, empty dict, or None to match all);
            omit parameter or specify empty dict or None for no filter, matching all; e.g.,

        ::

            {
                'Vx4E82R17q...:3:CL:16:0': {
                    'attr-match': {
                        'name': 'Alex',
                        'sex': 'M',
                        'favouriteDrink': None
                    },
                    'minima': {  # if both attr-match and minima present, combined conjunctively (i.e., via AND)
                        'favouriteNumber' : 10,
                        'score': 100  # if more than one minimum present, combined conjunctively (i.e., via AND)
                    }
                },
                'R17v42T4pk...:3:CL:19:0': {
                    'attr-match': {
                        'height': 175,
                        'birthdate': '1975-11-15'  # combined conjunctively (i.e., via AND)
                    }
                },
                'Z9ccax812j...:3:CL:27:0': {
                    'attr-match': {}  # match all attributes on this cred def
                },
                '9cHbp54C8n...:3:CL:37:0': {
                    'minima': {  # request all attributes on this cred def, request preds specifying employees>=50
                        'employees' : 50,
                    }
                }
                ...
            }

        :param filt_dflt_incl: whether to request (True) all creds by attribute/predicate
            that filter does not identify by cred def, or (False) to exclude them. Note that
            if the filter is None or {}, this parameter is unnecessary - it applies to a filter,
            not a non-filter.
        :return: indy_sdk requested_credentials json for use in proof creation

async def build_req_creds_json(self, creds: dict, filt: dict = None, filt_dflt_incl: bool = False) -> str:
        """
        Build and return indy-sdk requested credentials json from input indy-sdk creds structure
        through specified filter.

        :param creds: indy-sdk creds structure
        :param filt: filter  mapping cred def ids to:
            - (optionally) 'attr-match': dict mapping attributes to values (omit, empty dict, or None to match all);
            - (optionally) 'minima': (pred) integer lower-bounds of interest (omit, empty dict, or None to match all);
            omit parameter or specify empty dict or None for no filter, matching all; e.g.,

        ::

            {
                'Vx4E82R17q...:3:CL:16:0': {
                    'attr-match': {
                        'name': 'Alex',
                        'sex': 'M',
                        'favouriteDrink': None
                    },
                    'minima': {  # if both attr-match and minima present, combined conjunctively (i.e., via AND)
                        'favouriteNumber' : 10,
                        'score': 100  # if more than one minimum present, combined conjunctively (i.e., via AND)
                    }
                },
                'R17v42T4pk...:3:CL:19:0': {
                    'attr-match': {
                        'height': 175,
                        'birthdate': '1975-11-15'  # combined conjunctively (i.e., via AND)
                    }
                },
                'Z9ccax812j...:3:CL:27:0': {
                    'attr-match': {}  # match all attributes on this cred def
                },
                '9cHbp54C8n...:3:CL:37:0': {
                    'minima': {  # request all attributes on this cred def, request preds specifying employees>=50
                        'employees' : 50,
                    }
                }
                ...
            }

        :param filt_dflt_incl: whether to request (True) all creds by attribute/predicate
            that filter does not identify by cred def, or (False) to exclude them. Note that
            if the filter is None or {}, this parameter is unnecessary - it applies to a filter,
            not a non-filter.
        :return: indy_sdk requested_credentials json for use in proof creation
        """

        LOGGER.debug('HolderProver.build_req_creds_json >>> creds: %s, filt: %s', creds, filt)

        req_creds = {
            'self_attested_attributes': {},
            'requested_attributes': {},
            'requested_predicates': {}
        }

        def _add_cred(cred, uuid, key):
            nonlocal req_creds
            req_creds[key][uuid] = {
                'cred_id': cred['cred_info']['referent'],
                'revealed': True
            }
            if cred.get('interval', None):
                req_creds[key][uuid]['timestamp'] = cred['interval']['to']
            if key == 'requested_attributes':
                req_creds[key][uuid]['revealed'] = True

        if filt:
            for cd_id in filt:
                try:
                    json.loads(await self.get_cred_def(cd_id))
                except AbsentCredDef:
                    LOGGER.warning(
                        'HolderProver.build_req_creds_json: ignoring filter criterion, no cred def on %s', cd_id)
                    filt.pop(cd_id)

        for attr_uuid in creds.get('attrs', {}):
            for cred in creds['attrs'][attr_uuid]:
                if attr_uuid in req_creds['requested_attributes']:
                    continue
                cred_info = cred['cred_info']
                cred_cd_id = cred_info['cred_def_id']

                if filt:
                    if cred_cd_id not in filt:
                        if filt_dflt_incl:
                            _add_cred(cred, attr_uuid, 'requested_attributes')
                        continue
                    if cred_cd_id in filt and 'attr-match' in (filt[cred_cd_id] or {}):  # maybe filt[cred_cd_id]: None
                        if not {k: str(filt[cred_cd_id].get('attr-match', {})[k])
                                for k in filt[cred_cd_id].get('attr-match', {})}.items() <= cred_info['attrs'].items():
                            continue
                    _add_cred(cred, attr_uuid, 'requested_attributes')
                else:
                    _add_cred(cred, attr_uuid, 'requested_attributes')

        for pred_uuid in creds.get('predicates', {}):
            for cred in creds['predicates'][pred_uuid]:
                if pred_uuid in req_creds['requested_predicates']:
                    continue
                cred_info = cred['cred_info']
                cred_cd_id = cred_info['cred_def_id']

                if filt:
                    if cred_cd_id not in filt:
                        if filt_dflt_incl:
                            _add_cred(cred, pred_uuid, 'requested_predicates')
                        continue
                    if cred_cd_id in filt and 'minima' in (filt[cred_cd_id] or {}):  # maybe filt[cred_cd_id]: None
                        minima = filt[cred_cd_id].get('minima', {})
                        try:
                            if any((attr not in cred_info['attrs'])
                                or (int(cred_info['attrs'][attr]) < int(minima[attr]))
                                    for attr in minima):
                                continue
                        except ValueError:
                            continue  # int conversion failed - reject candidate
                    _add_cred(cred, pred_uuid, 'requested_predicates')
                else:
                    _add_cred(cred, pred_uuid, 'requested_predicates')

        rv_json = json.dumps(req_creds)
        LOGGER.debug('HolderProver.build_req_creds_json <<< %s', rv_json)
        return rv_json