Skip to content

Commit

Permalink
split into scenarios
Browse files Browse the repository at this point in the history
  • Loading branch information
rlve committed Nov 29, 2024
1 parent ebf67a6 commit cf12ae3
Show file tree
Hide file tree
Showing 3 changed files with 330 additions and 274 deletions.
1 change: 1 addition & 0 deletions scenarios/examples/cheqd/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
- HOLDER=http://holder:3001
volumes:
- ./example.py:/usr/src/app/example.py:ro,z
- ./helpers.py:/usr/src/app/helpers.py:ro,z
command: python -m example
depends_on:
issuer:
Expand Down
332 changes: 58 additions & 274 deletions scenarios/examples/cheqd/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,283 +4,91 @@
"""

import asyncio
import json
from dataclasses import dataclass
from os import getenv
from typing import Tuple, Mapping, Optional

from acapy_controller import Controller
from acapy_controller.logging import logging_to_stdout
from acapy_controller.protocols import didexchange
from acapy_controller.controller import Minimal
from helpers import (
assert_credential_definitions,
assert_wallet_dids,
create_credential_definition,
create_did,
create_schema,
deactivate_did,
issue_credential_v2,
resolve_did,
)

ISSUER = getenv("ISSUER", "http://issuer:3001")
HOLDER = getenv("HOLDER", "http://holder:3001")


@dataclass
class V20CredExRecord(Minimal):
"""V2.0 credential exchange record."""

state: str
cred_ex_id: str
connection_id: str
thread_id: str


@dataclass
class V20CredExRecordFormat(Minimal):
"""V2.0 credential exchange record anoncreds."""

rev_reg_id: Optional[str] = None
cred_rev_id: Optional[str] = None


@dataclass
class V20CredExRecordDetail(Minimal):
"""V2.0 credential exchange record detail."""

cred_ex_record: V20CredExRecord
details: Optional[V20CredExRecordFormat] = None


def format_json(json_to_format):
"""Pretty print json."""
return json.dumps(json_to_format, indent=4)
async def scenario1_create_and_resolve_did(issuer):
"""Perform a scenario involving DID creation and resolution.
This function demonstrates the creation of a DID using the provided issuer
controller, followed by resolving the created DID to retrieve its document.
"""
did = await create_did(issuer)

async def create_did(issuer):
"""Create a DID on the Cheqd testnet."""
did_create_result = await issuer.post("/did/cheqd/create")
did = did_create_result.get("did")
await resolve_did(issuer, did)

assert did, "DID creation failed."
assert did_create_result.get("verkey"), "Verkey is missing in DID creation result."
# updated_did_document = await update_did(issuer, did, did_document)

print(f"Created DID: {did}")
return did


async def resolve_did(issuer, did):
"""Resolve the DID document."""
resolution_result = await issuer.get(f"/resolver/resolve/{did}")
did_document = resolution_result.get("did_document")

assert did_document, "DID document resolution failed."
print(f"Resolved DID Document: {format_json(did_document)}")
return did_document


async def update_did(issuer, did, did_document):
"""Update the DID document by adding a service endpoint."""
service = [
{
"id": f"{did}#service-1",
"type": "MessagingService",
"serviceEndpoint": ["https://example.com/service"],
}
]
did_document["service"] = service
del did_document["@context"]

did_update_result = await issuer.post(
"/did/cheqd/update", json={"did": did, "didDocument": did_document}
)
updated_did_doc = did_update_result.get("didDocument")
updated_did = did_update_result.get("did")

assert updated_did == did, "DID mismatch after update."
assert (
"service" in updated_did_doc
), "Key 'service' is missing in updated DID document."
assert (
updated_did_doc["service"] == service
), "Service does not match the expected value!"

print(f"Updated DID Document: {format_json(updated_did_doc)}")
return updated_did_doc


async def deactivate_did(issuer, did):
"""Deactivate a DID on the Cheqd testnet."""
did_deactivate_result = await issuer.post(
"/did/cheqd/deactivate",
json={
"did": did,
"options": {"network": "testnet"},
},
)

assert did_deactivate_result.get("did") == did, "DID mismatch after deactivation."
assert (
did_deactivate_result.get("did_document_metadata", {}).get("deactivated") is True
), "DID document metadata does not contain deactivated=true."

print(f"Deactivated DID: {format_json(did_deactivate_result) }")


async def create_schema(issuer, did):
"""Create a schema on the Cheqd testnet."""
schema_create_result = await issuer.post(
"/anoncreds/schema",
json={
"schema": {
"attrNames": ["score"],
"issuerId": did,
"name": "Example schema",
"version": "1.0",
}
},
)
print(f"Created schema: {format_json(schema_create_result)}")
schema_state = schema_create_result.get("schema_state")
assert schema_state.get("state") == "finished", "Schema state is not finished."
assert "schema_id" in schema_state, "Key 'schema_id' is missing in schema_state."

schema_id = schema_state.get("schema_id")
assert (
did in schema_id
), f"schema_id does not contain the expected DID. Expected '{did}' in '{schema_id}'."

return schema_id

async def scenario2_create_schema_and_credential_definition(issuer, did):
"""Perform a scenario involving schema and credential definition creation.
async def create_credential_definition(issuer, did, schema_id):
"""Create a credential definition on the connected datastore."""
cred_def_create_result = await issuer.post(
"/anoncreds/credential-definition",
json={
"credential_definition": {
"issuerId": did,
"schemaId": schema_id,
"tag": "default",
}
},
)
This function demonstrates the creation of a schema and a corresponding credential
definition using the provided issuer controller and DID. It also validates the
created credential definition and asserts the presence of the DID in the wallet.
"""
schema_id = await create_schema(issuer, did)
print(schema_id)

cred_def_state = cred_def_create_result.get("credential_definition_state", {})
assert cred_def_state.get("state") == "finished", "Cred def state is not finished."
assert (
"credential_definition_id" in cred_def_state
), "Key 'credential_definition_id' is missing in credential_definition_state."
credential_definition_id = await create_credential_definition(issuer, did, schema_id)
print(credential_definition_id)

credential_definition_id = cred_def_state.get("credential_definition_id")
assert (
did in credential_definition_id
), "credential_definition_id does not contain the expected DID."
await assert_credential_definitions(issuer, credential_definition_id)
await assert_wallet_dids(issuer, did)

print(f"Created credential definition: {format_json(cred_def_create_result)}")
return credential_definition_id


async def assert_credential_definitions(issuer, credential_definition_id):
"""Retrieve all cred_defs & ensure array contain created credential_definition_id."""
get_result = await issuer.get("/anoncreds/credential-definitions")

credential_definition_ids = get_result.get("credential_definition_ids", [])
assert (
credential_definition_id in credential_definition_ids
), "credential_definition_ids does not contain the expected credential_definition_id."


async def assert_wallet_dids(issuer, did):
"""Retrieve all wallet dids and ensure array contain created did."""
get_result = await issuer.get("/wallet/did?method=cheqd")

dids = get_result.get("results", [])
assert any(obj.get("did") == did for obj in dids), f"DID {did} not found in array"

async def scenario3_issue_credential(issuer, holder, credential_definition_id):
"""Perform a scenario involving credential issuance.
async def issue_credential_v2(
issuer: Controller,
holder: Controller,
issuer_connection_id: str,
holder_connection_id: str,
cred_def_id: str,
attributes: Mapping[str, str],
) -> Tuple[V20CredExRecordDetail, V20CredExRecordDetail]:
"""Issue an credential using issue-credential/2.0.
Issuer and holder should already be connected.
This function demonstrates the process of connecting an issuer and holder,
followed by issuing a credential based on a given credential definition ID.
It uses DID exchange for establishing connections and then issues the credential
with specified attributes.
"""

