docs: 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.,
  
          ::
  
              {
                  'Vx4E82R17q...:3:CL:16:tag': {
                      '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
                  },
                  'R17v42T4pk...:3:CL:19:tag': None,  # request all attrs, no preds, default intervals on all attrs
                  'e3vc5K168n...:3:CL:23:tag': {},  # request all attrs, no preds, default intervals on all attrs
                  'Z9ccax812j...:3:CL:27:tag': {  # request all attrs, no preds, this interval on all attrs
                      'interval': (1528112408, 1528116008)
                  },
                  '9cHbp54C8n...:3:CL:37:tag': {  # request no attrs and some predicates; specify interval
                      '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)
                  },
                  '6caBcmLi33...:3:CL:41:tag': {  # all attrs, one pred, default intervals to now on attrs & pred
                      '>': {
                          '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)