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

Fix: RevRegEntry Transaction Endorsement #2558

Merged
merged 21 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
cdf5751
fix + unit tests
shaangill025 Oct 19, 2023
4078b97
Merge branch 'main' into issue_2441
shaangill025 Oct 19, 2023
5d3a5ea
update send_entry on calling publish-revocations
shaangill025 Oct 19, 2023
e14beb2
Merge branch 'main' of https://github.com/hyperledger/aries-cloudagen…
shaangill025 Oct 19, 2023
f1b6e26
Merge branch 'issue_2441' of https://github.com/shaangill025/aries-cl…
shaangill025 Oct 19, 2023
e318d31
fix int test
shaangill025 Oct 23, 2023
169372e
Merge branch 'main' of https://github.com/hyperledger/aries-cloudagen…
shaangill025 Oct 23, 2023
b79b7f3
Merge branch 'main' into issue_2441
swcurran Nov 2, 2023
cc35120
Merge branch 'main' into issue_2441
swcurran Nov 7, 2023
19ee5f1
Merge branch 'main' into issue_2441
shaangill025 Nov 8, 2023
d8627e4
Merge branch 'main' of https://github.com/hyperledger/aries-cloudagen…
shaangill025 Nov 8, 2023
c14710d
Merge branch 'issue_2441' of https://github.com/shaangill025/aries-cl…
shaangill025 Nov 8, 2023
c7c72bb
Merge branch 'main' of https://github.com/hyperledger/aries-cloudagen…
shaangill025 Nov 10, 2023
b57e19e
unit test fix
shaangill025 Nov 10, 2023
2a19d12
fix timing issue with revoc verification bdd step
shaangill025 Nov 11, 2023
15fc768
Merge branch 'main' into issue_2441
swcurran Nov 17, 2023
00bd7b1
Merge branch 'main' of https://github.com/hyperledger/aries-cloudagen…
shaangill025 Nov 22, 2023
394f117
fixes + fixed tests
shaangill025 Nov 27, 2023
58cce5a
Merge branch 'main' of https://github.com/hyperledger/aries-cloudagen…
shaangill025 Nov 27, 2023
4232efa
Merge branch 'main' into issue_2441
dbluhm Nov 28, 2023
3408274
Merge branch 'main' into issue_2441
dbluhm Nov 29, 2023
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
26 changes: 25 additions & 1 deletion aries_cloudagent/revocation/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from ..protocols.revocation_notification.v1_0.models.rev_notification_record import (
RevNotificationRecord,
)
from ..connections.models.conn_record import ConnRecord
from ..core.error import BaseError
from ..core.profile import Profile
from ..indy.issuer import IndyIssuer
Expand Down Expand Up @@ -48,6 +49,7 @@ async def revoke_credential_by_cred_ex_id(
thread_id: str = None,
connection_id: str = None,
comment: str = None,
write_ledger: bool = True,
):
"""Revoke a credential by its credential exchange identifier at issue.

Expand Down Expand Up @@ -80,6 +82,7 @@ async def revoke_credential_by_cred_ex_id(
thread_id=thread_id,
connection_id=connection_id,
comment=comment,
write_ledger=write_ledger,
)

async def revoke_credential(
Expand All @@ -92,6 +95,7 @@ async def revoke_credential(
thread_id: str = None,
connection_id: str = None,
comment: str = None,
write_ledger: bool = True,
):
"""Revoke a credential.

