|
1 | 1 | """Issuer revocation registry storage handling.""" |
2 | 2 |
|
3 | | -import json |
4 | 3 | import importlib |
| 4 | +import json |
5 | 5 | import logging |
6 | 6 | import uuid |
7 | 7 | from functools import total_ordering |
|
16 | 16 | from ...core.profile import Profile, ProfileSession |
17 | 17 | from ...indy.credx.issuer import ( |
18 | 18 | CATEGORY_CRED_DEF, |
| 19 | + CATEGORY_REV_REG, |
19 | 20 | CATEGORY_REV_REG_DEF_PRIVATE, |
20 | 21 | ) |
21 | 22 | from ...indy.issuer import IndyIssuer, IndyIssuerError |
@@ -361,95 +362,108 @@ async def send_entry( |
361 | 362 |
|
362 | 363 | return rev_entry_res |
363 | 364 |
|
| 365 | + def _get_revoked_discrepancies( |
| 366 | + self, recs: Sequence[IssuerCredRevRecord], rev_reg_delta: dict |
| 367 | + ) -> Tuple[list, int]: |
| 368 | + revoked_ids = [] |
| 369 | + rec_count = 0 |
| 370 | + for rec in recs: |
| 371 | + if rec.state == IssuerCredRevRecord.STATE_REVOKED: |
| 372 | + revoked_ids.append(int(rec.cred_rev_id)) |
| 373 | + if int(rec.cred_rev_id) not in rev_reg_delta["value"]["revoked"]: |
| 374 | + rec_count += 1 |
| 375 | + |
| 376 | + return revoked_ids, rec_count |
| 377 | + |
364 | 378 | async def fix_ledger_entry( |
365 | 379 | self, |
366 | 380 | profile: Profile, |
367 | 381 | apply_ledger_update: bool, |
368 | 382 | genesis_transactions: str, |
369 | 383 | ) -> Tuple[dict, dict, dict]: |
370 | 384 | """Fix the ledger entry to match wallet-recorded credentials.""" |
| 385 | + recovery_txn = {} |
| 386 | + applied_txn = {} |
| 387 | + |
371 | 388 | # get rev reg delta (revocations published to ledger) |
372 | 389 | ledger = profile.inject(BaseLedger) |
373 | 390 | async with ledger: |
374 | 391 | (rev_reg_delta, _) = await ledger.get_revoc_reg_delta(self.revoc_reg_id) |
375 | 392 |
|
376 | 393 | # get rev reg records from wallet (revocations and status) |
377 | | - recs = [] |
378 | | - rec_count = 0 |
379 | | - accum_count = 0 |
380 | | - recovery_txn = {} |
381 | | - applied_txn = {} |
382 | 394 | async with profile.session() as session: |
383 | 395 | recs = await IssuerCredRevRecord.query_by_ids( |
384 | 396 | session, rev_reg_id=self.revoc_reg_id |
385 | 397 | ) |
386 | 398 |
|
387 | | - revoked_ids = [] |
388 | | - for rec in recs: |
389 | | - if rec.state == IssuerCredRevRecord.STATE_REVOKED: |
390 | | - revoked_ids.append(int(rec.cred_rev_id)) |
391 | | - if int(rec.cred_rev_id) not in rev_reg_delta["value"]["revoked"]: |
392 | | - # await rec.set_state(session, IssuerCredRevRecord.STATE_ISSUED) |
393 | | - rec_count += 1 |
| 399 | + revoked_ids, rec_count = self._get_revoked_discrepancies(recs, rev_reg_delta) |
| 400 | + |
| 401 | + LOGGER.debug(f"Fixed entry recs count = {rec_count}") |
| 402 | + LOGGER.debug(f"Rev reg entry value: {self.revoc_reg_entry.value}") |
| 403 | + LOGGER.debug(f"Rev reg delta: {rev_reg_delta.get('value')}") |
| 404 | + |
| 405 | + # No update required if no discrepancies |
| 406 | + if rec_count == 0: |
| 407 | + return (rev_reg_delta, {}, {}) |
394 | 408 |
|
395 | | - LOGGER.debug(">>> fixed entry recs count = %s", rec_count) |
396 | | - LOGGER.debug( |
397 | | - ">>> rev_reg_record.revoc_reg_entry.value: %s", |
398 | | - self.revoc_reg_entry.value, |
| 409 | + # We have revocation discrepancies, generate the recovery txn |
| 410 | + async with profile.session() as session: |
| 411 | + # We need the cred_def and rev_reg_def_private to generate the recovery txn |
| 412 | + issuer_rev_reg_record = await IssuerRevRegRecord.retrieve_by_revoc_reg_id( |
| 413 | + session, self.revoc_reg_id |
| 414 | + ) |
| 415 | + cred_def_id = issuer_rev_reg_record.cred_def_id |
| 416 | + cred_def = await session.handle.fetch(CATEGORY_CRED_DEF, cred_def_id) |
| 417 | + rev_reg_def_private = await session.handle.fetch( |
| 418 | + CATEGORY_REV_REG_DEF_PRIVATE, self.revoc_reg_id |
| 419 | + ) |
| 420 | + |
| 421 | + credx_module = importlib.import_module("indy_credx") |
| 422 | + cred_defn = credx_module.CredentialDefinition.load(cred_def.value_json) |
| 423 | + rev_reg_defn_private = credx_module.RevocationRegistryDefinitionPrivate.load( |
| 424 | + rev_reg_def_private.value_json |
399 | 425 | ) |
400 | | - LOGGER.debug('>>> rev_reg_delta.get("value"): %s', rev_reg_delta.get("value")) |
401 | | - |
402 | | - # if we had any revocation discrepancies, check the accumulator value |
403 | | - if rec_count > 0: |
404 | | - if (self.revoc_reg_entry.value and rev_reg_delta.get("value")) and not ( |
405 | | - self.revoc_reg_entry.value.accum == rev_reg_delta["value"]["accum"] |
406 | | - ): |
407 | | - # self.revoc_reg_entry = rev_reg_delta["value"] |
408 | | - # await self.save(session) |
409 | | - accum_count += 1 |
| 426 | + calculated_txn = await generate_ledger_rrrecovery_txn( |
| 427 | + genesis_transactions, |
| 428 | + self.revoc_reg_id, |
| 429 | + revoked_ids, |
| 430 | + cred_defn, |
| 431 | + rev_reg_defn_private, |
| 432 | + ) |
| 433 | + recovery_txn = json.loads(calculated_txn.to_json()) |
| 434 | + |
| 435 | + LOGGER.debug(f"Applying ledger update: {apply_ledger_update}") |
| 436 | + if apply_ledger_update: |
410 | 437 | async with profile.session() as session: |
411 | | - issuer_rev_reg_record = ( |
412 | | - await IssuerRevRegRecord.retrieve_by_revoc_reg_id( |
413 | | - session, self.revoc_reg_id |
| 438 | + ledger = session.inject_or(BaseLedger) |
| 439 | + if not ledger: |
| 440 | + reason = "No ledger available" |
| 441 | + if not session.context.settings.get_value("wallet.type"): |
| 442 | + reason += ": missing wallet-type?" |
| 443 | + raise LedgerError(reason=reason) |
| 444 | + |
| 445 | + async with ledger: |
| 446 | + ledger_response = await ledger.send_revoc_reg_entry( |
| 447 | + self.revoc_reg_id, "CL_ACCUM", recovery_txn |
414 | 448 | ) |
| 449 | + |
| 450 | + applied_txn = ledger_response["result"] |
| 451 | + |
| 452 | + # Update the local wallets rev reg entry with the new accumulator value |
| 453 | + async with profile.session() as session: |
| 454 | + rev_reg = await session.handle.fetch( |
| 455 | + CATEGORY_REV_REG, self.revoc_reg_id, for_update=True |
415 | 456 | ) |
416 | | - cred_def_id = issuer_rev_reg_record.cred_def_id |
417 | | - _cred_def = await session.handle.fetch(CATEGORY_CRED_DEF, cred_def_id) |
418 | | - _rev_reg_def_private = await session.handle.fetch( |
419 | | - CATEGORY_REV_REG_DEF_PRIVATE, self.revoc_reg_id |
420 | | - ) |
421 | | - credx_module = importlib.import_module("indy_credx") |
422 | | - cred_defn = credx_module.CredentialDefinition.load(_cred_def.value_json) |
423 | | - rev_reg_defn_private = ( |
424 | | - credx_module.RevocationRegistryDefinitionPrivate.load( |
425 | | - _rev_reg_def_private.value_json |
| 457 | + new_value_json = rev_reg.value_json |
| 458 | + new_value_json["value"]["accum"] = applied_txn["txn"]["data"]["value"][ |
| 459 | + "accum" |
| 460 | + ] |
| 461 | + await session.handle.replace( |
| 462 | + CATEGORY_REV_REG, |
| 463 | + rev_reg.name, |
| 464 | + json.dumps(new_value_json), |
| 465 | + rev_reg.tags, |
426 | 466 | ) |
427 | | - ) |
428 | | - calculated_txn = await generate_ledger_rrrecovery_txn( |
429 | | - genesis_transactions, |
430 | | - self.revoc_reg_id, |
431 | | - revoked_ids, |
432 | | - cred_defn, |
433 | | - rev_reg_defn_private, |
434 | | - ) |
435 | | - recovery_txn = json.loads(calculated_txn.to_json()) |
436 | | - |
437 | | - LOGGER.debug(">>> apply_ledger_update = %s", apply_ledger_update) |
438 | | - if apply_ledger_update: |
439 | | - async with profile.session() as session: |
440 | | - ledger = session.inject_or(BaseLedger) |
441 | | - if not ledger: |
442 | | - reason = "No ledger available" |
443 | | - if not session.context.settings.get_value("wallet.type"): |
444 | | - reason += ": missing wallet-type?" |
445 | | - raise LedgerError(reason=reason) |
446 | | - |
447 | | - async with ledger: |
448 | | - ledger_response = await ledger.send_revoc_reg_entry( |
449 | | - self.revoc_reg_id, "CL_ACCUM", recovery_txn |
450 | | - ) |
451 | | - |
452 | | - applied_txn = ledger_response["result"] |
453 | 467 |
|
454 | 468 | return (rev_reg_delta, recovery_txn, applied_txn) |
455 | 469 |
|
|
0 commit comments