async def get_schema(self, index: Union[SchemaKey, int, str]) -> str: """ Get schema from ledger by SchemaKey namedtuple (origin DID, name, version), sequence number, or schema identifier. Raise AbsentSchema for no such schema, logging any error condition and raising BadLedgerTxn on bad request. Retrieve the schema from the anchor's schema cache if it has it; cache it en passant if it does not (and there is a corresponding schema on the ledger). :param index: schema key (origin DID, name, version), sequence number, or schema identifier :return: schema json, parsed from ledger """ LOGGER.debug('BaseAnchor.get_schema >>> index: %s', index) rv_json = json.dumps({}) with SCHEMA_CACHE.lock: if SCHEMA_CACHE.contains(index): LOGGER.info('BaseAnchor.get_schema: got schema %s from cache', index) rv_json = SCHEMA_CACHE[index] LOGGER.debug('BaseAnchor.get_schema <<< %s', rv_json) return json.dumps(rv_json) if isinstance(index, SchemaKey) or (isinstance(index, str) and ok_schema_id(index)): s_id = schema_id(*index) if isinstance(index, SchemaKey) else index s_key = schema_key(s_id) req_json = await ledger.build_get_schema_request(self.did, s_id) resp_json = await self._submit(req_json) resp = json.loads(resp_json) if not ('result' in resp and resp['result'].get('data', {}).get('attr_names', None)): LOGGER.debug('BaseAnchor.get_schema <!< no schema exists on %s', index) raise AbsentSchema('No schema exists on {}'.format(index)) try: (_, rv_json) = await ledger.parse_get_schema_response(resp_json) except IndyError: # ledger replied, but there is no such schema LOGGER.debug('BaseAnchor.get_schema <!< no schema exists on %s', index) raise AbsentSchema('No schema exists on {}'.format(index)) SCHEMA_CACHE[s_key] = json.loads(rv_json) # cache indexes by both txn# and schema key en passant LOGGER.info('BaseAnchor.get_schema: got schema %s from ledger', index) elif isinstance(index, (int, str)): # index is not a schema id: it's a stringified int txn# if it's a str txn_json = await self.get_txn(int(index)) # raises AbsentPool if anchor has no pool txn = json.loads(txn_json) if txn.get('type', None) == '101': # {} for no such txn; 101 marks indy-sdk schema txn type rv_json = await self.get_schema(self.pool.protocol.txn_data2schema_key(txn)) else: LOGGER.debug('BaseAnchor.get_schema <!< no schema at seq #%s on ledger', index) raise AbsentSchema('No schema at seq #{} on ledger'.format(index)) else: LOGGER.debug('BaseAnchor.get_schema <!< bad schema index type') raise AbsentSchema('Attempt to get schema on ({}) {} , must use schema key or an int'.format( type(index), index)) LOGGER.debug('BaseAnchor.get_schema <<< %s', rv_json) return rv_json
async def _set_schema(s_id: str) -> None: nonlocal s_id2schema if not ok_schema_id(s_id): LOGGER.debug('Verifier.verify_proof <!< Bad schema id %s', s_id) raise BadIdentifier('Bad schema id {}'.format(s_id)) if s_id not in s_id2schema: schema = json.loads(await self.get_schema(s_id)) # add to cache en passant if not schema: LOGGER.debug( 'Verifier.verify_proof <!< absent schema %s, proof req may be for another ledger', s_id) raise AbsentSchema('Absent schema {}, proof req may be for another ledger'.format(s_id)) s_id2schema[s_id] = schema
async def verify_proof(self, proof_req: dict, proof: dict) -> str: """ Verify proof as Verifier. Raise AbsentRevReg if a proof cites a revocation registry that does not exist on the distributed ledger. :param proof_req: proof request as Verifier creates, as per proof_req_json above :param proof: proof as HolderProver creates :return: json encoded True if proof is valid; False if not """ LOGGER.debug('Verifier.verify_proof >>> proof_req: %s, proof: %s', proof_req, proof) s_id2schema = {} cd_id2cred_def = {} rr_id2rr_def = {} rr_id2rr = {} proof_ids = proof['identifiers'] for proof_id in proof_ids: # schema s_id = proof_id['schema_id'] if not ok_schema_id(s_id): LOGGER.debug('Verifier.verify_proof: <!< Bad schema id %s', s_id) raise BadIdentifier('Bad schema id {}'.format(s_id)) if s_id not in s_id2schema: schema = json.loads( await self.get_schema(s_id)) # add to cache en passant if not schema: LOGGER.debug( 'Verifier.verify_proof: <!< absent schema %s, proof req may be for another ledger', s_id) raise AbsentSchema( 'Absent schema {}, proof req may be for another ledger' .format(s_id)) s_id2schema[s_id] = schema # cred def cd_id = proof_id['cred_def_id'] if not ok_cred_def_id(cd_id): LOGGER.debug('Verifier.verify_proof: <!< Bad cred def id %s', cd_id) raise BadIdentifier('Bad cred def id {}'.format(cd_id)) if cd_id not in cd_id2cred_def: cred_def = json.loads( await self.get_cred_def(cd_id)) # add to cache en passant cd_id2cred_def[cd_id] = cred_def # rev reg def rr_id = proof_id['rev_reg_id'] if not rr_id: continue if not ok_rev_reg_id(rr_id): LOGGER.debug('Verifier.verify_proof: <!< Bad rev reg id %s', rr_id) raise BadIdentifier('Bad rev reg id {}'.format(rr_id)) rr_def_json = await self._get_rev_reg_def(rr_id) rr_id2rr_def[rr_id] = json.loads(rr_def_json) # timestamp timestamp = proof_id['timestamp'] with REVO_CACHE.lock: revo_cache_entry = REVO_CACHE.get(rr_id, None) (rr_json, _) = await revo_cache_entry.get_state_json( self._build_rr_state_json, timestamp, timestamp) if rr_id not in rr_id2rr: rr_id2rr[rr_id] = {} rr_id2rr[rr_id][timestamp] = json.loads(rr_json) rv = json.dumps(await anoncreds.verifier_verify_proof( json.dumps(proof_req), json.dumps(proof), json.dumps(s_id2schema), json.dumps(cd_id2cred_def), json.dumps(rr_id2rr_def), json.dumps(rr_id2rr))) LOGGER.debug('Verifier.verify_proof <<< %s', rv) return rv