Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 67 additions & 6 deletions acapy_agent/anoncreds/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,73 @@
from ..core.event_bus import Event
from .models.revocation import RevRegDef

SCHEMA_FINISHED_EVENT = "anoncreds::schema::finished"
CRED_DEF_FINISHED_EVENT = "anoncreds::credential-definition::finished"
REV_REG_DEF_FINISHED_EVENT = "anoncreds::revocation-registry-definition::finished"
REV_LIST_FINISHED_EVENT = "anoncreds::revocation-list::finished"

SCHEMA_FINISHED_PATTERN = re.compile(SCHEMA_FINISHED_EVENT)
CRED_DEF_FINISHED_PATTERN = re.compile(CRED_DEF_FINISHED_EVENT)
REV_REG_DEF_FINISHED_PATTERN = re.compile(REV_REG_DEF_FINISHED_EVENT)
REV_LIST_FINISHED_PATTERN = re.compile(REV_LIST_FINISHED_EVENT)


class SchemaFinishedPayload(NamedTuple):
"""Payload of schema finished event."""

schema_id: str
issuer_id: str
name: str
version: str
attr_names: list
options: dict


class SchemaFinishedEvent(Event):
"""Event for schema finished."""

event_topic = SCHEMA_FINISHED_EVENT

def __init__(
self,
payload: SchemaFinishedPayload,
):
"""Initialize an instance.

Args:
payload: SchemaFinishedPayload

"""
self._topic = self.event_topic
self._payload = payload

@classmethod
def with_payload(
cls,
schema_id: str,
issuer_id: str,
name: str,
version: str,
attr_names: list,
options: Optional[dict] = None,
):
"""With payload."""
payload = SchemaFinishedPayload(
schema_id=schema_id,
issuer_id=issuer_id,
name=name,
version=version,
attr_names=attr_names,
options=options or {},
)
return cls(payload)

@property
def payload(self) -> SchemaFinishedPayload:
"""Return payload."""
return self._payload


class CredDefFinishedPayload(NamedTuple):
"""Payload of cred def finished event."""

Expand All @@ -23,6 +81,7 @@ class CredDefFinishedPayload(NamedTuple):
issuer_id: str
support_revocation: bool
max_cred_num: int
tag: str
options: dict


Expand All @@ -49,16 +108,18 @@ def with_payload(
issuer_id: str,
support_revocation: bool,
max_cred_num: int,
tag: str,
options: Optional[dict] = None,
):
"""With payload."""
payload = CredDefFinishedPayload(
schema_id=schema_id,
cred_def_id=cred_def_id,
issuer_id=issuer_id,
support_revocation=support_revocation,
max_cred_num=max_cred_num,
options=options,
schema_id,
cred_def_id,
issuer_id,
support_revocation,
max_cred_num,
tag,
options,
)
return cls(payload)

