Skip to content

Commit

Permalink
Merge pull request #1607 from ianco/endorser-did-support
Browse files Browse the repository at this point in the history
Auto-promote author did to public after endorsing
  • Loading branch information
swcurran committed Feb 8, 2022
2 parents ec265ea + 54a1915 commit 70a69d3
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 59 deletions.
43 changes: 39 additions & 4 deletions aries_cloudagent/config/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -1690,6 +1690,17 @@ def add_arguments(self, parser: ArgumentParser):
"agent who will be endorsing transactions."
),
)
parser.add_argument(
"--endorser-endorse-with-did",
type=str,
metavar="<endorser-endorse-with-did>",
env_var="ACAPY_ENDORSER_ENDORSE_WITH_DID",
help=(
"For transaction Endorsers, specify the DID to use to endorse "
"transactions. The default (if not specified) is to use the "
"Endorser's Public DID."
),
)
parser.add_argument(
"--endorser-alias",
type=str,
Expand Down Expand Up @@ -1733,6 +1744,13 @@ def add_arguments(self, parser: ArgumentParser):
" the controller must invoke the endpoints required to create the"
" revocation registry and assign to the cred def.)",
)
parser.add_argument(
"--auto-promote-author-did",
action="store_true",
env_var="ACAPY_PROMOTE-AUTHOR-DID",
help="For Authors, specify whether to automatically promote"
" a DID to the wallet public DID after writing to the ledger.",
)

def get_settings(self, args: Namespace):
"""Extract endorser settings."""
Expand All @@ -1742,6 +1760,7 @@ def get_settings(self, args: Namespace):
settings["endorser.auto_endorse"] = False
settings["endorser.auto_write"] = False
settings["endorser.auto_create_rev_reg"] = False
settings["endorser.auto_promote_author_did"] = False

if args.endorser_protocol_role:
if args.endorser_protocol_role == ENDORSER_AUTHOR:
Expand All @@ -1758,6 +1777,17 @@ def get_settings(self, args: Namespace):
"Authors"
)

if args.endorser_endorse_with_did:
if settings["endorser.endorser"]:
settings[
"endorser.endorser_endorse_with_did"
] = args.endorser_endorse_with_did
else:
raise ArgsParseError(
"Parameter --endorser-endorse-with-did should only be set for "
"transaction Endorsers"
)

