Beispiel #1
0
    async def send_schema(self, schema_data_json: str) -> str:
        """
        Send schema to ledger, then retrieve it as written to the ledger and return it.
        If schema already exists on ledger, log error and return schema.

        :param schema_data_json: schema data json with name, version, attribute names; e.g.,

        ::

            {
                'name': 'my-schema',
                'version': '1.234',
                'attr_names': ['favourite_drink', 'height', 'last_visit_date']
            }

        :return: schema json as written to ledger (or existed a priori)
        """

        LOGGER.debug('Origin.send_schema >>> schema_data_json: %s',
                     schema_data_json)

        schema_data = json.loads(schema_data_json)
        s_key = schema_key(
            schema_id(self.did, schema_data['name'], schema_data['version']))
        with SCHEMA_CACHE.lock:
            try:
                rv_json = await self.get_schema(s_key)
                LOGGER.error(
                    'Schema %s version %s already exists on ledger for origin-did %s: not sending',
                    schema_data['name'], schema_data['version'], self.did)
            except AbsentSchema:  # OK - about to create and send it
                (_, schema_json) = await anoncreds.issuer_create_schema(
                    self.did, schema_data['name'], schema_data['version'],
                    json.dumps(schema_data['attr_names']))
                req_json = await ledger.build_schema_request(
                    self.did, schema_json)
                resp_json = await self._sign_submit(req_json)
                resp = json.loads(resp_json)
                resp_result_txn = resp['result']['txn']
                rv_json = await self.get_schema(
                    schema_key(
                        schema_id(resp_result_txn['metadata']['from'],
                                  resp_result_txn['data']['data']['name'],
                                  resp_result_txn['data']['data']['version']))
                )  # add to cache en passant

        LOGGER.debug('Origin.send_schema <<< %s', rv_json)
        return rv_json
