Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anoncreds schema endorsement #2715

Merged
merged 3 commits into from
Jan 31, 2024
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
6 changes: 3 additions & 3 deletions aries_cloudagent/anoncreds/default/did_indy/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from ....config.injection_context import InjectionContext
from ....core.profile import Profile
from ...base import BaseAnonCredsRegistrar, BaseAnonCredsResolver
from ...models.anoncreds_cred_def import (
CredDef,
CredDefResult,
Expand All @@ -14,13 +15,12 @@
from ...models.anoncreds_revocation import (
GetRevListResult,
GetRevRegDefResult,
RevRegDef,
RevRegDefResult,
RevList,
RevListResult,
RevRegDef,
RevRegDefResult,
)
from ...models.anoncreds_schema import AnonCredsSchema, GetSchemaResult, SchemaResult
from ...base import BaseAnonCredsRegistrar, BaseAnonCredsResolver

LOGGER = logging.getLogger(__name__)

Expand Down
54 changes: 54 additions & 0 deletions aries_cloudagent/anoncreds/default/legacy_indy/author.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Author specific for indy legacy."""

from typing import Optional

from aiohttp import web

from aries_cloudagent.connections.models.conn_record import ConnRecord
from aries_cloudagent.messaging.models.base import BaseModelError
from aries_cloudagent.protocols.endorse_transaction.v1_0.util import (
get_endorser_connection_id,
)
from aries_cloudagent.storage.error import StorageNotFoundError


async def get_endorser_info(profile, options: Optional[dict] = {}):
"""Gets the endorser did for the current transaction."""
endorser_connection_id = options.get("endorser_connection_id", None)
if not endorser_connection_id:
endorser_connection_id = await get_endorser_connection_id(profile)

if not endorser_connection_id:
raise web.HTTPForbidden(reason="No endorser connection found")

try:
async with profile.session() as session:
connection_record = await ConnRecord.retrieve_by_id(
session, endorser_connection_id
)
endorser_info = await connection_record.metadata_get(
session, "endorser_info"
)
except StorageNotFoundError as err:
raise web.HTTPNotFound(
reason=f"Connection for endorser with id {endorser_connection_id} not found"
) from err
except BaseModelError as err:
raise web.HTTPBadRequest(reason=err.roll_up) from err

if not endorser_info:
raise web.HTTPForbidden(
reason=(
"Endorser Info is not set up in "
"connection metadata for this connection record"
)
)
if "endorser_did" not in endorser_info.keys():
raise web.HTTPForbidden(
reason=(
' "endorser_did" is not set in "endorser_info"'
" in connection metadata for this connection record"
)
)

return endorser_info["endorser_did"], endorser_connection_id
133 changes: 114 additions & 19 deletions aries_cloudagent/anoncreds/default/legacy_indy/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import json
import logging
import re
import uuid
from asyncio import shield
from typing import List, Optional, Pattern, Sequence, Tuple

from base58 import alphabet

from ....anoncreds.default.legacy_indy.author import get_endorser_info
from ....cache.base import BaseCache
from ....config.injection_context import InjectionContext
from ....core.profile import Profile
Expand All @@ -22,9 +24,20 @@
GET_CRED_DEF,
IndyLedgerRequestsExecutor,
)
from ....messaging.responder import BaseResponder
from ....multitenant.base import BaseMultitenantManager
from ....revocation_anoncreds.models.issuer_cred_rev_record import IssuerCredRevRecord
from ....protocols.endorse_transaction.v1_0.manager import (
TransactionManager,
TransactionManagerError,
)
from ....protocols.endorse_transaction.v1_0.util import is_author_role
from ....revocation_anoncreds.models.issuer_cred_rev_record import (
IssuerCredRevRecord,
)
from ....revocation_anoncreds.recover import generate_ledger_rrrecovery_txn
from ....storage.error import StorageError
from ....utils import sentinel
from ....wallet.did_info import DIDInfo
from ...base import (
AnonCredsObjectAlreadyExists,
AnonCredsObjectNotFound,
Expand Down Expand Up @@ -194,11 +207,7 @@ async def register_schema(
# Assume endorser role on the network, no option for 3rd-party endorser
ledger = profile.inject_or(BaseLedger)
if not ledger:
reason = "No ledger available"
if not profile.settings.get_value("wallet.type"):
# TODO is this warning necessary?
reason += ": missing wallet-type?"
raise AnonCredsRegistrationError(reason)
raise AnonCredsRegistrationError("No ledger available")

# Translate schema into format expected by Indy
LOGGER.debug("Registering schema: %s", schema_id)
Expand All @@ -212,32 +221,90 @@ async def register_schema(
}
LOGGER.debug("schema value: %s", indy_schema)

endorser_did = None
create_transaction = options.get("create_transaction_for_endorser", False)

if is_author_role(profile) or create_transaction:
endorser_did, endorser_connection_id = await get_endorser_info(
profile, options
)

write_ledger = (
True if endorser_did is None and not create_transaction else False
)

# Get either the transaction or the seq_no or the created schema
async with ledger:
try:
seq_no = await shield(
ledger.send_schema_anoncreds(schema_id, indy_schema)
result = await shield(
ledger.send_schema_anoncreds(
schema_id,
indy_schema,
write_ledger=write_ledger,
endorser_did=endorser_did,
)
)
except LedgerObjectAlreadyExistsError as err:
indy_schema = err.obj
schema = AnonCredsSchema(
name=indy_schema["name"],
version=indy_schema["version"],
attr_names=indy_schema["attrNames"],
issuer_id=indy_schema["id"].split(":")[0],
)
raise AnonCredsSchemaAlreadyExists(err.message, err.obj_id, schema)
except (AnonCredsIssuerError, LedgerError) as err:
raise AnonCredsRegistrationError("Failed to register schema") from err

# Didn't need endorsement, so return schema result
if write_ledger:
return SchemaResult(
job_id=None,
schema_state=SchemaState(
state=SchemaState.STATE_FINISHED,
schema_id=schema_id,
schema=schema,
),
registration_metadata={},
schema_metadata={"seqNo": result},
)

# Need endorsement, so execute transaction flow
(schema_id, schema_def) = result

job_id = uuid.uuid4().hex
meta_data = {"context": {"job_id": job_id, "schema_id": schema_id}}

transaction_manager = TransactionManager(profile)
try:
transaction = await transaction_manager.create_record(
messages_attach=schema_def["signed_txn"],
connection_id=endorser_connection_id,
meta_data=meta_data,
)
except StorageError:
raise AnonCredsRegistrationError("Failed to store transaction record")

if profile.settings.get("endorser.auto_request"):
try:
(
transaction,
transaction_request,
) = await transaction_manager.create_request(transaction=transaction)
except (StorageError, TransactionManagerError) as err:
raise AnonCredsRegistrationError(
"Transaction manager failed to create request: " + err.roll_up
) from err

responder = profile.inject(BaseResponder)
await responder.send(
message=transaction_request,
connection_id=endorser_connection_id,
)

return SchemaResult(
job_id=None,
job_id=job_id,
schema_state=SchemaState(
state=SchemaState.STATE_FINISHED,
state=SchemaState.STATE_WAIT,
schema_id=schema_id,
schema=schema,
),
registration_metadata={},
schema_metadata={"seqNo": seq_no},
registration_metadata={
"txn": transaction.serialize(),
},
)

async def get_credential_definition(
Expand Down Expand Up @@ -771,3 +838,31 @@ async def fix_ledger_entry(
applied_txn = ledger_response["result"]

return (rev_reg_delta, recovery_txn, applied_txn)

async def txn_submit(
self,
profile: Profile,
ledger_transaction: str,
sign: bool = None,
taa_accept: bool = None,
sign_did: DIDInfo = sentinel,
write_ledger: bool = True,
) -> str:
"""Submit a transaction to the ledger."""
ledger = profile.inject(BaseLedger)

if not ledger:
raise LedgerError("No ledger available")

try:
return await shield(
ledger.txn_submit(
ledger_transaction,
sign=sign,
taa_accept=taa_accept,
sign_did=sign_did,
write_ledger=write_ledger,
)
)
except LedgerError as err:
raise AnonCredsRegistrationError(err.roll_up) from err
Loading
Loading