Skip to content

Commit

Permalink
Merge pull request #108 from andrewwhitehead/fix-demo-pres-request
Browse files Browse the repository at this point in the history
Fix demo presentation request, optimize credential retrieval
  • Loading branch information
nrempel authored Jul 31, 2019
2 parents 7ff42bf + 03d5180 commit 3b62a43
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 41 deletions.
14 changes: 14 additions & 0 deletions aries_cloudagent/config/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,16 @@ def add_arguments(self, parser: ArgumentParser):
action="store_true",
help="Enable additional logging around connections",
)
parser.add_argument(
"--debug-credentials",
action="store_true",
help="Enable additional logging around credential exchanges",
)
parser.add_argument(
"--debug-presentations",
action="store_true",
help="Enable additional logging around presentation exchanges",
)
parser.add_argument(
"--invite",
action="store_true",
Expand Down Expand Up @@ -224,6 +234,10 @@ def get_settings(self, args: Namespace) -> dict:
settings["debug.enabled"] = True
if args.debug_connections:
settings["debug.connections"] = True
if args.debug_credentials:
settings["debug.credentials"] = True
if args.debug_presentations:
settings["debug.presentations"] = True
if args.debug_seed:
settings["debug.seed"] = args.debug_seed
if args.invite:
Expand Down
51 changes: 36 additions & 15 deletions aries_cloudagent/holder/indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import json
import logging

from collections import OrderedDict
from typing import Sequence

import indy.anoncreds
from indy.error import ErrorCode, IndyError

Expand Down Expand Up @@ -115,7 +118,7 @@ async def get_credentials(self, start: int, count: int, wql: dict):
async def get_credentials_for_presentation_request_by_referent(
self,
presentation_request: dict,
referent: str,
referents: Sequence[str],
start: int,
count: int,
extra_query: dict = {},
Expand All @@ -125,9 +128,9 @@ async def get_credentials_for_presentation_request_by_referent(
Args:
presentation_request: Valid presentation request from issuer
referent: Presentation request referent to use to search for creds
referents: Presentation request referents to use to search for creds
start: Starting index
count: Number of records to return
count: Maximum number of records to return
extra_query: wql query dict
"""
Expand All @@ -138,27 +141,45 @@ async def get_credentials_for_presentation_request_by_referent(
json.dumps(extra_query),
)

# We need to move the database cursor position manually...
if start > 0:
# TODO: move cursors in chunks to avoid exploding memory
await indy.anoncreds.prover_fetch_credentials_for_proof_req(
search_handle, referent, start
if not referents:
referents = (
*presentation_request["requested_attributes"],
*presentation_request["requested_predicates"],
)
creds_dict = OrderedDict()

try:
(
credentials_json
) = await indy.anoncreds.prover_fetch_credentials_for_proof_req(
search_handle, referent, count
)
for reft in referents:
# We need to move the database cursor position manually...
if start > 0:
# TODO: move cursors in chunks to avoid exploding memory
await indy.anoncreds.prover_fetch_credentials_for_proof_req(
search_handle, reft, start
)
(
credentials_json
) = await indy.anoncreds.prover_fetch_credentials_for_proof_req(
search_handle, reft, count
)
credentials = json.loads(credentials_json)
for cred in credentials:
cred_id = cred["cred_info"]["referent"]
if cred_id not in creds_dict:
cred["presentation_referents"] = {reft}
creds_dict[cred_id] = cred
else:
creds_dict[cred_id]["presentation_referents"].add(reft)

finally:
# Always close
await indy.anoncreds.prover_close_credentials_search_for_proof_req(
search_handle
)

credentials = json.loads(credentials_json)
return credentials
for cred in creds_dict.values():
cred["presentation_referents"] = list(cred["presentation_referents"])

return tuple(creds_dict.values())[:count]

async def get_credential(self, credential_id: str):
"""
Expand Down
10 changes: 7 additions & 3 deletions aries_cloudagent/holder/tests/test_indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,15 @@ async def test_get_credentials_for_presentation_request_by_referent(
mock_prover_search_credentials_for_proof_req,
):
mock_prover_search_credentials_for_proof_req.return_value = "search_handle"
mock_prover_fetch_credentials_for_proof_req.return_value = '{"x": "y"}'
mock_prover_fetch_credentials_for_proof_req.return_value = (
'[{"cred_info": {"referent": "asdb"}}]'
)

mock_wallet = async_mock.MagicMock()
holder = IndyHolder(mock_wallet)

credentials = await holder.get_credentials_for_presentation_request_by_referent(
{"p": "r"}, "asdb", 2, 3, {"e": "q"}
{"p": "r"}, ("asdb",), 2, 3, {"e": "q"}
)

mock_prover_search_credentials_for_proof_req.assert_called_once_with(
Expand All @@ -132,7 +134,9 @@ async def test_get_credentials_for_presentation_request_by_referent(
"search_handle"
)

assert credentials == json.loads('{"x": "y"}')
assert credentials == (
{"cred_info": {"referent": "asdb"}, "presentation_referents": ["asdb"]},
)

@async_mock.patch("indy.anoncreds.prover_get_credential")
async def test_get_credential(self, mock_get_cred):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Meta:
RECORD_TYPE = "credential_exchange"
RECORD_ID_NAME = "credential_exchange_id"
WEBHOOK_TOPIC = "credentials"
LOG_STATE_FLAG = "debug.credentials"

INITIATOR_SELF = "self"
INITIATOR_EXTERNAL = "external"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder):
(
credentials
) = await holder.get_credentials_for_presentation_request_by_referent(
presentation_request, referent, 0, 2, {}
presentation_request, (referent,), 0, 2, {}
)
if len(credentials) != 1:
self._logger.warning(
Expand All @@ -73,7 +73,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder):
(
credentials
) = await holder.get_credentials_for_presentation_request_by_referent(
presentation_request, referent, 0, 2, {}
presentation_request, (referent,), 0, 2, {}
)
if len(credentials) != 1:
self._logger.warning(
Expand Down
4 changes: 3 additions & 1 deletion aries_cloudagent/messaging/presentations/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,9 @@ async def create_presentation(
)
presentation_exchange_record.presentation = presentation
await presentation_exchange_record.save(
self.context, reason="Create presentation"
self.context,
reason="Create presentation",
log_params={"requested_credentials": requested_credentials},
)

return presentation_exchange_record, presentation_message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Meta:
RECORD_TYPE = "presentation_exchange"
RECORD_ID_NAME = "presentation_exchange_id"
WEBHOOK_TOPIC = "presentations"
LOG_STATE_FLAG = "debug.presentations"

INITIATOR_SELF = "self"
INITIATOR_EXTERNAL = "external"
Expand Down
19 changes: 17 additions & 2 deletions aries_cloudagent/messaging/presentations/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ async def presentation_exchange_credentials_list(request: web.BaseRequest):
context = request.app["request_context"]

presentation_exchange_id = request.match_info["id"]
presentation_referent = request.match_info["referent"]
presentation_referent = request.match_info.get("referent")

try:
presentation_exchange_record = await PresentationExchange.retrieve_by_id(
Expand All @@ -171,12 +171,23 @@ async def presentation_exchange_credentials_list(request: web.BaseRequest):
holder: BaseHolder = await context.inject(BaseHolder)
credentials = await holder.get_credentials_for_presentation_request_by_referent(
presentation_exchange_record.presentation_request,
presentation_referent,
(presentation_referent,) if presentation_referent else (),
start,
count,
extra_query,
)

presentation_exchange_record.log_state(
context,
"Retrieved presentation credentials",
{
"presentation_exchange_id": presentation_exchange_id,
"referent": presentation_referent,
"extra_query": extra_query,
"credentials": credentials,
},
)

return web.json_response(credentials)


Expand Down Expand Up @@ -334,6 +345,10 @@ async def register(app: web.Application):
[
web.get("/presentation_exchange", presentation_exchange_list),
web.get("/presentation_exchange/{id}", presentation_exchange_retrieve),
web.get(
"/presentation_exchange/{id}/credentials",
presentation_exchange_credentials_list,
),
web.get(
"/presentation_exchange/{id}/credentials/{referent}",
presentation_exchange_credentials_list,
Expand Down
41 changes: 24 additions & 17 deletions demo/runners/alice.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ def __init__(self, http_port: int, admin_port: int, **kwargs):
http_port,
admin_port,
prefix="Alice",
extra_args=["--auto-accept-invites", "--auto-accept-requests"],
extra_args=[
"--auto-accept-invites",
"--auto-accept-requests",
"--auto-store-credential",
],
seed=None,
**kwargs,
)
Expand Down Expand Up @@ -98,35 +102,38 @@ async def handle_presentations(self, message):
)

# include self-attested attributes (not included in credentials)
credentials_by_reft = {}
revealed = {}
self_attested = {}
predicates = {}

for referent in presentation_request["requested_attributes"]:
# select credentials to provide for the proof
credentials = await self.admin_GET(
f"/presentation_exchange/{presentation_exchange_id}/credentials"
)
if credentials:
for row in credentials:
for referent in row["presentation_referents"]:
if referent not in credentials_by_reft:
credentials_by_reft[referent] = row

# select credentials to provide for the proof
credentials = await self.admin_GET(
f"/presentation_exchange/{presentation_exchange_id}"
+ f"/credentials/{referent}"
)
if credentials:
for referent in presentation_request["requested_attributes"]:
if referent in credentials_by_reft:
revealed[referent] = {
"cred_id": credentials[0]["cred_info"]["referent"],
"cred_id": credentials_by_reft[referent]["cred_info"][
"referent"
],
"revealed": True,
}
else:
self_attested[referent] = "my self-attested value"

for referent in presentation_request["requested_predicates"]:

# select credentials to provide for the proof
credentials = await self.admin_GET(
f"/presentation_exchange/{presentation_exchange_id}"
f"/credentials/{referent}"
)
if credentials:
if referent in credentials_by_reft:
predicates[referent] = {
"cred_id": credentials[0]["cred_info"]["referent"],
"cred_id": credentials_by_reft[referent]["cred_info"][
"referent"
],
"revealed": True,
}

Expand Down
2 changes: 1 addition & 1 deletion demo/runners/performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def __init__(self, port: int, **kwargs):
super().__init__("Alice", port, seed=None, **kwargs)
self.credential_state = {}
self.credential_event = asyncio.Event()
self.extra_args = ["--auto-respond-credential-offer"]
self.extra_args = ["--auto-respond-credential-offer", "--auto-store-credential"]

async def handle_credentials(self, payload):
cred_id = payload["credential_exchange_id"]
Expand Down

0 comments on commit 3b62a43

Please sign in to comment.