if args.endorser_alias:
if settings["endorser.author"]:
settings["endorser.endorser_alias"] = args.endorser_alias
Expand Down Expand Up @@ -1790,7 +1820,6 @@ def get_settings(self, args: Namespace):
if settings["endorser.author"]:
settings["endorser.auto_request"] = True
else:
pass
raise ArgsParseError(
"Parameter --auto-request-endorsement should only be set for "
"transaction Authors"
Expand All @@ -1800,7 +1829,6 @@ def get_settings(self, args: Namespace):
if settings["endorser.endorser"]:
settings["endorser.auto_endorse"] = True
else:
pass
raise ArgsParseError(
"Parameter --auto-endorser-transactions should only be set for "
"transaction Endorsers"
Expand All @@ -1810,7 +1838,6 @@ def get_settings(self, args: Namespace):
if settings["endorser.author"]:
settings["endorser.auto_write"] = True
else:
pass
raise ArgsParseError(
"Parameter --auto-write-transactions should only be set for "
"transaction Authors"
Expand All @@ -1820,12 +1847,20 @@ def get_settings(self, args: Namespace):
if settings["endorser.author"]:
settings["endorser.auto_create_rev_reg"] = True
else:
pass
raise ArgsParseError(
"Parameter --auto-create-revocation-transactions should only be set "
"for transaction Authors"
)

if args.auto_promote_author_did:
if settings["endorser.author"]:
settings["endorser.auto_promote_author_did"] = True
else:
raise ArgsParseError(
"Parameter --auto-promote-author-did should only be set "
"for transaction Authors"
)

return settings


Expand Down
1 change: 1 addition & 0 deletions aries_cloudagent/ledger/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ def taa_digest(self, version: str, text: str):
async def txn_endorse(
self,
request_json: str,
endorse_did: DIDInfo = None,
) -> str:
"""Endorse (sign) the provided transaction."""

Expand Down
6 changes: 4 additions & 2 deletions aries_cloudagent/ledger/indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,14 @@ async def get_wallet_public_did(self) -> DIDInfo:
async def _endorse(
self,
request_json: str,
endorse_did: DIDInfo = None,
) -> str:
if not self.pool.handle:
raise ClosedPoolError(
f"Cannot endorse request with closed pool '{self.pool.name}'"
)

public_info = await self.get_wallet_public_did()
public_info = endorse_did if endorse_did else await self.get_wallet_public_did()
if not public_info:
raise BadLedgerRequestError(
"Cannot endorse transaction without a public DID"
Expand Down Expand Up @@ -403,9 +404,10 @@ async def _submit(
async def txn_endorse(
self,
request_json: str,
endorse_did: DIDInfo = None,
) -> str:
"""Endorse a (signed) ledger transaction."""
return await self._endorse(request_json)
return await self._endorse(request_json, endorse_did=endorse_did)

async def txn_submit(
self,
Expand Down
3 changes: 2 additions & 1 deletion aries_cloudagent/ledger/indy_vdr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,7 @@ async def get_wallet_public_did(self) -> DIDInfo:
async def txn_endorse(
self,
request_json: str,
endorse_did: DIDInfo = None,
) -> str:
"""Endorse (sign) the provided transaction."""
try:
Expand All @@ -1360,7 +1361,7 @@ async def txn_endorse(

async with self.profile.session() as session:
wallet = session.inject(BaseWallet)
sign_did = await wallet.get_public_did()
sign_did = endorse_did if endorse_did else await wallet.get_public_did()
if not sign_did:
raise BadLedgerRequestError(
"Cannot endorse transaction without a public DID"
Expand Down
6 changes: 3 additions & 3 deletions aries_cloudagent/ledger/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
)
from .endpoint_type import EndpointType
from .error import BadLedgerRequestError, LedgerError, LedgerTransactionError
from .util import notify_did_event
from .util import notify_register_did_event


class LedgerModulesResultSchema(OpenAPISchema):
Expand Down Expand Up @@ -316,10 +316,10 @@ async def register_ledger_nym(request: web.BaseRequest):
)
)

meta_data = {"verkey": verkey, "alias": alias, "role": role}
meta_data = {"did": did, "verkey": verkey, "alias": alias, "role": role}
if not create_transaction_for_endorser:
# Notify event
await notify_did_event(context.profile, did, meta_data)
await notify_register_did_event(context.profile, did, meta_data)
return web.json_response({"success": success})
else:
transaction_mgr = TransactionManager(context.profile)
Expand Down
4 changes: 2 additions & 2 deletions aries_cloudagent/ledger/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

TAA_ACCEPTED_RECORD_TYPE = "taa_accepted"

DID_EVENT_PREFIX = "acapy::DID::"
DID_EVENT_PREFIX = "acapy::REGISTER_DID::"
EVENT_LISTENER_PATTERN = re.compile(f"^{DID_EVENT_PREFIX}(.*)?$")


async def notify_did_event(profile: Profile, did: str, meta_data: dict):
async def notify_register_did_event(profile: Profile, did: str, meta_data: dict):
"""Send notification for a DID post-process event."""
await profile.notify(
DID_EVENT_PREFIX + did,
Expand Down
27 changes: 24 additions & 3 deletions aries_cloudagent/protocols/endorse_transaction/v1_0/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from ....storage.error import StorageError, StorageNotFoundError
from ....transport.inbound.receipt import MessageReceipt
from ....wallet.base import BaseWallet
from ....wallet.util import notify_endorse_did_event

from .messages.cancel_transaction import CancelTransaction
from .messages.endorsed_transaction_response import EndorsedTransactionResponse
Expand Down Expand Up @@ -204,6 +205,7 @@ async def create_endorse_response(
self,
transaction: TransactionRecord,
state: str,
use_endorser_did: str = None,
):
"""
Create a response to endorse a transaction.
Expand Down Expand Up @@ -233,10 +235,22 @@ async def create_endorse_response(
wallet: BaseWallet = session.inject_or(BaseWallet)
if not wallet:
raise StorageError("No wallet available")
endorser_did_info = await wallet.get_public_did()
endorser_did_info = None
override_did = (
use_endorser_did
if use_endorser_did
else session.context.settings.get_value(
"endorser.endorser_endorse_with_did"
)
)
if override_did:
endorser_did_info = await wallet.get_local_did(override_did)
else:
endorser_did_info = await wallet.get_public_did()
if not endorser_did_info:
raise StorageError(
"Transaction cannot be endorsed as there is no Public DID in wallet"
"Transaction cannot be endorsed as there is no Public DID in wallet "
"or Endorser DID specified"
)
endorser_did = endorser_did_info.did
endorser_verkey = endorser_did_info.verkey
Expand All @@ -250,7 +264,9 @@ async def create_endorse_response(
raise LedgerError(reason=reason)

async with ledger:
endorsed_msg = await shield(ledger.txn_endorse(transaction_json))
endorsed_msg = await shield(
ledger.txn_endorse(transaction_json, endorse_did=endorser_did_info)
)

# need to return the endorsed msg or else the ledger will reject the
# eventual transaction write
Expand Down Expand Up @@ -790,6 +806,11 @@ async def endorsed_txn_post_processing(
self._profile, rev_reg_id, meta_data
)

elif ledger_response["result"]["txn"]["type"] == "1":
# write DID to ledger
did = ledger_response["result"]["txn"]["data"]["dest"]
await notify_endorse_did_event(self._profile, did, meta_data)

else:
# TODO unknown ledger transaction type, just ignore for now ...
pass
16 changes: 14 additions & 2 deletions aries_cloudagent/protocols/endorse_transaction/v1_0/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ class TranIdMatchInfoSchema(OpenAPISchema):
)


class EndorserDIDInfoSchema(OpenAPISchema):
"""Path parameters and validators for request Endorser DID."""

endorser_did = fields.Str(
description="Endorser DID",
required=False,
)


class AssignTransactionJobsSchema(OpenAPISchema):
"""Assign transaction related jobs to connection record."""

Expand Down Expand Up @@ -289,6 +298,7 @@ async def transaction_create_request(request: web.BaseRequest):
tags=["endorse-transaction"],
summary="For Endorser to endorse a particular transaction record",
)
@querystring_schema(EndorserDIDInfoSchema())
@match_info_schema(TranIdMatchInfoSchema())
@response_schema(TransactionRecordSchema(), 200)
async def endorse_transaction_response(request: web.BaseRequest):
Expand All @@ -305,6 +315,7 @@ async def endorse_transaction_response(request: web.BaseRequest):
outbound_handler = request["outbound_message_router"]

transaction_id = request.match_info["tran_id"]
endorser_did = request.query.get("endorser_did")
try:
async with context.profile.session() as session:
transaction = await TransactionRecord.retrieve_by_id(
Expand All @@ -313,6 +324,7 @@ async def endorse_transaction_response(request: web.BaseRequest):
connection_record = await ConnRecord.retrieve_by_id(
session, transaction.connection_id
)
# provided DID is validated in the TransactionManager

except StorageNotFoundError as err:
raise web.HTTPNotFound(reason=err.roll_up) from err
Expand Down Expand Up @@ -341,6 +353,7 @@ async def endorse_transaction_response(request: web.BaseRequest):
) = await transaction_mgr.create_endorse_response(
transaction=transaction,
state=TransactionRecord.STATE_TRANSACTION_ENDORSED,
use_endorser_did=endorser_did,
)
except (IndyIssuerError, LedgerError) as err:
raise web.HTTPBadRequest(reason=err.roll_up) from err
Expand Down Expand Up @@ -787,11 +800,10 @@ async def on_startup_event(profile: Profile, event: Event):
value = {"endorser_did": endorser_did, "endorser_name": endorser_alias}
await conn_record.metadata_set(session, key="endorser_info", value=value)

except Exception as e:
except Exception:
# log the error, but continue
LOGGER.exception(
"Error accepting endorser invitation/configuring endorser connection: %s",
str(e),
)


Expand Down
Loading

0 comments on commit 70a69d3

Please sign in to comment.