Skip to content

Commit 9b519cb

Browse files
authored
Merge branch 'main' into feature/keylist-webhooks
2 parents e180aa0 + 9fce18b commit 9b519cb

144 files changed

Lines changed: 7070 additions & 4507 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 91 additions & 33 deletions
Large diffs are not rendered by default.

DevReadMe.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ See the [README](README.md) for details about this repository and information ab
1818
- [Developing](#developing)
1919
- [Prerequisites](#prerequisites)
2020
- [Running Locally](#running-locally)
21+
- [Logging](#logging)
2122
- [Running Tests](#running-tests)
2223
- [Running Aries Agent Test Harness Tests](#running-aries-agent-test-harness-tests)
2324
- [Development Workflow](#development-workflow)

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@ An ACA-Py instance puts together an OpenAPI-documented REST interface based on t
7878

7979
Technical note: the administrative API exposed by the agent for the controller to use must be protected with an API key (using the --admin-api-key command line arg) or deliberately left unsecured using the --admin-insecure-mode command line arg. The latter should not be used other than in development if the API is not otherwise secured.
8080

81+
## Troubleshooting
82+
83+
There are a number of resources for getting help with ACA-Py and troubleshooting
84+
any problems you might run into. The [Troubleshooting](Troubleshooting.md)
85+
document contains some guidance about issues that have been experienced in the
86+
past. Feel free to submit PRs to supplement the troubleshooting document!
87+
Searching the [ACA-Py GitHub
88+
issues](https://github.com/hyperledger/aries-cloudagent-python/issues) will
89+
often uncover challenges that others have experienced, often with answers to
90+
solving those challenges. As well, there is the "aries-cloudagent-python"
91+
channel on the Hyperledger Discord chat server ([invitation
92+
here](https://discord.gg/hyperledger)).
93+
8194
## Credit
8295

8396
The initial implementation of ACA-Py was developed by the Government of British Columbia’s Digital Trust Team in Canada. To learn more about what’s happening with decentralized identity and digital trust in British Columbia, a new website will be launching and the link will be made available here.

Troubleshooting.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Troubleshooting Aries Cloud Agent Python <!-- omit in toc -->
2+
3+
This document contains some troubleshooting information that contributors to the
4+
community think may be helpful. Most of the content here assumes the reader has
5+
gotten started with ACA-Py and has arrived here because of an issue that came up
6+
in their use of ACA-Py.
7+
8+
Contributions (via pull request) to this document are welcome. Topics added here
9+
will mostly come from reported issues that contributors think would be helpful
10+
to the larger community.
11+
12+
## Table of Contents <!-- omit in toc -->
13+
14+
- [Unable to Connect to Ledger](#unable-to-connect-to-ledger)
15+
- [Local ledger running?](#local-ledger-running)
16+
- [Any Firewalls](#any-firewalls)
17+
- [Damaged, Unpublishable Revocation Registry](#damaged-unpublishable-revocation-registry)
18+
19+
## Unable to Connect to Ledger
20+
21+
The most common issue hit by first time users is getting an error on startup "unable to connect to ledger". Here are a list of things to check when you see that error.
22+
23+
### Local ledger running?
24+
25+
Unless you specify via startup parameters or environment variables that you are using a public Hyperledger Indy ledger, ACA-Py assumes that you are running a local ledger -- an instance of [von-network](https://github.com/bcgov/von-network).
26+
If that is the cause -- have you started your local ledger, and did it startup properly. Things to check:
27+
28+
- Any errors in the startup of von-network?
29+
- Is the von-network webserver (usually at `https:/localhost:9000`) accessible? If so, can you click on and see the Genesis File?
30+
- Do you even need a local ledger? If not, you can use a public sandbox ledger,
31+
such as the [Dev Greenlight ledger](), likely by just prefacing your ACA-Py
32+
command with `LEDGER_URL=http://dev.greenlight.bcovrin.vonx.io`. For example,
33+
when running the Alice-Faber demo in the [demo](demo) folder, you can run (for
34+
example), the Faber agent using the command:
35+
`LEDGER_URL=http://dev.greenlight.bcovrin.vonx.io ./run_demo faber`
36+
37+
### Any Firewalls
38+
39+
Do you have any firewalls in play that might be blocking the ports that are used by the ledger, notably 9701-9708? To access a ledger
40+
the ACA-Py instance must be able to get to those ports of the ledger, regardless if the ledger is local or remote.
41+
42+
## Damaged, Unpublishable Revocation Registry
43+
44+
We have discovered that in the ACA-Py AnonCreds implementation, it is possible
45+
to get into a state where the publishing of updates to a Revocation Registry
46+
(RevReg) is impossible. This can happen where ACA-Py starts to publish an update
47+
to the RevReg, but the write transaction to the Hyperledger Indy ledger fails
48+
for some reason. When a credential revocation is published, aca-py (via indy-sdk
49+
or askar/credx) updates the revocation state in the wallet as well as on the
50+
ledger. The revocation state is dependant on whatever the previous revocation
51+
state is/was, so if the ledger and wallet are mis-matched the publish will fail.
52+
(Andrew/s PR # 1804 (merged) should mitigate but probably won't completely
53+
eliminate this from happening).
54+
55+
For example, in case we've seen, the write RevRegEntry transaction failed at the
56+
ledger because there was a problem with accepting the TAA (Transaction Author
57+
Agreement). Once the error occurred, the RevReg state held by the ACA-Py agent,
58+
and the RevReg state on the ledger were different. Even after the ability to
59+
write to the ledger was restored, the RevReg could still not be published
60+
because of the differences in the RevReg state. Such a situation can now be
61+
corrected, as follows:
62+
63+
To address this issue, some new endpoints were added to ACA-Py in Release 0.7.4,
64+
as follows:
65+
66+
- GET `/revocation/registry/<id>/issued` - counts of the number of issued/revoked
67+
within a registry
68+
- GET `/revocation/registry/<id>/issued/details` - details of all credentials
69+
issued/revoked within a registry
70+
- GET `/revocation/registry/<id>/issued/indy_recs` - calculated rev_reg_delta from
71+
the ledger
72+
- This is used to compare ledger revoked vs wallet revoked credentials, which
73+
is essentially the state of the RevReg on the ledger and in ACA-Py. Where
74+
there is a difference, we have an error.
75+
- PUT `/revocation/registry/<id>/fix-revocation-entry-state` - publish an update
76+
to the RevReg state on the ledger to bring it into alignment with what is in
77+
the ACA-Py instance.
78+
- There is a boolean parameter (`apply_ledger_update`) to control whether the
79+
ledger entry actually gets published so, if you are so inclined, you can
80+
call the endpoint to see what the transaction would be, before you actually
81+
try to do a ledger update. This will return:
82+
- `rev_reg_delta` - same as the ".../indy_recs" endpoint
83+
- `accum_calculated` - transaction to write to ledger
84+
- `accum_fixed` - If `apply_ledger_update`, the transaction actually written
85+
to the ledger
86+
87+
Note that there is (currently) a backlog item to prevent the wallet and ledger
88+
from getting out of sync (e.g. don't update the ACA-Py RevReg state if the
89+
ledger write fails), but even after that change is made, having this ability
90+
will be retained for use if needed.
91+
92+
We originally ran into this due to the TAA acceptance getting lost when
93+
switching to multi-ledger (as described
94+
[here](https://github.com/hyperledger/aries-cloudagent-python/blob/main/Multiledger.md#a-special-warning-for-taa-acceptance).
95+
Note that this is one reason how this "out of sync" scenario can occur, but
96+
there may be others.
97+
98+
We add an integration test that demonstrates/tests this issue [here](https://github.com/hyperledger/aries-cloudagent-python/blob/main/demo/features/taa-txn-author-acceptance.feature#L67).
99+
100+
To run the scenario either manually or using the integration tests, you can do the following:
101+
102+
- Start von-network in TAA mode:
103+
- `./manage start --taa-sample --logs`
104+
- Start the tails server as usual:
105+
- `./manage start --logs`
106+
- To run the scenario manually, start faber and let the agent know it needs to TAA-accept before doing any ledger writes:
107+
- `./run_demo faber --revocation --taa-accept`, and then you can run through all the transactions using the Swagger page.
108+
- To run the scenario via an integration test, run:
109+
- `./run_bdd -t @taa_required`

aries_cloudagent/config/logging.py

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -113,47 +113,53 @@ def print_banner(
113113

114114
# Inbound transports
115115
banner.print_subtitle("Inbound Transports")
116-
banner.print_spacer()
117-
banner.print_list(
118-
[
119-
f"{transport.scheme}://{transport.host}:{transport.port}"
120-
for transport in inbound_transports.values()
121-
]
122-
)
123-
banner.print_spacer()
124-
125-
external_in_transports = set().union(
126-
*(
127-
transport
128-
for transport in inbound_transports.values()
129-
if transport.is_external
130-
)
131-
)
116+
internal_in_transports = [
117+
f"{transport.scheme}://{transport.host}:{transport.port}"
118+
for transport in inbound_transports.values()
119+
if not transport.is_external
120+
]
121+
if internal_in_transports:
122+
banner.print_spacer()
123+
banner.print_list(internal_in_transports)
124+
banner.print_spacer()
125+
external_in_transports = [
126+
f"{transport.scheme}://{transport.host}:{transport.port}"
127+
for transport in inbound_transports.values()
128+
if transport.is_external
129+
]
132130
if external_in_transports:
133131
banner.print_spacer()
134-
banner.print_list([f"{external_in_transports}"])
132+
banner.print_subtitle(" External Plugin")
133+
banner.print_spacer()
134+
banner.print_list(external_in_transports)
135135
banner.print_spacer()
136136

137137
# Outbound transports
138-
schemes = set().union(
139-
*(transport.schemes for transport in outbound_transports.values())
138+
banner.print_subtitle("Outbound Transports")
139+
internal_schemes = set().union(
140+
*(
141+
transport.schemes
142+
for transport in outbound_transports.values()
143+
if not transport.is_external
144+
)
140145
)
141-
if schemes:
142-
banner.print_subtitle("Outbound Transports")
146+
if internal_schemes:
143147
banner.print_spacer()
144-
banner.print_list([f"{scheme}" for scheme in sorted(schemes)])
148+
banner.print_list([f"{scheme}" for scheme in sorted(internal_schemes)])
145149
banner.print_spacer()
146150

147-
external_out_transports = set().union(
151+
external_schemes = set().union(
148152
*(
149-
transport
153+
transport.schemes
150154
for transport in outbound_transports.values()
151155
if transport.is_external
152156
)
153157
)
154-
if external_out_transports:
158+
if external_schemes:
159+
banner.print_spacer()
160+
banner.print_subtitle(" External Plugin")
155161
banner.print_spacer()
156-
banner.print_list([f"{external_out_transports}"])
162+
banner.print_list([f"{scheme}" for scheme in sorted(external_schemes)])
157163
banner.print_spacer()
158164

159165
# DID info

aries_cloudagent/core/conductor.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
from ..vc.ld_proofs.document_loader import DocumentLoader
6464
from ..version import __version__, RECORD_TYPE_ACAPY_VERSION
6565
from ..wallet.did_info import DIDInfo
66+
from .oob_processor import OobMessageProcessor
6667

6768
from .dispatcher import Dispatcher
6869
from .util import STARTUP_EVENT_TOPIC, SHUTDOWN_EVENT_TOPIC
@@ -203,6 +204,13 @@ async def setup(self):
203204
BaseMultitenantManager, MultitenantManagerProvider(self.root_profile)
204205
)
205206

207+
# Bind oob message processor to be able to receive and process un-encrypted
208+
# messages
209+
context.injector.bind_instance(
210+
OobMessageProcessor,
211+
OobMessageProcessor(inbound_message_router=self.inbound_message_router),
212+
)
213+
206214
# Bind default PyLD document loader
207215
context.injector.bind_instance(
208216
DocumentLoader, DocumentLoader(self.root_profile)
@@ -636,8 +644,10 @@ async def queue_outbound(
636644
message: An outbound message to be sent
637645
inbound: The inbound message that produced this response, if available
638646
"""
647+
has_target = outbound.target or outbound.target_list
648+
639649
# populate connection target(s)
640-
if not outbound.target and not outbound.target_list and outbound.connection_id:
650+
if not has_target and outbound.connection_id:
641651
conn_mgr = ConnectionManager(profile)
642652
try:
643653
outbound.target_list = await self.dispatcher.run_task(
@@ -654,6 +664,15 @@ async def queue_outbound(
654664
self.admin_server.notify_fatal_error()
655665
raise
656666
del conn_mgr
667+
# Find oob/connectionless target we can send the message to
668+
elif not has_target and outbound.reply_thread_id:
669+
message_processor = profile.inject(OobMessageProcessor)
670+
outbound.target = await self.dispatcher.run_task(
671+
message_processor.find_oob_target_for_outbound_message(
672+
profile, outbound
673+
)
674+
)
675+
657676
return await self._queue_message(profile, outbound)
658677

659678
async def _queue_message(

aries_cloudagent/core/dispatcher.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
from aiohttp.web import HTTPException
1616

17+
18+
from ..connections.models.conn_record import ConnRecord
1719
from ..core.profile import Profile
1820
from ..messaging.agent_message import AgentMessage
1921
from ..messaging.base_message import BaseMessage
@@ -173,11 +175,20 @@ async def handle_message(
173175

174176
context.injector.bind_instance(BaseResponder, responder)
175177

176-
connection_mgr = ConnectionManager(profile)
177-
connection = await connection_mgr.find_inbound_connection(
178-
inbound_message.receipt
179-
)
180-
del connection_mgr
178+
# When processing oob attach message we supply the connection id
179+
# associated with the inbound message
180+
if inbound_message.connection_id:
181+
async with self.profile.session() as session:
182+
connection = await ConnRecord.retrieve_by_id(
183+
session, inbound_message.connection_id
184+
)
185+
else:
186+
connection_mgr = ConnectionManager(profile)
187+
connection = await connection_mgr.find_inbound_connection(
188+
inbound_message.receipt
189+
)
190+
del connection_mgr
191+
181192
if connection:
182193
inbound_message.connection_id = connection.connection_id
183194

0 commit comments

Comments
 (0)