Skip to content

Commit 300290d

Browse files
authored
0.12.lts Patch the fix_ledger_entry improvements (openwallet-foundation#3558)
* Patch the fix_ledger_entry improvements Signed-off-by: jamshale <jamiehalebc@gmail.com> * Repair unit test for update local wallet Signed-off-by: jamshale <jamiehalebc@gmail.com> --------- Signed-off-by: jamshale <jamiehalebc@gmail.com>
1 parent 9d99961 commit 300290d

2 files changed

Lines changed: 113 additions & 70 deletions

File tree

aries_cloudagent/revocation/models/issuer_rev_reg_record.py

Lines changed: 80 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Issuer revocation registry storage handling."""
22

3-
import json
43
import importlib
4+
import json
55
import logging
66
import uuid
77
from functools import total_ordering
@@ -16,6 +16,7 @@
1616
from ...core.profile import Profile, ProfileSession
1717
from ...indy.credx.issuer import (
1818
CATEGORY_CRED_DEF,
19+
CATEGORY_REV_REG,
1920
CATEGORY_REV_REG_DEF_PRIVATE,
2021
)
2122
from ...indy.issuer import IndyIssuer, IndyIssuerError
@@ -361,95 +362,108 @@ async def send_entry(
361362

362363
return rev_entry_res
363364

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+
364378
async def fix_ledger_entry(
365379
self,
366380
profile: Profile,
367381
apply_ledger_update: bool,
368382
genesis_transactions: str,
369383
) -> Tuple[dict, dict, dict]:
370384
"""Fix the ledger entry to match wallet-recorded credentials."""
385+
recovery_txn = {}
386+
applied_txn = {}
387+
371388
# get rev reg delta (revocations published to ledger)
372389
ledger = profile.inject(BaseLedger)
373390
async with ledger:
374391
(rev_reg_delta, _) = await ledger.get_revoc_reg_delta(self.revoc_reg_id)
375392

376393
# 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 = {}
382394
async with profile.session() as session:
383395
recs = await IssuerCredRevRecord.query_by_ids(
384396
session, rev_reg_id=self.revoc_reg_id
385397
)
386398

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, {}, {})
394408

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
399425
)
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:
410437
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
414448
)
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
415456
)
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,
426466
)
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"]
453467

454468
return (rev_reg_delta, recovery_txn, applied_txn)
455469

aries_cloudagent/revocation/models/tests/test_issuer_rev_reg_record.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,15 @@
77
from aries_cloudagent.tests import mock
88
from unittest import IsolatedAsyncioTestCase
99

10+
from ....askar.profile import AskarProfileSession
1011
from ....core.in_memory import InMemoryProfile, InMemoryProfileSession
1112
from ....core.profile import Profile, ProfileSession
1213
from ....config.injection_context import InjectionContext
1314
from ....indy.issuer import IndyIssuer, IndyIssuerError
1415
from ....indy.util import indy_client_dir
1516
from ....ledger.base import BaseLedger
1617
from ....tails.base import BaseTailsServer
17-
1818
from ...error import RevocationError
19-
2019
from .. import issuer_rev_reg_record as test_module
2120
from ..issuer_rev_reg_record import IssuerRevRegRecord
2221
from ..revocation_registry import RevocationRegistry
@@ -83,6 +82,10 @@ async def test_order(self):
8382
await rec1.save(session, reason="another record")
8483
assert rec0 < rec1
8584

85+
@mock.patch(
86+
"aries_cloudagent.core.tests.test_profile.TestProfileSession",
87+
mock.MagicMock(AskarProfileSession, autospec=True),
88+
)
8689
async def test_fix_ledger_entry(self):
8790
mock_cred_def = {
8891
"ver": "1.0",
@@ -188,6 +191,16 @@ def handle(self):
188191
)
189192
)
190193

194+
TestProfileSession.handle = mock.MagicMock(
195+
fetch=mock.CoroutineMock(
196+
side_effect=[
197+
mock.MagicMock(value_json=json.dumps(mock_cred_def)),
198+
mock.MagicMock(value_json=json.dumps(mock_reg_rev_def_private)),
199+
mock.MagicMock(value_json=REV_REG_DEF),
200+
]
201+
),
202+
replace=mock.CoroutineMock(),
203+
)
191204
credx_module = importlib.import_module("indy_credx")
192205
rev_reg_delta_json = json.dumps(
193206
{
@@ -226,7 +239,15 @@ def handle(self):
226239
)
227240
self.ledger.send_revoc_reg_entry = mock.CoroutineMock(
228241
return_value={
229-
"result": {"...": "..."},
242+
"result": {
243+
"txn": {
244+
"data": {
245+
"value": {
246+
"accum": "1 0792BD1C8C1A529173FDF54A5B30AC90C2472956622E9F04971D36A9BF77C2C5 1 13B18B6B68AD62605C74FD61088814338EDEEB41C2195F96EC0E83B2B3D0258F 1 102ED0DDE96F6367199CE1C0B138F172BC913B65E37250581606974034F4CA20 1 1C53786D2C15190B57167CDDD2A046CAD63970B5DE43F4D492D4F46B8EEE6FF1 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000"
247+
}
248+
}
249+
}
250+
},
230251
},
231252
)
232253
_test_session = TestProfile.test_session(
@@ -265,7 +286,15 @@ def handle(self):
265286
"accum": "1 0792BD1C8C1A529173FDF54A5B30AC90C2472956622E9F04971D36A9BF77C2C5 1 13B18B6B68AD62605C74FD61088814338EDEEB41C2195F96EC0E83B2B3D0258F 1 102ED0DDE96F6367199CE1C0B138F172BC913B65E37250581606974034F4CA20 1 1C53786D2C15190B57167CDDD2A046CAD63970B5DE43F4D492D4F46B8EEE6FF1 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000"
266287
},
267288
},
268-
{"...": "..."},
289+
{
290+
"txn": {
291+
"data": {
292+
"value": {
293+
"accum": "1 0792BD1C8C1A529173FDF54A5B30AC90C2472956622E9F04971D36A9BF77C2C5 1 13B18B6B68AD62605C74FD61088814338EDEEB41C2195F96EC0E83B2B3D0258F 1 102ED0DDE96F6367199CE1C0B138F172BC913B65E37250581606974034F4CA20 1 1C53786D2C15190B57167CDDD2A046CAD63970B5DE43F4D492D4F46B8EEE6FF1 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000"
294+
},
295+
}
296+
}
297+
},
269298
) == await rec.fix_ledger_entry(
270299
profile=_test_profile,
271300
apply_ledger_update=True,

0 commit comments

Comments
 (0)