issuer_cred_ex = await issuer.post(
"/issue-credential-2.0/send",
json={
"auto_issue": True,
"auto_remove": False,
"comment": "Credential from minimal example",
"trace": False,
"connection_id": issuer_connection_id,
"filter": {
"anoncreds": {
"cred_def_id": cred_def_id,
}
},
"credential_preview": {
"type": "issue-credential-2.0/2.0/credential-preview", # pyright: ignore
"attributes": [
{
"name": name,
"value": value,
}
for name, value in attributes.items()
],
},
},
response=V20CredExRecord,
)
issuer_cred_ex_id = issuer_cred_ex.cred_ex_id

holder_cred_ex = await holder.event_with_values(
topic="issue_credential_v2_0",
event_type=V20CredExRecord,
connection_id=holder_connection_id,
state="offer-received",
)
holder_cred_ex_id = holder_cred_ex.cred_ex_id

await holder.post(
f"/issue-credential-2.0/records/{holder_cred_ex_id}/send-request",
response=V20CredExRecord,
)

await issuer.event_with_values(
topic="issue_credential_v2_0",
cred_ex_id=issuer_cred_ex_id,
state="request-received",
# Connect issuer and holder
issuer_conn_with_anoncreds_holder, holder_anoncreds_conn = await didexchange(
issuer, holder
)

await holder.event_with_values(
topic="issue_credential_v2_0",
cred_ex_id=holder_cred_ex_id,
state="credential-received",
issue_credential_result = await issue_credential_v2(
issuer,
holder,
issuer_conn_with_anoncreds_holder.connection_id,
holder_anoncreds_conn.connection_id,
credential_definition_id,
{"score": "99"},
)
print(issue_credential_result)

await holder.post(
f"/issue-credential-2.0/records/{holder_cred_ex_id}/store",
json={},
response=V20CredExRecordDetail,
)

issuer_cred_ex = await issuer.event_with_values(
topic="issue_credential_v2_0",
event_type=V20CredExRecord,
cred_ex_id=issuer_cred_ex_id,
state="done",
)
async def scenario4_deactivate_did(issuer, did):
"""Perform a scenario to deactivate a DID.
holder_cred_ex = await holder.event_with_values(
topic="issue_credential_v2_0",
event_type=V20CredExRecord,
cred_ex_id=holder_cred_ex_id,
state="done",
)

return (
V20CredExRecordDetail(cred_ex_record=issuer_cred_ex),
V20CredExRecordDetail(cred_ex_record=holder_cred_ex),
)
This function demonstrates the deactivation of a given DID using the provided
issuer controller.
"""
await deactivate_did(issuer, did)


async def main():
Expand All @@ -292,39 +100,15 @@ async def main():
This section of the test script demonstrates the CRUD operations of a did
followed by creating schema, credential definition and credential issuance.
"""
did = await create_did(issuer)
did = await scenario1_create_and_resolve_did(issuer)

await resolve_did(issuer, did)

# updated_did_document = await update_did(issuer, did, did_document)

schema_id = await create_schema(issuer, did)
print(schema_id)

credential_definition_id = await create_credential_definition(
issuer, did, schema_id
credential_definition_id = (
await scenario2_create_schema_and_credential_definition(issuer, did)
)
print(credential_definition_id)

await assert_credential_definitions(issuer, credential_definition_id)
await assert_wallet_dids(issuer, did)

# Connect issuer and holder
issuer_conn_with_anoncreds_holder, holder_anoncreds_conn = await didexchange(
issuer, holder
)

issue_credential_result = await issue_credential_v2(
issuer,
holder,
issuer_conn_with_anoncreds_holder.connection_id,
holder_anoncreds_conn.connection_id,
credential_definition_id,
{"score": "99"},
)
print(issue_credential_result)
await scenario3_issue_credential(issuer, holder, credential_definition_id)

# await deactivate_did(issuer, did)
# await scenario4_deactivate_did(issuer, did)


if __name__ == "__main__":
Expand Down
Loading

0 comments on commit cf12ae3

Please sign in to comment.