<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 async def build_proof_req_json(self, cd_id2spec: dict) -> str: """ Build and return indy-sdk proof request for input attributes and non-revocation intervals by cred def id. :param cd_id2spec: dict mapping cred def ids to: - (optionally) 'attrs': lists of names of attributes of interest (omit for all, empty list or None for none) - (optionally) '>=': (pred) inclusive int lower-bounds of interest (omit, empty list, or None for none) - (optionally) '>': (pred) exclusive int lower-bounds of interest (omit, empty list, or None for none) - (optionally) '<=': (pred) inclusive int upper-bounds of interest (omit, empty list, or None for none) - (optionally) '<': (pred) exclusive int upper-bounds of interest (omit, empty list, or None for none) - (optionally), 'interval': either - (2-tuple) pair of epoch second counts marking 'from' and 'to' timestamps, or - | single epoch second count to set 'from' and 'to' the same; default | (now, now) for cred defs supporting revocation or None otherwise; e.g., :: { 'attrs': [ # request attrs 'name' and 'favouriteDrink' from this cred def's schema 'name', 'favouriteDrink' ], '>=': { # request predicate score>=80 from this cred def 'score': 80 } '<=': { # request ranking <=10 from this cred def 'ranking': 10 } 'interval': 1528116008 # same instant for all attrs and preds of corresponding schema }, 'interval': (1528112408, 1528116008) }, 'attrs': [], # or equivalently, 'attrs': None '>=': { 'employees': '50' # nicety: implementation converts to int for caller }, '>=': { 'revenue': '10000000' # nicety: implementation converts to int for caller 'ebidta': 0 } 'interval': (1528029608, 1528116008) }, '>': { 'regEpoch': 1514782800 } }, } :return: indy-sdk proof request json """


        LOGGER.debug('Verifier.build_proof_req_json >>> cd_id2spec: %s', cd_id2spec)

        cd_id2schema = {}
        now = int(time())
        rv = {
            'nonce': str(int(time())),
            'name': 'proof_req',
            'version': '0.0',
            'requested_attributes': {},
            'requested_predicates': {}
        }

        for cd_id in cd_id2spec:
            if not ok_cred_def_id(cd_id):
                LOGGER.debug('Verifier.build_proof_req_json <!< Bad cred def id %s', cd_id)
                raise BadIdentifier('Bad cred def id {}'.format(cd_id))

            interval = None
            cred_def = json.loads(await self.get_cred_def(cd_id))
            seq_no = cred_def_id2seq_no(cd_id)
            cd_id2schema[cd_id] = json.loads(await self.get_schema(seq_no))

            if 'revocation' in cred_def['value']:
                fro_to = cd_id2spec[cd_id].get('interval', (now, now)) if cd_id2spec[cd_id] else (now, now)
                interval = {
                    'from': fro_to if isinstance(fro_to, int) else min(fro_to),
                    'to': fro_to if isinstance(fro_to, int) else max(fro_to)
                }

            for attr in (cd_id2spec[cd_id].get('attrs', cd_id2schema[cd_id]['attrNames']) or []
                    if cd_id2spec[cd_id] else cd_id2schema[cd_id]['attrNames']):
                attr_uuid = '{}_{}_uuid'.format(seq_no, canon(attr))
                rv['requested_attributes'][attr_uuid] = {
                    'name': attr,
                    'restrictions': [{
                        'cred_def_id': cd_id
                    }]
                }
                if interval:
                    rv['requested_attributes'][attr_uuid]['non_revoked'] = interval

            for pred in Predicate:
                for attr in (cd_id2spec[cd_id].get(pred.value.math, {}) or {} if cd_id2spec[cd_id] else {}):
                    pred_uuid = '{}_{}_{}_uuid'.format(seq_no, canon(attr), pred.value.fortran)
                    try:
                        rv['requested_predicates'][pred_uuid] = {
                            'name': attr,
                            'p_type': pred.value.math,
                            'p_value': Predicate.to_int(cd_id2spec[cd_id][pred.value.math][attr]),
                            'restrictions': [{
                                'cred_def_id': cd_id
                            }]
                        }
                    except ValueError:
                        LOGGER.info(
                            'cannot build %s predicate on non-int bound %s for %s',
                            pred.value.fortran,
                            cd_id2spec[cd_id][pred.value.math][attr],
                            attr)
                        continue  # int conversion failed - reject candidate
                    if interval:
                        rv['requested_predicates'][pred_uuid]['non_revoked'] = interval

        LOGGER.debug('Verifier.build_proof_req_json <<< %s', json.dumps(rv))
        return json.dumps(rv)