# aca-py endorsement >= 0.7.4
Upgrading aca-py version to >= 0.7.4 breaks endorsement in the YOMA cloudapi, and possibly in general compared how it was implemented up to and including 0.7.3.
## Attempted debugs and fixes
For all of the fixes tried aries_cloudcontroller version has been bumped from `0.5.3` to `0.6.3`
NOTE: Many tests fail likely to the same underlying problem so I've been looking at test_connections.py in the e2e folder.
1. `test_accept_invitation_oob` is fixable by using 0.7.5 which fixes the return type of the invite to OObRecord so adding an oob webhook listener is the solution. Then one can listen to that instead of ConnectionRecord. Opened a PR for this which correctly fails as 0.7.5 is not yet available on pypi [corresponding PR](https://github.com/didx-xyz/aries-cloudapi-python/pull/260). This has been tested to work when using 0.7.5 and main:latest from github, building and passing that into the container locally.
2. `test_oob_connect_via_public_did` is not fixable this way and the subject to fixing for the tries described below. I assumed that fixing this will largely lead to fixing everything else.
### 1. Upgrade to 0.7.4
Simply upgrading `aries-cloudagent-python` to `0.7.4`
```bash
aiohttp.client_exceptions.ClientResponseError: 400, message='No endorser connection found', url=URL('http://localhost:4021/wallet/did/public?did=AE6mNovM6bwFJJsQkfNaMx')
```
so there is no endorser connection for the subwallet.
* Seems to be [buggy with respect to OOB](https://github.com/hyperledger/aries-cloudagent-python/issues/1936)
***Further assumption: Use latest due to it containing bug fixes for endorser so skip to 3.***
#### Attempted fixes
1. set `ACAPY_AUTO_ENDORSE_TRANSACTIONS=true` on ga-agent
* same error
2. manually setting up an endorser connection
### 2. Upgrade to 0.7.5-rc0
Simply upgrading `aries-cloudagent-python` to `0.7.5-rc0`
```bash
aiohttp.client_exceptions.ClientResponseError: 400, message='No endorser connection found', url=URL('http://localhost:4021/wallet/did/public?did=AE6mNovM6bwFJJsQkfNaMx')
```
so there is no endorser connection for the subwallet.
***Further assumption: Use latest due to it containing bug fixes for endorser so skip to 3.***
### 3. Upgrade to github `main/latest`
Simply upgrading `aries-cloudagent-python` to `main` (GH)
```bash
aiohttp.client_exceptions.ClientResponseError: 400, message='No endorser connection found', url=URL('http://localhost:4021/wallet/did/public?did=AE6mNovM6bwFJJsQkfNaMx')
```
so there is no endorser connection for the subwallet.
1. In order to fix this (`test_oob_connect_via_public_did`) the problem is that there seems to be no endorser connection (so we establish this in the onboarding) and try generate and write a public did for the tenant wallet via the endorser to the ledger. That is just as described in [this PR](https://github.com/hyperledger/aries-cloudagent-python/issues/1929). You can check out `wip/debug-endorser-0.7.5` branch of the cloudapi repo which has this setup (but is still failing).
* In the onboarding create a connection (OOB) between tenant and endorser. Then set the endorsement info respectively:
```python
await endorser_controller.endorse_transaction.set_endorser_role(
conn_id=endorser_connection["connection_id"],
transaction_my_job="TRANSACTION_ENDORSER",
)
await issuer_controller.endorse_transaction.set_endorser_role(
conn_id=connection_record.connection_id, transaction_my_job="TRANSACTION_AUTHOR"
)
# Make sure endorsement has been configured
# There is currently no way to retrieve endorser info. We'll just set it
# to make sure the endorser info is set.
await issuer_controller.endorse_transaction.set_endorser_info(
conn_id=connection_record.connection_id,
endorser_did=endorser_did.did,
)
```
* Registering the nym on ledger fails:
```python
try:
issuer_did = await acapy_wallet.get_public_did(controller=issuer_controller)
except CloudApiException:
# no public did
issuer_did = await acapy_wallet.create_did(issuer_controller)
txn = await acapy_ledger.register_nym_on_ledger(
endorser_controller,
# connection_id=endorser_connection["connection_id"],
did=issuer_did.did,
verkey=issuer_did.verkey,
alias=name,
# create_transaction_for_endorser=True
role="ENDORSER"
)
# await endorser_controller.endorse_transaction.endorse_transaction(tran_id=txn.txn.transaction_id)
await acapy_ledger.accept_taa_if_required(issuer_controller)
await acapy_wallet.set_public_did(issuer_controller, issuer_did.did)
```
with:
```bash
'http://governance-ga-agent:3021/ledger/register-nym?did=XvCpu3b8TRqWgdpQuMYSGV&verkey=HrMiC1FYPN2Vo7jUaFqeXs2yib1a9g3P4PLJ9iAnmLUg&alias=faberAMX&role=ENDORSER\')), (), status=403, message=\\"Ledger request error. Request failed: client request invalid: UnauthorizedClientRequest(\'9dxXsBkgbngBiNcsfRdZsM\', 1666087966627606971, \'Rule for this action is: 1 STEWARD signature is required OR 1 TRUSTEE signature is required\\\\\\\\nFailed checks:\\\\\\\\nConstraint: 1 STEWARD signature is required, Error: Not enough STEWARD signatures\\\\\\\\nConstraint: 1 TRUSTEE signature is required, Error: Not enough TRUSTEE signatures\')
```
* This seems silly because auto endorseing transactions is set to true
* if we remove `role="ENDORSER"` we get the folowing error instead:
```bash
Exception: ('Error creating issuer tenant', '{"detail":"Error setting public did: FyDsBciJyrNRYp3FWAjH53"}')
```
* Adding `create_transaction_for_endorser=true`:
```
real_url=URL(\'http://governance-ga-agent:3021/ledger/register-nym?did=QLQ3LYuz7ErXptE6YpCCtu&verkey=DieZC7wGRCL1wjZ5hML6yub3aJYo1D66ukrxYGSZYFnW&alias=faberLOO&create_transaction_for_endorser=true\')), (), status=500, message=\'Internal Server Error\
```
with aca-py ga-agent providing some more detail:
```
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/asyncio/tasks.py", line 250, in _wakeup
future.result()
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/asyncio/tasks.py", line 180, in _step
result = coro.send(None)
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aries_cloudagent/ledger/routes.py", line 275, in register_ledger_nym
session, connection_id
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aries_cloudagent/messaging/models/base_record.py", line 239, in retrieve_by_id
cls.RECORD_TYPE, record_id, {"forUpdate": for_update, "retrieveTags": False}
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aries_cloudagent/storage/askar.py", line 86, in get_record
raise StorageError("Record ID not provided")
aries_cloudagent.storage.error.StorageError: Record ID not provided
2022-10-18 10:44:09,588 aiohttp.server ERROR Error handling request
Traceback (most recent call last):
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aiohttp/web_protocol.py", line 433, in _handle_request
resp = await request_handler(request)
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aiohttp/web_app.py", line 504, in _handle
resp = await handler(request)
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aiohttp/web_middlewares.py", line 117, in impl
return await handler(request)
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aries_cloudagent/admin/server.py", line 170, in ready_middleware
return await handler(request)
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aries_cloudagent/admin/server.py", line 207, in debug_middleware
return await handler(request)
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aiohttp_apispec/middlewares.py", line 45, in validation_middleware
return await handler(request)
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aries_cloudagent/admin/server.py", line 304, in check_token
return await handler(request)
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aries_cloudagent/admin/server.py", line 395, in setup_context
return await task
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/asyncio/tasks.py", line 250, in _wakeup
future.result()
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/asyncio/tasks.py", line 180, in _step
result = coro.send(None)
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aries_cloudagent/ledger/routes.py", line 275, in register_ledger_nym
session, connection_id
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aries_cloudagent/messaging/models/base_record.py", line 239, in retrieve_by_id
cls.RECORD_TYPE, record_id, {"forUpdate": for_update, "retrieveTags": False}
File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aries_cloudagent/storage/askar.py", line 86, in get_record
raise StorageError("Record ID not provided")
aries_cloudagent.storage.error.StorageError: Record ID not provided
```
Not sure what's going on with the Record ID there.
* Setting `connection_id=endorser_connection["connection_id"]` changes the error to:
```bash
real_url=URL(\'http://governance-ga-agent:3021/ledger/register-nym?did=6BxBst5wZwkSBj3P3xpvkq&verkey=3q2ftZgimV4DzuQWVBPKJ6DZoStAo9UFbJtaM4omXsLL&alias=faberTHC&conn_id=83206627-386a-40bb-8c88-87d0d368081f&create_transaction_for_endorser=true\')), (), status=403, message=\'Endorser Info is not set up in connection metadata for this connection record\'
```
* We can also try the tenant connection id giving `Record not found` - no surprise there
* Then with:
```python
txn = await acapy_ledger.register_nym_on_ledger(
endorser_controller,
connection_id=endorser_connection["connection_id"],
did=issuer_did.did,
verkey=issuer_did.verkey,
alias=name,
create_transaction_for_endorser=True,
role="ENDORSER"
)
```
yielding:
```bash
real_url=URL(\'http://governance-ga-agent:3021/ledger/register-nym?did=33BFjMKaTVDRAUGuUuZ2JP&verkey=27QoUrqTHEhsyPHzg29ggSpQbrWFiNK1FAxJgmHmthct&alias=faberSMU&conn_id=af664809-eecc-4bda-8368-b09dc20e834f&create_transaction_for_endorser=true&role=ENDORSER\')), (), status=403, message=\'Endorser Info is not set up in connection metadata for this connection record\',
```
* And finally trying the issuer_controller instead of the endorser controller to create a transaction record intead of writing it (so that the endorser could sign the transaction record and then write it):
```python
txn = await acapy_ledger.register_nym_on_ledger(
issuer_controller,
connection_id=connection_record.connection_id,
did=issuer_did.did,
verkey=issuer_did.verkey,
alias=name,
create_transaction_for_endorser=True
# role="ENDORSER"
)
```
yielding:
```bash
real_url=URL(\'http://governance-multitenant-agent:3021/ledger/register-nym?did=FcjrYhFF4f4PR5QidcQVV5&verkey=8y3hQzTjpkaBRVTknxpYeB6GVLDch2AfroNkLKUsNk66&alias=faberRMY&conn_id=b3fb28e3-03d9-44f0-bd63-e57aed596e63&create_transaction_for_endorser=true\')), (), status=400, message=\'Cannot register NYM without a public DID.
```
* This sort of makes sense as obviously writing the public DID is what we try here in the frist place. However, it's sort of strange that we're not allowed to just create the transaction record (without actually performing the write).
Tried a gazzilion other ways as well but this is the main crux imho.
* There was also a way of producing DID has no associated documents which I cannot reproduce anymore atm.
* UPDATE 18/10/2022 afternoon: We can almost endorse the transaction but not quite:
with running:
```python
try:
issuer_did = await acapy_wallet.get_public_did(controller=issuer_controller)
except CloudApiException:
# no public did
issuer_did = await acapy_wallet.create_did(issuer_controller)
txn = await acapy_ledger.register_nym_on_ledger(
issuer_controller,
connection_id=connection_record.connection_id,
did=issuer_did.did,
verkey=issuer_did.verkey,
alias=name,
create_transaction_for_endorser=True
# role="STEWARD"
)
endorser_txns = await endorser_controller.endorse_transaction.get_records()
end_txn = endorser_txns.results[0]
await acapy_ledger.accept_taa_if_required(issuer_controller)
await endorser_controller.endorse_transaction.endorse_transaction(tran_id=end_txn.transaction_id)
await endorser_controller.endorse_transaction.write_transaction(tran_id=end_txn.transaction_id)
# await endorser_controller.endorse_transaction.endorse_transaction(tran_id=txn.txn.transaction_id)
await acapy_wallet.set_public_did(issuer_controller, issuer_did.did)
```
we obtain `Not enough TRUSTEE signatures`:
```bash
ClientResponseError(\\naiohttp.client_exceptions.ClientResponseError: 400, message=\\"Ledger request error. Request failed: client request invalid: UnauthorizedClientRequest(\'8NafWKTNYtwFCeFTdvcgZm\', 1666102933344750833, \'Not enough TRUSTEE signatures\').\\", url=URL(\'http://governance-ga-agent:3021/transactions/88ee9d4e-fed6-4e59-a272-268b6c7b8237/endorse\
```
### 4. Applicable to all
Both 2. and 3. updates contain some PRs regarding endorsement with bugfixes.
1. [1926](https://github.com/hyperledger/aries-cloudagent-python/pull/1926/files)
2. [1926 related issue 1929](https://github.com/hyperledger/aries-cloudagent-python/issues/1929)
1. The flow described here seems like what we're trying to do, but doesn't work for our setup even with this pr merged.
3. [PR 232 - also endorser fix](https://github.com/didx-xyz/aries-cloudapi-python/pull/232)
4. [also relevant discussion on PR 1926](https://github.com/hyperledger/aries-cloudagent-python/pull/1926#issuecomment-1235933758)