Expand Down Expand Up @@ -147,7 +151,27 @@ async def revoke_credential(
await txn.commit()
await self.set_cred_revoked_state(rev_reg_id, crids)
if delta_json:
await issuer_rr_upd.send_entry(self._profile)
if write_ledger:
await issuer_rr_upd.send_entry(self._profile)
else:
async with self._profile.session() as session:
try:
connection_record = await ConnRecord.retrieve_by_id(
session, connection_id
)
except StorageNotFoundError:
raise RevocationManagerError(
f"No connection record found for id: {connection_id}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this checking to see if there is an endorser connection? Is so, the error message should be more explicit, I think.

Copy link
Contributor Author

@shaangill025 shaangill025 Oct 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, to check that the connection_id if provided when calling POST /revocation/revoke exists. If no connection_id is provided and the profile is author role then connection_id will be retrieved from endorser.endorser_alias which will always exist. Maybe I can change it to No endorser connection record .... ?

)
endorser_info = await connection_record.metadata_get(
session, "endorser_info"
)
endorser_did = endorser_info["endorser_did"]
await issuer_rr_upd.send_entry(
self._profile,
write_ledger=write_ledger,
endorser_did=endorser_did,
)
await notify_revocation_published_event(
self._profile, rev_reg_id, [cred_rev_id]
)
Expand Down
36 changes: 30 additions & 6 deletions aries_cloudagent/revocation/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ async def revoke(request: web.BaseRequest):
body = await request.json()
cred_ex_id = body.get("cred_ex_id")
body["notify"] = body.get("notify", context.settings.get("revocation.notify"))
notify = body.get("notify")
notify = body.get("notify", False)
connection_id = body.get("connection_id")
body["notify_version"] = body.get("notify_version", "v1_0")
notify_version = body["notify_version"]
Expand All @@ -532,14 +532,38 @@ async def revoke(request: web.BaseRequest):
)

rev_manager = RevocationManager(context.profile)
profile = context.profile
write_ledger = True
if is_author_role(profile):
write_ledger = False
if not connection_id:
connection_id = await get_endorser_connection_id(profile)
if not connection_id:
raise web.HTTPBadRequest(reason="No endorser connection found")
try:
if cred_ex_id:
# rev_reg_id and cred_rev_id should not be present so we can
# safely splat the body
await rev_manager.revoke_credential_by_cred_ex_id(**body)
await rev_manager.revoke_credential_by_cred_ex_id(
cred_ex_id=cred_ex_id,
publish=body.get("publish", False),
notify=notify,
notify_version=notify_version,
thread_id=body.get("thread_id"),
connection_id=connection_id,
comment=body.get("comment"),
write_ledger=write_ledger,
)
else:
# no cred_ex_id so we can safely splat the body
await rev_manager.revoke_credential(**body)
await rev_manager.revoke_credential(
rev_reg_id=body.get("rev_reg_id"),
cred_rev_id=body.get("cred_rev_id"),
publish=body.get("publish", False),
notify=notify,
notify_version=notify_version,
thread_id=body.get("thread_id"),
connection_id=connection_id,
comment=body.get("comment"),
write_ledger=write_ledger,
)
except (
RevocationManagerError,
RevocationError,
Expand Down
144 changes: 144 additions & 0 deletions aries_cloudagent/revocation/tests/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
IssuerCredRevRecord,
)

from ...connections.models.conn_record import ConnRecord
from ...core.in_memory import InMemoryProfile
from ...indy.issuer import IndyIssuer
from ...protocols.issue_credential.v1_0.models.credential_exchange import (
Expand Down Expand Up @@ -96,6 +97,149 @@ async def test_revoke_credential_publish(self):
["2", "1"],
)

async def test_revoke_credential_publish_endorser(self):
conn_record = ConnRecord(
their_label="Hello",
their_role=ConnRecord.Role.RESPONDER.rfc160,
alias="Bob",
)
session = await self.profile.session()
await conn_record.save(session)
await conn_record.metadata_set(
session,
key="endorser_info",
value={
"endorser_did": "test_endorser_did",
"endorser_name": "test_endorser_name",
},
)
conn_id = conn_record.connection_id
assert conn_id is not None
manager = RevocationManager(self.profile)
CRED_EX_ID = "dummy-cxid"
CRED_REV_ID = "1"
mock_issuer_rev_reg_record = async_mock.MagicMock(
revoc_reg_id=REV_REG_ID,
tails_local_path=TAILS_LOCAL,
send_entry=async_mock.CoroutineMock(),
clear_pending=async_mock.CoroutineMock(),
pending_pub=["2"],
)
issuer = async_mock.MagicMock(IndyIssuer, autospec=True)
issuer.revoke_credentials = async_mock.CoroutineMock(
return_value=(
json.dumps(
{
"ver": "1.0",
"value": {
"prevAccum": "1 ...",
"accum": "21 ...",
"issued": [1],
},
}
),
[],
)
)
self.profile.context.injector.bind_instance(IndyIssuer, issuer)

