Skip to content

Commit d5ac9dd

Browse files
authored
Merge branch 'main' into fix/put-redirect
2 parents 9ee7b2a + 592dfd0 commit d5ac9dd

6 files changed

Lines changed: 254 additions & 200 deletions

File tree

aries_cloudagent/indy/credx/issuer.py

Lines changed: 104 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
)
2121

2222
from ...askar.profile import AskarProfile
23-
from ...core.profile import ProfileSession
2423

2524
from ..issuer import (
2625
IndyIssuer,
@@ -384,7 +383,6 @@ async def revoke_credentials(
384383
revoc_reg_id: str,
385384
tails_file_path: str,
386385
cred_revoc_ids: Sequence[str],
387-
transaction: ProfileSession = None,
388386
) -> Tuple[str, Sequence[str]]:
389387
"""
390388
Revoke a set of credentials in a revocation registry.
@@ -399,66 +397,84 @@ async def revoke_credentials(
399397
400398
"""
401399

402-
txn = transaction if transaction else await self._profile.transaction()
403-
try:
404-
rev_reg_def = await txn.handle.fetch(CATEGORY_REV_REG_DEF, revoc_reg_id)
405-
rev_reg = await txn.handle.fetch(
406-
CATEGORY_REV_REG, revoc_reg_id, for_update=True
407-
)
408-
rev_reg_info = await txn.handle.fetch(
409-
CATEGORY_REV_REG_INFO, revoc_reg_id, for_update=True
410-
)
411-
if not rev_reg_def:
412-
raise IndyIssuerError("Revocation registry definition not found")
413-
if not rev_reg:
414-
raise IndyIssuerError("Revocation registry not found")
415-
if not rev_reg_info:
416-
raise IndyIssuerError("Revocation registry metadata not found")
417-
except AskarError as err:
418-
raise IndyIssuerError("Error retrieving revocation registry") from err
400+
delta = None
401+
failed_crids = set()
402+
max_attempt = 5
403+
attempt = 0
419404

420-
try:
421-
rev_reg_def = RevocationRegistryDefinition.load(rev_reg_def.raw_value)
422-
except CredxError as err:
423-
raise IndyIssuerError(
424-
"Error loading revocation registry definition"
425-
) from err
426-
427-
rev_crids = []
428-
failed_crids = []
429-
max_cred_num = rev_reg_def.max_cred_num
430-
rev_info = rev_reg_info.value_json
431-
used_ids = set(rev_info.get("used_ids") or [])
432-
433-
for rev_id in cred_revoc_ids:
434-
rev_id = int(rev_id)
435-
if rev_id < 1 or rev_id > max_cred_num:
436-
LOGGER.error(
437-
"Skipping requested credential revocation"
438-
"on rev reg id %s, cred rev id=%s not in range",
439-
revoc_reg_id,
440-
rev_id,
441-
)
442-
elif rev_id > rev_info["curr_id"]:
443-
LOGGER.warn(
444-
"Skipping requested credential revocation"
445-
"on rev reg id %s, cred rev id=%s not yet issued",
446-
revoc_reg_id,
447-
rev_id,
448-
)
449-
elif rev_id in used_ids:
450-
LOGGER.warn(
451-
"Skipping requested credential revocation"
452-
"on rev reg id %s, cred rev id=%s already revoked",
453-
revoc_reg_id,
454-
rev_id,
455-
)
456-
else:
457-
rev_crids.append(rev_id)
405+
while True:
406+
attempt += 1
407+
if attempt >= max_attempt:
408+
raise IndyIssuerError("Repeated conflict attempting to update registry")
409+
try:
410+
async with self._profile.session() as session:
411+
rev_reg_def = await session.handle.fetch(
412+
CATEGORY_REV_REG_DEF, revoc_reg_id
413+
)
414+
rev_reg = await session.handle.fetch(CATEGORY_REV_REG, revoc_reg_id)
415+
rev_reg_info = await session.handle.fetch(
416+
CATEGORY_REV_REG_INFO, revoc_reg_id
417+
)
418+
if not rev_reg_def:
419+
raise IndyIssuerError("Revocation registry definition not found")
420+
if not rev_reg:
421+
raise IndyIssuerError("Revocation registry not found")
422+
if not rev_reg_info:
423+
raise IndyIssuerError("Revocation registry metadata not found")
424+
except AskarError as err:
425+
raise IndyIssuerError("Error retrieving revocation registry") from err
426+
427+
try:
428+
rev_reg_def = RevocationRegistryDefinition.load(rev_reg_def.raw_value)
429+
except CredxError as err:
430+
raise IndyIssuerError(
431+
"Error loading revocation registry definition"
432+
) from err
433+
434+
rev_crids = set()
435+
failed_crids = set()
436+
max_cred_num = rev_reg_def.max_cred_num
437+
rev_info = rev_reg_info.value_json
438+
used_ids = set(rev_info.get("used_ids") or [])
439+
440+
for rev_id in cred_revoc_ids:
441+
rev_id = int(rev_id)
442+
if rev_id < 1 or rev_id > max_cred_num:
443+
LOGGER.error(
444+
"Skipping requested credential revocation"
445+
"on rev reg id %s, cred rev id=%s not in range",
446+
revoc_reg_id,
447+
rev_id,
448+
)
449+
failed_crids.add(rev_id)
450+
elif rev_id > rev_info["curr_id"]:
451+
LOGGER.warn(
452+
"Skipping requested credential revocation"
453+
"on rev reg id %s, cred rev id=%s not yet issued",
454+
revoc_reg_id,
455+
rev_id,
456+
)
457+
failed_crids.add(rev_id)
458+
elif rev_id in used_ids:
459+
LOGGER.warn(
460+
"Skipping requested credential revocation"
461+
"on rev reg id %s, cred rev id=%s already revoked",
462+
revoc_reg_id,
463+
rev_id,
464+
)
465+
failed_crids.add(rev_id)
466+
else:
467+
rev_crids.add(rev_id)
468+
469+
if not rev_crids:
470+
break
458471

459-
if rev_crids:
460472
try:
461473
rev_reg = RevocationRegistry.load(rev_reg.raw_value)
474+
except CredxError as err:
475+
raise IndyIssuerError("Error loading revocation registry") from err
476+
477+
try:
462478
delta = await asyncio.get_event_loop().run_in_executor(
463479
None,
464480
lambda: rev_reg.update(
@@ -472,31 +488,41 @@ async def revoke_credentials(
472488
raise IndyIssuerError("Error updating revocation registry") from err
473489

474490
try:
475-
await txn.handle.replace(
476-
CATEGORY_REV_REG, revoc_reg_id, rev_reg.to_json_buffer()
477-
)
478-
used_ids.update(rev_crids)
479-
rev_info["used_ids"] = list(used_ids)
480-
await txn.handle.replace(
481-
CATEGORY_REV_REG_INFO, revoc_reg_id, value_json=rev_info
482-
)
483-
for cred_rev_id in rev_crids:
484-
issuer_cr_rec = await IssuerCredRevRecord.retrieve_by_ids(
485-
txn,
486-
revoc_reg_id,
487-
str(cred_rev_id),
491+
async with self._profile.transaction() as txn:
492+
rev_reg_upd = await txn.handle.fetch(
493+
CATEGORY_REV_REG, revoc_reg_id, for_update=True
494+
)
495+
rev_info_upd = await txn.handle.fetch(
496+
CATEGORY_REV_REG_INFO, revoc_reg_id, for_update=True
488497
)
489-
await issuer_cr_rec.set_state(
490-
txn, IssuerCredRevRecord.STATE_REVOKED
498+
if not rev_reg_upd or not rev_reg_info:
499+
LOGGER.warn(
500+
"Revocation registry missing, skipping update: {}",
501+
revoc_reg_id,
502+
)
503+
delta = None
504+
break
505+
rev_info_upd = rev_info_upd.value_json
506+
if rev_info_upd != rev_info:
507+
# handle concurrent update to the registry by retrying
508+
continue
509+
await txn.handle.replace(
510+
CATEGORY_REV_REG, revoc_reg_id, rev_reg.to_json_buffer()
511+
)
512+
used_ids.update(rev_crids)
513+
rev_info_upd["used_ids"] = sorted(used_ids)
514+
await txn.handle.replace(
515+
CATEGORY_REV_REG_INFO, revoc_reg_id, value_json=rev_info_upd
491516
)
492-
if not transaction:
493517
await txn.commit()
494518
except AskarError as err:
495519
raise IndyIssuerError("Error saving revocation registry") from err
496-
else:
497-
delta = None
520+
break
498521

499-
return (delta and delta.to_json(), failed_crids)
522+
return (
523+
delta and delta.to_json(),
524+
[str(rev_id) for rev_id in sorted(failed_crids)],
525+
)
500526

501527
async def merge_revocation_registry_deltas(
502528
self, fro_delta: str, to_delta: str
@@ -567,7 +593,7 @@ async def create_and_store_revocation_registry(
567593
rev_reg_def,
568594
rev_reg_def_private,
569595
rev_reg,
570-
rev_reg_delta,
596+
_rev_reg_delta,
571597
) = await asyncio.get_event_loop().run_in_executor(
572598
None,
573599
lambda: RevocationRegistryDefinition.create(

aries_cloudagent/indy/issuer.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from typing import Sequence, Tuple
55

66
from ..core.error import BaseError
7-
from ..core.profile import ProfileSession
87

98

109
DEFAULT_CRED_DEF_TAG = "default"
@@ -150,7 +149,6 @@ async def revoke_credentials(
150149
revoc_reg_id: str,
151150
tails_file_path: str,
152151
cred_rev_ids: Sequence[str],
153-
transaction: ProfileSession = None,
154152
) -> Tuple[str, Sequence[str]]:
155153
"""
156154
Revoke a set of credentials in a revocation registry.

aries_cloudagent/indy/sdk/issuer.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import indy.blob_storage
99
from indy.error import AnoncredsRevocationRegistryFullError, IndyError, ErrorCode
1010

11-
from ...core.profile import ProfileSession
1211
from ...indy.sdk.profile import IndySdkProfile
1312
from ...messaging.util import encode
1413
from ...revocation.models.issuer_cred_rev_record import IssuerCredRevRecord
@@ -267,7 +266,6 @@ async def revoke_credentials(
267266
rev_reg_id: str,
268267
tails_file_path: str,
269268
cred_rev_ids: Sequence[str],
270-
transaction: ProfileSession = None,
271269
) -> Tuple[str, Sequence[str]]:
272270
"""
273271
Revoke a set of credentials in a revocation registry.
@@ -281,7 +279,7 @@ async def revoke_credentials(
281279
Tuple with the combined revocation delta, list of cred rev ids not revoked
282280
283281
"""
284-
failed_crids = []
282+
failed_crids = set()
285283
tails_reader_handle = await create_tails_reader(tails_file_path)
286284

287285
result_json = None
@@ -290,22 +288,12 @@ async def revoke_credentials(
290288
"Exception when revoking credential", IndyIssuerError
291289
):
292290
try:
293-
session = await self.profile.session()
294291
delta_json = await indy.anoncreds.issuer_revoke_credential(
295292
self.profile.wallet.handle,
296293
tails_reader_handle,
297294
rev_reg_id,
298295
cred_rev_id,
299296
)
300-
issuer_cr_rec = await IssuerCredRevRecord.retrieve_by_ids(
301-
session,
302-
rev_reg_id,
303-
cred_rev_id,
304-
)
305-
await issuer_cr_rec.set_state(
306-
session, IssuerCredRevRecord.STATE_REVOKED
307-
)
308-
309297
except IndyError as err:
310298
if err.error_code == ErrorCode.AnoncredsInvalidUserRevocId:
311299
LOGGER.error(
@@ -323,7 +311,7 @@ async def revoke_credentials(
323311
err, "Revocation error", IndyIssuerError
324312
).roll_up
325313
)
326-
failed_crids.append(cred_rev_id)
314+
failed_crids.add(int(cred_rev_id))
327315
continue
328316
except StorageError as err:
329317
LOGGER.warning(
@@ -344,7 +332,7 @@ async def revoke_credentials(
344332
else:
345333
result_json = delta_json
346334

347-
return (result_json, failed_crids)
335+
return (result_json, [str(rev_id) for rev_id in sorted(failed_crids)])
348336

349337
async def merge_revocation_registry_deltas(
350338
self, fro_delta: str, to_delta: str

0 commit comments

Comments
 (0)