Beispiel #2
0
async def test_schema_cache():
    N = 32
    s_key = []
    schema = []
    for i in range(N):
        s_key.append(
            SchemaKey('did.{}'.format(i), 'schema-{}'.format(i // 5),
                      '{}'.format(i % 5)))
        schema.append({
            # 'id': schema_id(s_key[i].origin_did, s_key[i].name, s_key[i].version),
            'id':
            schema_id(*s_key[i]),
            'name':
            s_key[i].version,
            'version':
            s_key[i].version,
            'seqNo':
            i,
            'attrNames': ['attr-{}-{}'.format(i, j) for j in range(N)],
            'ver':
            '1.0'
        })

    for i in range(N):
        if i % 2:
            SCHEMA_CACHE[s_key[i]] = schema[i]
        else:
            SCHEMA_CACHE[schema[i]['seqNo']] = schema[i]

    for i in range(N):
        assert SCHEMA_CACHE.contains(s_key[i])
        assert SCHEMA_CACHE.contains(schema[i]['seqNo'])
        assert SCHEMA_CACHE[s_key[i]] == SCHEMA_CACHE[schema[i]['seqNo']]

    assert len(SCHEMA_CACHE.index()) == N
    assert not SCHEMA_CACHE.contains(-1)

    try:
        SCHEMA_CACHE[-1]
    except CacheIndex:
        pass

    # Exercise cache clearing and feeding
    cached = SCHEMA_CACHE.schemata()
    assert SCHEMA_CACHE.schemata()
    cached_json = json.dumps(cached)
    SCHEMA_CACHE.clear()
    assert not SCHEMA_CACHE.schemata()
    SCHEMA_CACHE.feed(json.loads(cached_json))
    assert len(SCHEMA_CACHE.schemata()) == len(cached)
Beispiel #3
0
async def test_schema_cache():
    N = 5
    s_key = []
    schema = []
    for i in range(N):
        s_key.append(
            SchemaKey('did.{}'.format(i), 'schema-{}'.format(i // 5),
                      '{}'.format(i % 5)))
        schema.append({
            # 'id': schema_id(s_key[i].origin_did, s_key[i].name, s_key[i].version),
            'id':
            schema_id(*s_key[i]),
            'name':
            s_key[i].version,
            'version':
            s_key[i].version,
            'seqNo':
            i,
            'attrNames': ['attr-{}-{}'.format(i, j) for j in range(N)],
            'ver':
            '1.0'
        })

    for i in range(N):
        if i % 2:
            SCHEMA_CACHE[s_key[i]] = schema[i]
        else:
            SCHEMA_CACHE[schema[i]['seqNo']] = schema[i]

    for i in range(N):
        assert SCHEMA_CACHE.contains(s_key[i])
        assert SCHEMA_CACHE.contains(schema[i]['seqNo'])
        assert SCHEMA_CACHE[s_key[i]] == SCHEMA_CACHE[schema[i]['seqNo']]

    assert len(SCHEMA_CACHE.index()) == N
    assert not SCHEMA_CACHE.contains(-1)

    try:
        SCHEMA_CACHE[-1]
    except CacheIndex:
        pass
Beispiel #4
0
 async def _resolve_schemas(self) -> bool:
     LOGGER.info('Resolving schemas for prover')
     await asyncio.sleep(5)
     synced = False
     while not synced:
         missing = set()
         for spec in self._request_specs.values():
             for schema in spec['schemas']:
                 if 'id' not in schema:
                     s_key = schema['key']
                     if 'did' not in s_key:
                         missing.add((s_key['name'], s_key['version']))
                     else:
                         schema['id'] = schema_id(s_key['did'],
                                                  s_key['name'],
                                                  s_key['version'])
         if not missing:
             synced = True
         else:
             for s_key in missing:
                 self.send('issuer-manager', None,
                           ResolveSchemaRequest(*s_key))
             await asyncio.sleep(1)
     return synced
Beispiel #5
0
    async def _publish_schema(self, issuer: VonIssuer, schema: dict) -> None:
        """
        Check the ledger for a specific schema and version, and publish it if not found.
        Also publish the related credential definition if not found

        Args:
            issuer: the initialized and opened issuer instance publishing the schema
            schema: a dict which will be updated with the published schema and credential def
        """

        if not schema or "definition" not in schema:
            raise ValueError("Missing schema definition")
        definition = schema["definition"]

        if not schema.get("ledger"):
            LOGGER.info(
                "Checking for schema: %s (%s)",
                definition.name,
                definition.version,
            )
            # Check if schema exists on ledger

            try:
                s_key = schema_key(
                    schema_id(issuer.did, definition.name, definition.version)
                )
                schema_json = await issuer.get_schema(s_key)
                ledger_schema = json.loads(schema_json)
                log_json("Schema found on ledger:", ledger_schema, LOGGER)
            except AbsentSchema:
                # If not found, send the schema to the ledger
                LOGGER.info(
                    "Publishing schema: %s (%s)",
                    definition.name,
                    definition.version,
                )
                schema_json = await issuer.send_schema(
                    json.dumps(
                        {
                            "name": definition.name,
                            "version": definition.version,
                            "attr_names": definition.attr_names,
                        }
                    )
                )
                ledger_schema = json.loads(schema_json)
                if not ledger_schema or not ledger_schema.get("seqNo"):
                    raise RuntimeError("Schema was not published to ledger")
                log_json("Published schema:", ledger_schema, LOGGER)
            schema["ledger"] = ledger_schema

        if not schema.get("credential_definition"):
            # Check if credential definition has been published
            LOGGER.info(
                "Checking for credential def: %s (%s)",
                definition.name,
                definition.version,
            )

            try:
                cred_def_json = await issuer.get_cred_def(
                    cred_def_id(issuer.did, schema["ledger"]["seqNo"])
                )
                cred_def = json.loads(cred_def_json)
                log_json("Credential def found on ledger:", cred_def, LOGGER)
            except AbsentCredDef:
                # If credential definition is not found then publish it
                LOGGER.info(
                    "Publishing credential def: %s (%s)",
                    definition.name,
                    definition.version,
                )
                cred_def_json = await issuer.send_cred_def(
                    schema_json, revocation=False
                )
                cred_def = json.loads(cred_def_json)
                log_json("Published credential def:", cred_def, LOGGER)
            schema["credential_definition"] = cred_def
Beispiel #6
0
    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 agent'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('_BaseAgent.get_schema >>> index: %s', index)

        rv_json = json.dumps({})
        with SCHEMA_CACHE.lock:
            if SCHEMA_CACHE.contains(index):
                LOGGER.info(
                    '_BaseAgent.get_schema: got schema %s from schema cache',
                    index)
                rv_json = SCHEMA_CACHE[index]
                LOGGER.debug('_BaseAgent.get_schema <<< %s', rv_json)
                return json.dumps(rv_json)

            if isinstance(index, SchemaKey) or (isinstance(index, str)
                                                and ':2:' in 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(
                        '_BaseAgent.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(
                        '_BaseAgent.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('_BaseAgent.get_schema: got schema %s from ledger',
                            index)

            elif isinstance(
                    index, (int, str)
            ):  # ':2:' not in index - it's a stringified int txn num if it's a str
                txn_json = await self.get_txn(int(index))
                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(
                        SchemaKey(txn['metadata']['from'],
                                  txn['data']['data']['name'],
                                  txn['data']['data']['version']))
                else:
                    LOGGER.info(
                        '_BaseAgent.get_schema: no schema at seq #%s on ledger',
                        index)

            else:
                LOGGER.debug(
                    '_BaseAgent.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('_BaseAgent.get_schema <<< %s', rv_json)
        return rv_json