Skip to content

Commit

Permalink
Merge pull request #333 from sklump/cred-def-reconstruct
Browse files Browse the repository at this point in the history
revisit send-cred-def and associated non-secret record write
  • Loading branch information
andrewwhitehead committed Jan 24, 2020
2 parents 4b77626 + 4e4cc98 commit 870f31e
Show file tree
Hide file tree
Showing 2 changed files with 327 additions and 214 deletions.
160 changes: 86 additions & 74 deletions aries_cloudagent/ledger/indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import asyncio
import json
import logging
import re
import tempfile

from hashlib import sha256
Expand Down Expand Up @@ -486,95 +485,108 @@ async def send_credential_definition(self, schema_id: str, tag: str = None):
"""

async def cred_def_in_wallet(wallet_handle, cred_def_id) -> bool:
"""Create an offer to check whether cred def id is in wallet."""
try:
await indy.anoncreds.issuer_create_credential_offer(
wallet_handle,
cred_def_id
)
return True
except IndyError as error:
if error.error_code != ErrorCode.CommonInvalidStructure:
raise IndyErrorHandler.wrap_error(error) from error
# CommonInvalidStructure signifies no such cred def in wallet: pass
return False

public_info = await self.wallet.get_public_did()
if not public_info:
raise BadLedgerRequestError(
"Cannot publish credential definition without a public DID"
)

schema = await self.get_schema(schema_id)
credential_definition_json = None

# TODO: add support for tag, sig type, and config
try:
(
credential_definition_id,
credential_definition_json,
) = await indy.anoncreds.issuer_create_and_store_credential_def(
self.wallet.handle,
public_info.did,
json.dumps(schema),
tag or "default",
"CL",
json.dumps({"support_revocation": False}),
if not schema:
raise LedgerError(f"Ledger {self.pool_name} has no schema {schema_id}")

# check if cred def is on ledger already
for test_tag in [tag, ] if tag else ["tag", "default"]:
credential_definition_id = (
f"{public_info.did}:3:CL:{str(schema['seqNo'])}:{test_tag}"
)
ledger_cred_def = await self.fetch_credential_definition(
credential_definition_id
)
# If the cred def already exists in the wallet, we need some way of obtaining
# that cred def id (from schema id passed) since we can now assume we can use
# it in future operations.
except IndyError as error:
if error.error_code == ErrorCode.AnoncredsCredDefAlreadyExistsError:
try:
credential_definition_id = re.search(
r"\w*:3:CL:(([1-9][0-9]*)|(.{21,22}:2:.+:[0-9.]+)):\w*",
error.message,
).group(0)
# The regex search failed so let the error bubble up
except AttributeError:
if ledger_cred_def:
self.logger.warning(
"Credential definition %s already exists on ledger %s",
credential_definition_id,
self.pool_name,
)
if not await cred_def_in_wallet(
self.wallet.handle, credential_definition_id
):
raise LedgerError(
"Previous credential definition exists, but ID could "
"not be extracted"
f"Credential definition {credential_definition_id} is on "
f"ledger {self.pool_name} but not in wallet {self.wallet.name}"
)
else:
raise IndyErrorHandler.wrap_error(error) from error

# check if the cred def already exists on the ledger
created_cred_def = json.loads(
credential_definition_json
) if credential_definition_json else None
exist_def = await self.fetch_credential_definition(credential_definition_id)

if created_cred_def:
if exist_def:
if exist_def["value"] != created_cred_def["value"]:
self.logger.warning(
"Ledger definition of cred def %s will be replaced",
credential_definition_id,
)
exist_def = None
else:
if not exist_def:
break
else: # no such cred def on ledger
if await cred_def_in_wallet(self.wallet.handle, credential_definition_id):
raise LedgerError(
f"Wallet {self.wallet.name} "
f"does not pertain to ledger on pool {self.pool_name}"
f"Credential definition {credential_definition_id} is in wallet "
f"{self.wallet.name} but not on ledger {self.pool_name}"
)

if not exist_def:
with IndyErrorHandler("Exception when building cred def request"):
request_json = await indy.ledger.build_cred_def_request(
public_info.did, credential_definition_json
# Cred def is neither on ledger nor in wallet: create and send it
try:
(
credential_definition_id,
credential_definition_json,
) = await indy.anoncreds.issuer_create_and_store_credential_def(
self.wallet.handle,
public_info.did,
json.dumps(schema),
tag or "default",
"CL",
json.dumps({"support_revocation": False}),
)
await self._submit(request_json, True, public_did=public_info.did)
else:
self.logger.warning(
"Ledger definition of cred def %s already exists",
credential_definition_id,
)
except IndyError as error:
raise IndyErrorHandler.wrap_error(error) from error
else: # created cred def in wallet OK
wallet_cred_def = json.loads(credential_definition_json)
with IndyErrorHandler("Exception when building cred def request"):
request_json = await indy.ledger.build_cred_def_request(
public_info.did, credential_definition_json
)
await self._submit(request_json, True, public_did=public_info.did)
ledger_cred_def = await self.fetch_credential_definition(
credential_definition_id
)
assert wallet_cred_def["value"] == ledger_cred_def["value"]

schema_id_parts = schema_id.split(":")
cred_def_tags = {
"schema_id": schema_id,
"schema_issuer_did": schema_id_parts[0],
"schema_name": schema_id_parts[-2],
"schema_version": schema_id_parts[-1],
"issuer_did": public_info.did,
"cred_def_id": credential_definition_id,
"epoch": str(int(time())),
}
record = StorageRecord(
CRED_DEF_SENT_RECORD_TYPE, credential_definition_id, cred_def_tags,
)
# Add non-secrets records if not yet present
storage = self.get_indy_storage()
await storage.add_record(record)
found = await storage.search_records(
type_filter=CRED_DEF_SENT_RECORD_TYPE,
tag_query={"cred_def_id": credential_definition_id}
).fetch_all()

if not found:
schema_id_parts = schema_id.split(":")
cred_def_tags = {
"schema_id": schema_id,
"schema_issuer_did": schema_id_parts[0],
"schema_name": schema_id_parts[-2],
"schema_version": schema_id_parts[-1],
"issuer_did": public_info.did,
"cred_def_id": credential_definition_id,
"epoch": str(int(time())),
}
record = StorageRecord(
CRED_DEF_SENT_RECORD_TYPE, credential_definition_id, cred_def_tags,
)
await storage.add_record(record)

return credential_definition_id

Expand Down

0 comments on commit 870f31e

Please sign in to comment.