Skip to content

Commit 7097f15

Browse files
authored
Merge branch 'main' into fix/askar-anoncreds-multi-ledger
2 parents 7f134e7 + 8257ff8 commit 7097f15

File tree

6 files changed

+209
-82
lines changed

6 files changed

+209
-82
lines changed

acapy_agent/anoncreds/events.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@ def with_payload(
5353
):
5454
"""With payload."""
5555
payload = CredDefFinishedPayload(
56-
schema_id, cred_def_id, issuer_id, support_revocation, max_cred_num, options
56+
schema_id=schema_id,
57+
cred_def_id=cred_def_id,
58+
issuer_id=issuer_id,
59+
support_revocation=support_revocation,
60+
max_cred_num=max_cred_num,
61+
options=options,
5762
)
5863
return cls(payload)
5964

acapy_agent/anoncreds/issuer.py

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from ..core.error import BaseError
2222
from ..core.event_bus import Event, EventBus
2323
from ..core.profile import Profile
24+
from ..protocols.endorse_transaction.v1_0.util import is_author_role
2425
from .base import AnonCredsSchemaAlreadyExists, BaseAnonCredsError
2526
from .error_messages import ANONCREDS_PROFILE_REQUIRED_MSG
2627
from .events import CredDefFinishedEvent
@@ -306,9 +307,22 @@ async def create_and_register_credential_definition(
306307
307308
"""
308309
options = options or {}
309-
support_revocation = options.get("support_revocation", False)
310-
if not isinstance(support_revocation, bool):
311-
raise ValueError("support_revocation must be a boolean")
310+
support_revocation_option = options.get("support_revocation")
311+
312+
if support_revocation_option is None:
313+
# Support revocation not set - Default to auto-create rev reg if author role
314+
is_author = is_author_role(self.profile)
315+
auto_create_rev_reg = self.profile.settings.get(
316+
"endorser.auto_create_rev_reg", False
317+
)
318+
319+
support_revocation = bool(is_author and auto_create_rev_reg)
320+
else:
321+
# If support_revocation is explicitly set, use that value
322+
if not isinstance(support_revocation_option, bool):
323+
raise ValueError("support_revocation must be a boolean")
324+
325+
support_revocation = support_revocation_option
312326

313327
max_cred_num = options.get("revocation_registry_size", DEFAULT_MAX_CRED_NUM)
314328
if not isinstance(max_cred_num, int):
@@ -317,7 +331,8 @@ async def create_and_register_credential_definition(
317331
# Don't allow revocable cred def to be created without tails server base url
318332
if not self.profile.settings.get("tails_server_base_url") and support_revocation:
319333
raise AnonCredsIssuerError(
320-
"tails_server_base_url not configured. Can't create revocable credential definition." # noqa: E501
334+
"tails_server_base_url not configured. "
335+
"Can't create revocable credential definition."
321336
)
322337

323338
anoncreds_registry = self.profile.inject(AnonCredsRegistry)
@@ -331,31 +346,31 @@ async def create_and_register_credential_definition(
331346
) = await asyncio.get_event_loop().run_in_executor(
332347
None,
333348
lambda: CredentialDefinition.create(
334-
schema_id,
335-
schema_result.schema.serialize(),
336-
issuer_id,
337-
tag or DEFAULT_CRED_DEF_TAG,
338-
signature_type or DEFAULT_SIGNATURE_TYPE,
349+
schema_id=schema_id,
350+
schema=schema_result.schema.serialize(),
351+
issuer_id=issuer_id,
352+
tag=tag or DEFAULT_CRED_DEF_TAG,
353+
signature_type=signature_type or DEFAULT_SIGNATURE_TYPE,
339354
support_revocation=support_revocation,
340355
),
341356
)
342357

343358
try:
344359
cred_def_result = await anoncreds_registry.register_credential_definition(
345-
self.profile,
346-
schema_result,
347-
CredDef.from_native(cred_def),
348-
options,
360+
profile=self.profile,
361+
schema=schema_result,
362+
credential_definition=CredDef.from_native(cred_def),
363+
options=options,
349364
)
350365

351366
await self.store_credential_definition(
352-
schema_result,
353-
cred_def_result,
354-
cred_def_private,
355-
key_proof,
356-
support_revocation,
357-
max_cred_num,
358-
options,
367+
schema_result=schema_result,
368+
cred_def_result=cred_def_result,
369+
cred_def_private=cred_def_private,
370+
key_proof=key_proof,
371+
support_revocation=support_revocation,
372+
max_cred_num=max_cred_num,
373+
options=options,
359374
)
360375

361376
return cred_def_result
@@ -415,12 +430,12 @@ async def store_credential_definition(
415430
if cred_def_result.credential_definition_state.state == STATE_FINISHED:
416431
await self.notify(
417432
CredDefFinishedEvent.with_payload(
418-
schema_result.schema_id,
419-
identifier,
420-
cred_def_result.credential_definition_state.credential_definition.issuer_id,
421-
support_revocation,
422-
max_cred_num,
423-
options,
433+
schema_id=schema_result.schema_id,
434+
cred_def_id=identifier,
435+
issuer_id=cred_def_result.credential_definition_state.credential_definition.issuer_id,
436+
support_revocation=support_revocation,
437+
max_cred_num=max_cred_num,
438+
options=options,
424439
)
425440
)
426441
except AskarError as err:

acapy_agent/anoncreds/revocation_setup.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,8 @@ def register_events(self, event_bus: EventBus):
6767
async def on_cred_def(self, profile: Profile, event: CredDefFinishedEvent):
6868
"""Handle cred def finished."""
6969
payload = event.payload
70-
auto_create_revocation = is_author_role(profile) and profile.settings.get(
71-
"endorser.auto_create_rev_reg", False
72-
)
7370

74-
if payload.support_revocation or auto_create_revocation:
71+
if payload.support_revocation:
7572
revoc = AnonCredsRevocation(profile)
7673
for registry_count in range(self.INITIAL_REGISTRY_COUNT):
7774
await revoc.create_and_register_revocation_registry_definition(

acapy_agent/anoncreds/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ async def schemas_post(request: web.BaseRequest):
187187
a null value.
188188
schema : The schema. If the value of the schema_state.state response field
189189
is finished, this field MUST be present and MUST NOT have a null value.
190-
registration_metadata : This field contains metadata about hte registration
190+
registration_metadata : This field contains metadata about the registration
191191
process
192192
schema_metadata : This fields contains metadata about the schema.
193193

acapy_agent/anoncreds/tests/test_issuer.py

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,9 +462,167 @@ async def test_create_and_register_credential_definition_invalid_options_raises_
462462
issuer_id="issuer-id",
463463
schema_id="schema-id",
464464
signature_type="CL",
465-
options={"support_revocation": "100"}, # requires integer
465+
options={"revocation_registry_size": "100"}, # requires integer
466466
)
467467

468+
@mock.patch.object(CredDef, "from_native", return_value=MockCredDefEntry())
469+
@mock.patch(
470+
"anoncreds.CredentialDefinition.create",
471+
return_value=(mock.MagicMock(), mock.MagicMock(), mock.MagicMock()),
472+
)
473+
async def test_create_and_register_credential_definition_support_revocation_conditions(
474+
self, mock_cred_def_create, _
475+
):
476+
schema_result = GetSchemaResult(
477+
schema_id="schema-id",
478+
schema=AnonCredsSchema(
479+
issuer_id="issuer-id",
480+
name="schema-name",
481+
version="1.0",
482+
attr_names=["attr1", "attr2"],
483+
),
484+
schema_metadata={},
485+
resolution_metadata={},
486+
)
487+
488+
cred_def_result = CredDefResult(
489+
job_id="job-id",
490+
credential_definition_state=CredDefState(
491+
state="finished",
492+
credential_definition=CredDef(
493+
issuer_id="did:sov:3avoBCqDMFHFaKUHug9s8W",
494+
schema_id="schema-id",
495+
tag="tag",
496+
type="CL",
497+
value=CredDefValue(
498+
primary=CredDefValuePrimary("n", "s", {}, "rctxt", "z")
499+
),
500+
),
501+
credential_definition_id="cred-def-id",
502+
),
503+
credential_definition_metadata={},
504+
registration_metadata={},
505+
)
506+
507+
self.profile.inject = mock.Mock(
508+
return_value=mock.MagicMock(
509+
get_schema=mock.CoroutineMock(return_value=schema_result),
510+
register_credential_definition=mock.CoroutineMock(
511+
return_value=cred_def_result
512+
),
513+
)
514+
)
515+
516+
# Configure author role and auto create rev reg -- expectation: support revocation is True when not specified
517+
self.profile.settings.set_value("endorser.author", True)
518+
self.profile.settings.set_value("endorser.auto_create_rev_reg", True)
519+
520+
# First assert AnonCredsIssuerError if tails_server_base_url is not set
521+
with self.assertRaises(test_module.AnonCredsIssuerError) as exc:
522+
await self.issuer.create_and_register_credential_definition(
523+
issuer_id="issuer-id",
524+
schema_id="schema-id",
525+
signature_type="CL",
526+
tag="tag",
527+
)
528+
assert (
529+
str(exc.exception.message)
530+
== "tails_server_base_url not configured. Can't create revocable credential definition."
531+
)
532+
533+
# Now, set the tails_server_base_url
534+
self.profile.settings.set_value("tails_server_base_url", "https://example.com")
535+
536+
for support_revocation in [True, False, None]:
537+
# Mock the store_credential_definition method
538+
with mock.patch.object(
539+
self.issuer, "store_credential_definition"
540+
) as mock_store_cred_def:
541+
# Reset the mocks for each iteration
542+
mock_cred_def_create.reset_mock()
543+
mock_store_cred_def.reset_mock()
544+
545+
await self.issuer.create_and_register_credential_definition(
546+
issuer_id="issuer-id",
547+
schema_id="schema-id",
548+
signature_type="CL",
549+
tag="tag",
550+
options={"support_revocation": support_revocation},
551+
)
552+
553+
# Check if support_revocation is True when None or True was passed
554+
expected_support_revocation = (
555+
support_revocation if support_revocation is not None else True
556+
)
557+
558+
# Assert CredentialDefinition.create call was made with correct support_revocation value
559+
mock_cred_def_create.assert_called_once_with(
560+
schema_id="schema-id",
561+
schema=schema_result.schema.serialize(),
562+
issuer_id="issuer-id",
563+
tag="tag",
564+
signature_type="CL",
565+
support_revocation=expected_support_revocation,
566+
)
567+
568+
# Assert store_credential_definition call args
569+
mock_store_cred_def.assert_called_once_with(
570+
schema_result=schema_result,
571+
cred_def_result=mock.ANY,
572+
cred_def_private=mock.ANY,
573+
key_proof=mock.ANY,
574+
support_revocation=expected_support_revocation,
575+
max_cred_num=mock.ANY,
576+
options=mock.ANY,
577+
)
578+
579+
# Now, disable author role and auto create rev reg -- expectation: support revocation is False when not specified
580+
self.profile.settings.set_value("endorser.author", False)
581+
self.profile.settings.set_value("endorser.auto_create_rev_reg", False)
582+
583+
for support_revocation in [True, False, None]:
584+
# Mock the CredentialDefinition.create call, and the store_credential_definition method
585+
with mock.patch.object(
586+
self.issuer, "store_credential_definition"
587+
) as mock_store_cred_def:
588+
# Reset the mock for each iteration
589+
mock_cred_def_create.reset_mock()
590+
mock_store_cred_def.reset_mock()
591+
592+
await self.issuer.create_and_register_credential_definition(
593+
issuer_id="issuer-id",
594+
schema_id="schema-id",
595+
signature_type="CL",
596+
tag="tag",
597+
options={"support_revocation": support_revocation},
598+
)
599+
600+
# Check if support_revocation is False when set to None
601+
expected_support_revocation = (
602+
support_revocation if support_revocation is not None else False
603+
)
604+
605+
# Assert CredentialDefinition.create call was made with correct support_revocation value
606+
mock_cred_def_create.assert_called_once_with(
607+
schema_id="schema-id",
608+
schema=schema_result.schema.serialize(),
609+
issuer_id="issuer-id",
610+
tag="tag",
611+
signature_type="CL",
612+
support_revocation=expected_support_revocation,
613+
)
614+
615+
# Assert store_credential_definition call args
616+
mock_store_cred_def.assert_called_once_with(
617+
schema_result=schema_result,
618+
cred_def_result=mock.ANY,
619+
cred_def_private=mock.ANY,
620+
key_proof=mock.ANY,
621+
support_revocation=expected_support_revocation,
622+
max_cred_num=mock.ANY,
623+
options=mock.ANY,
624+
)
625+
468626
@mock.patch.object(test_module.AnonCredsIssuer, "notify")
469627
async def test_create_and_register_credential_definition_finishes(self, mock_notify):
470628
self.profile.inject = mock.Mock(

acapy_agent/anoncreds/tests/test_revocation_setup.py

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -53,55 +53,7 @@ async def test_on_cred_def_support_revocation_registers_revocation_def(
5353
"create_and_register_revocation_registry_definition",
5454
return_value=None,
5555
)
56-
async def test_on_cred_def_author_with_auto_create_rev_reg_config_registers_reg_def(
57-
self, mock_register_revocation_registry_definition
58-
):
59-
self.profile.settings["endorser.author"] = True
60-
self.profile.settings["endorser.auto_create_rev_reg"] = True
61-
event = CredDefFinishedEvent(
62-
CredDefFinishedPayload(
63-
schema_id="schema_id",
64-
cred_def_id="cred_def_id",
65-
issuer_id="issuer_id",
66-
support_revocation=False,
67-
max_cred_num=100,
68-
options={},
69-
)
70-
)
71-
await self.revocation_setup.on_cred_def(self.profile, event)
72-
73-
assert mock_register_revocation_registry_definition.called
74-
75-
@mock.patch.object(
76-
AnonCredsRevocation,
77-
"create_and_register_revocation_registry_definition",
78-
return_value=None,
79-
)
80-
async def test_on_cred_def_author_with_auto_create_rev_reg_config_and_support_revoc_option_registers_reg_def(
81-
self, mock_register_revocation_registry_definition
82-
):
83-
self.profile.settings["endorser.author"] = True
84-
self.profile.settings["endorser.auto_create_rev_reg"] = True
85-
event = CredDefFinishedEvent(
86-
CredDefFinishedPayload(
87-
schema_id="schema_id",
88-
cred_def_id="cred_def_id",
89-
issuer_id="issuer_id",
90-
support_revocation=True,
91-
max_cred_num=100,
92-
options={},
93-
)
94-
)
95-
await self.revocation_setup.on_cred_def(self.profile, event)
96-
97-
assert mock_register_revocation_registry_definition.called
98-
99-
@mock.patch.object(
100-
AnonCredsRevocation,
101-
"create_and_register_revocation_registry_definition",
102-
return_value=None,
103-
)
104-
async def test_on_cred_def_not_author_or_support_rev_option(
56+
async def test_on_cred_def_not_support_rev_option(
10557
self, mock_register_revocation_registry_definition
10658
):
10759
event = CredDefFinishedEvent(

0 commit comments

Comments
 (0)