Expand Down
25 changes: 22 additions & 3 deletions acapy_agent/anoncreds/issuer.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from ..protocols.endorse_transaction.v1_0.util import is_author_role
from .base import AnonCredsSchemaAlreadyExists, BaseAnonCredsError
from .error_messages import ANONCREDS_PROFILE_REQUIRED_MSG
from .events import CredDefFinishedEvent
from .events import CredDefFinishedEvent, SchemaFinishedEvent
from .models.credential_definition import CredDef, CredDefResult
from .models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult, SchemaState
from .registry import AnonCredsRegistry
Expand Down Expand Up @@ -237,9 +237,23 @@ async def create_and_register_schema(
async def finish_schema(self, job_id: str, schema_id: str) -> None:
"""Mark a schema as finished."""
async with self.profile.transaction() as txn:
await self._finish_registration(txn, CATEGORY_SCHEMA, job_id, schema_id)
entry = await self._finish_registration(
txn, CATEGORY_SCHEMA, job_id, schema_id
)
await txn.commit()

schema = AnonCredsSchema.from_json(entry.value)
await self.notify(
SchemaFinishedEvent.with_payload(
schema_id=schema_id,
issuer_id=schema.issuer_id,
name=schema.name,
version=schema.version,
attr_names=schema.attr_names,
options={},
)
)

async def get_created_schemas(
self,
name: Optional[str] = None,
Expand Down Expand Up @@ -428,13 +442,17 @@ async def store_credential_definition(
)
await txn.commit()
if cred_def_result.credential_definition_state.state == STATE_FINISHED:
cred_def = (
cred_def_result.credential_definition_state.credential_definition
)
await self.notify(
CredDefFinishedEvent.with_payload(
schema_id=schema_result.schema_id,
cred_def_id=identifier,
issuer_id=cred_def_result.credential_definition_state.credential_definition.issuer_id,
issuer_id=cred_def.issuer_id,
support_revocation=support_revocation,
max_cred_num=max_cred_num,
tag=cred_def.tag,
options=options,
)
)
Expand Down Expand Up @@ -468,6 +486,7 @@ async def finish_cred_def(
issuer_id=cred_def.issuer_id,
support_revocation=support_revocation,
max_cred_num=max_cred_num,
tag=cred_def.tag,
options=options,
)
)
Expand Down
45 changes: 39 additions & 6 deletions acapy_agent/anoncreds/tests/test_issuer.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from ...tests import mock
from ...utils.testing import create_test_profile
from .. import issuer as test_module
from ..events import SchemaFinishedEvent


class MockSchemaEntry:
Expand Down Expand Up @@ -386,14 +387,46 @@ async def test_create_and_register_schema_with_endorsed_transaction_response_doe
assert isinstance(result, SchemaResult)
assert mock_store_schema.called

async def test_finish_schema(self):
self.profile.transaction = mock.Mock(
return_value=mock.MagicMock(
commit=mock.CoroutineMock(return_value=None),
)
)
@mock.patch.object(test_module.AnonCredsIssuer, "notify")
async def test_finish_schema(self, mock_notify):
# Create a mock entry with a valid schema JSON value
mock_entry = mock.MagicMock()
mock_entry.value = json.dumps(
{
"issuerId": "issuer-id",
"name": "test-schema",
"version": "1.0",
"attrNames": ["attr1", "attr2"],
}
)
mock_entry.tags = {}

# Mock the transaction context manager
mock_txn = mock.MagicMock()
mock_handle = mock.MagicMock()
mock_handle.fetch = mock.CoroutineMock(return_value=mock_entry)
mock_handle.insert = mock.CoroutineMock(return_value=None)
mock_handle.remove = mock.CoroutineMock(return_value=None)
mock_txn.handle = mock_handle
mock_txn.commit = mock.CoroutineMock(return_value=None)
mock_txn.__aenter__ = mock.CoroutineMock(return_value=mock_txn)
mock_txn.__aexit__ = mock.CoroutineMock(return_value=None)

self.profile.transaction = mock.Mock(return_value=mock_txn)

await self.issuer.finish_schema(job_id="job-id", schema_id="schema-id")

# Verify that SchemaFinishedEvent was emitted
mock_notify.assert_called_once()
call_args = mock_notify.call_args
assert isinstance(call_args[0][0], SchemaFinishedEvent)
event = call_args[0][0]
assert event.payload.schema_id == "schema-id"
assert event.payload.issuer_id == "issuer-id"
assert event.payload.name == "test-schema"
assert event.payload.version == "1.0"
assert event.payload.attr_names == ["attr1", "attr2"]

@mock.patch.object(AskarAnonCredsProfileSession, "handle")
async def test_get_created_schemas(self, mock_session_handle):
mock_session_handle.fetch_all = mock.CoroutineMock(
Expand Down
2 changes: 2 additions & 0 deletions acapy_agent/anoncreds/tests/test_revocation_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ async def test_on_cred_def_support_revocation_registers_revocation_def(
issuer_id="issuer_id",
support_revocation=True,
max_cred_num=100,
tag="default",
options={},
)
)
Expand All @@ -63,6 +64,7 @@ async def test_on_cred_def_not_support_rev_option(
issuer_id="issuer_id",
support_revocation=False,
max_cred_num=100,
tag="default",
options={},
)
)
Expand Down
26 changes: 14 additions & 12 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ python-json-logger = "^3.2.1"
pyyaml = "~6.0.2"
qrcode = { version = "^8.1", extras = ["pil"] }
requests = "~2.32.3"
urllib3 = ">=2.6.0,<3"
rlp = "^4.1.0"
sd-jwt = "^0.10.3"
unflatten = "~0.2"
Expand All @@ -53,7 +54,7 @@ did-peer-4 = "^0.1.4"
did-webvh = ">=1.0.0"

# Verifiable Credentials
anoncreds = "~0.2.0"
anoncreds = "~0.2.3"
indy-credx = "~1.1.1"

# askar
Expand Down