with async_mock.patch.object(
test_module.IssuerCredRevRecord,
"retrieve_by_cred_ex_id",
async_mock.CoroutineMock(),
) as mock_retrieve, async_mock.patch.object(
test_module, "IndyRevocation", autospec=True
) as revoc, async_mock.patch.object(
test_module.IssuerRevRegRecord,
"retrieve_by_id",
async_mock.CoroutineMock(return_value=mock_issuer_rev_reg_record),
):
mock_retrieve.return_value = async_mock.MagicMock(
rev_reg_id="dummy-rr-id", cred_rev_id=CRED_REV_ID
)
mock_rev_reg = async_mock.MagicMock(
get_or_fetch_local_tails_path=async_mock.CoroutineMock()
)
revoc.return_value.get_issuer_rev_reg_record = async_mock.CoroutineMock(
return_value=mock_issuer_rev_reg_record
)
revoc.return_value.get_ledger_registry = async_mock.CoroutineMock(
return_value=mock_rev_reg
)

await self.manager.revoke_credential_by_cred_ex_id(
cred_ex_id=CRED_EX_ID,
publish=True,
connection_id=conn_id,
write_ledger=False,
)

issuer.revoke_credentials.assert_awaited_once_with(
mock_issuer_rev_reg_record.cred_def_id,
mock_issuer_rev_reg_record.revoc_reg_id,
mock_issuer_rev_reg_record.tails_local_path,
["2", "1"],
)

async def test_revoke_credential_publish_endorser_x(self):
CRED_EX_ID = "dummy-cxid"
CRED_REV_ID = "1"
mock_issuer_rev_reg_record = async_mock.MagicMock(
revoc_reg_id=REV_REG_ID,
tails_local_path=TAILS_LOCAL,
send_entry=async_mock.CoroutineMock(),
clear_pending=async_mock.CoroutineMock(),
pending_pub=["2"],
)
issuer = async_mock.MagicMock(IndyIssuer, autospec=True)
issuer.revoke_credentials = async_mock.CoroutineMock(
return_value=(
json.dumps(
{
"ver": "1.0",
"value": {
"prevAccum": "1 ...",
"accum": "21 ...",
"issued": [1],
},
}
),
[],
)
)
self.profile.context.injector.bind_instance(IndyIssuer, issuer)

with async_mock.patch.object(
test_module.IssuerCredRevRecord,
"retrieve_by_cred_ex_id",
async_mock.CoroutineMock(),
) as mock_retrieve, async_mock.patch.object(
test_module, "IndyRevocation", autospec=True
) as revoc, async_mock.patch.object(
test_module.IssuerRevRegRecord,
"retrieve_by_id",
async_mock.CoroutineMock(return_value=mock_issuer_rev_reg_record),
):
mock_retrieve.return_value = async_mock.MagicMock(
rev_reg_id="dummy-rr-id", cred_rev_id=CRED_REV_ID
)
mock_rev_reg = async_mock.MagicMock(
get_or_fetch_local_tails_path=async_mock.CoroutineMock()
)
revoc.return_value.get_issuer_rev_reg_record = async_mock.CoroutineMock(
return_value=mock_issuer_rev_reg_record
)
revoc.return_value.get_ledger_registry = async_mock.CoroutineMock(
return_value=mock_rev_reg
)
with self.assertRaises(RevocationManagerError):
await self.manager.revoke_credential_by_cred_ex_id(
cred_ex_id=CRED_EX_ID,
publish=True,
connection_id="invalid_conn_id",
write_ledger=False,
)

async def test_revoke_cred_by_cxid_not_found(self):
CRED_EX_ID = "dummy-cxid"

Expand Down
Loading