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: Ledger error when registering nym after multi-ledger switch #2496

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 10 additions & 1 deletion aries_cloudagent/config/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from ..ledger.base import BaseLedger
from ..ledger.endpoint_type import EndpointType
from ..ledger.error import LedgerError
from ..multitenant.base import BaseMultitenantManager
from ..utils.http import fetch, FetchError
from ..wallet.base import BaseWallet

Expand Down Expand Up @@ -137,7 +138,15 @@ async def ledger_config(
async with ledger:
# Check transaction author agreement acceptance
if not ledger.read_only:
taa_info = await ledger.get_txn_author_agreement()
multitenant_mgr = session.inject_or(BaseMultitenantManager)
if multitenant_mgr:
subwallet = session.inject(BaseWallet)
sign_did_info = await subwallet.get_public_did()
taa_info = await ledger.get_txn_author_agreement(
sign_did_info=sign_did_info
)
else:
taa_info = await ledger.get_txn_author_agreement()
if taa_info["taa_required"] and public_did:
taa_accepted = await ledger.get_latest_txn_author_acceptance()
if (
Expand Down
11 changes: 11 additions & 0 deletions aries_cloudagent/config/multi_ledger_config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
- id: bcovrin1
is_production: true
is_write: true
genesis_url: 'http://test.bcovrin.vonx.io/genesis'
endorser_did: '8nFG9mvdT44tBh3wksrYXD'
endorser_alias: 'endorser_1'
- id: bcovrin2
is_write: true
genesis_url: 'http://dev.bcovrin.vonx.io/genesis'
endorser_did: 'L9b2uHgsabypjMmhF6xREm'
endorser_alias: 'endorser_2'
75 changes: 71 additions & 4 deletions aries_cloudagent/config/wallet.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
"""Wallet configuration."""

import logging
from typing import Tuple
import json

from typing import Tuple, Mapping, Any

from ..core.error import ProfileNotFoundError
from ..core.profile import Profile, ProfileManager, ProfileSession
from ..storage.base import BaseStorage
from ..storage.error import StorageNotFoundError
from ..ledger.base import BaseLedger
from ..storage.base import BaseStorage, StorageRecord
from ..storage.error import (
StorageNotFoundError,
StorageDuplicateError,
StorageError,
)
from ..version import RECORD_TYPE_ACAPY_VERSION, __version__
from ..wallet.base import BaseWallet
from ..wallet.crypto import seed_to_did
Expand All @@ -29,6 +36,63 @@
}


def is_multi_ledger(settings: Mapping[str, Any]) -> bool:
"""Check whether mutli-ledger mode is enabled."""
if (
settings.get_value("ledger.ledger_config_list")
and len(settings.get_value("ledger.ledger_config_list")) >= 1
):
return True
return False


async def update_public_did_ledger_id_map(
session,
info: DIDInfo,
config: dict,
):
"""Add or update acapy_ledger_public_did_map storage record."""
_curr_write_ledger = session.inject_or(BaseLedger)
storage = session.inject_or(BaseStorage)
ledger_id = config.get("ledger_pool_name") or _curr_write_ledger.pool_name
record_type_ledger_did_map = (
config.get("record_type_name") or "acapy_ledger_public_did_map"
)
try:
ledger_id_public_did_map_record: StorageRecord = await storage.find_record(
type_filter=record_type_ledger_did_map, tag_query={}
)
ledger_id_public_did_map = json.loads(ledger_id_public_did_map_record.value)
ledger_id_public_did_map[ledger_id] = {
"did": info.did,
"routing_keys": config.get("routing_keys"),
"mediation_endpoint": config.get("mediator_endpoint"),
"connection_id": config.get("connection_id"),
"write_ledger": config.get("write_ledger"),
}
await storage.update_record(
ledger_id_public_did_map_record,
json.dumps(ledger_id_public_did_map),
{},
)
except (StorageError, StorageNotFoundError, StorageDuplicateError):
ledger_id_public_did_map = {
ledger_id: {
"did": info.did,
"routing_keys": config.get("routing_keys"),
"mediation_endpoint": config.get("mediator_endpoint"),
"connection_id": config.get("connection_id"),
"write_ledger": config.get("write_ledger"),
}
}
record = StorageRecord(
record_type_ledger_did_map,
json.dumps(ledger_id_public_did_map),
{},
)
await storage.add_record(record)


async def wallet_config(
context: InjectionContext, provision: bool = False
) -> Tuple[Profile, DIDInfo]:
Expand Down Expand Up @@ -110,7 +174,10 @@ async def wallet_config(
print(f"Verkey: {local_did_info.verkey}")
else:
public_did_info = await wallet.create_public_did(
method=SOV, key_type=ED25519, seed=wallet_seed
method=SOV,
key_type=ED25519,
seed=wallet_seed,
context=context,
)
public_did = public_did_info.did
if provision:
Expand Down
24 changes: 19 additions & 5 deletions aries_cloudagent/indy/credx/holder.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

from ...askar.profile import AskarProfile
from ...ledger.base import BaseLedger
from ...multitenant.base import BaseMultitenantManager
from ...wallet.base import BaseWallet
from ...wallet.error import WalletNotFoundError

from ..holder import IndyHolder, IndyHolderError
Expand Down Expand Up @@ -389,11 +391,23 @@ async def credential_revoked(

if rev_reg_id:
cred_rev_id = cred.rev_reg_index
(rev_reg_delta, _) = await ledger.get_revoc_reg_delta(
rev_reg_id,
fro,
to,
)
async with self._profile.session() as session:
multitenant_mgr = session.inject_or(BaseMultitenantManager)
if multitenant_mgr:
subwallet = session.inject(BaseWallet)
sign_did_info = await subwallet.get_public_did()
(rev_reg_delta, _) = await ledger.get_revoc_reg_delta(
rev_reg_id,
fro,
to,
sign_did_info,
)
else:
(rev_reg_delta, _) = await ledger.get_revoc_reg_delta(
rev_reg_id,
fro,
to,
)
return cred_rev_id in rev_reg_delta["value"].get("revoked", [])
else:
return False
Expand Down
60 changes: 41 additions & 19 deletions aries_cloudagent/ledger/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ def read_only(self) -> bool:
"""Accessor for the ledger read-only flag."""

@abstractmethod
async def is_ledger_read_only(self) -> bool:
async def is_ledger_read_only(self, sign_did_info: DIDInfo = None) -> bool:
"""Check if ledger is read-only including TAA."""

@abstractmethod
async def get_key_for_did(self, did: str) -> str:
async def get_key_for_did(self, did: str, sign_did_info: DIDInfo = None) -> str:
"""Fetch the verkey for a ledger DID.

Args:
Expand All @@ -67,7 +67,10 @@ async def get_key_for_did(self, did: str) -> str:

@abstractmethod
async def get_endpoint_for_did(
self, did: str, endpoint_type: EndpointType = EndpointType.ENDPOINT
self,
did: str,
endpoint_type: EndpointType = EndpointType.ENDPOINT,
sign_did_info: DIDInfo = None,
) -> str:
"""Fetch the endpoint for a ledger DID.

Expand All @@ -77,7 +80,9 @@ async def get_endpoint_for_did(
"""

@abstractmethod
async def get_all_endpoints_for_did(self, did: str) -> dict:
async def get_all_endpoints_for_did(
self, did: str, sign_did_info: DIDInfo = None
) -> dict:
"""Fetch all endpoints for a ledger DID.

Args:
Expand Down Expand Up @@ -142,6 +147,7 @@ async def register_nym(
role: str = None,
write_ledger: bool = True,
endorser_did: str = None,
sign_did_info: DIDInfo = None,
) -> Tuple[bool, dict]:
"""Register a nym on the ledger.

Expand All @@ -153,7 +159,7 @@ async def register_nym(
"""

@abstractmethod
async def get_nym_role(self, did: str):
async def get_nym_role(self, did: str, sign_did_info: DIDInfo = None):
"""Return the role registered to input public DID on the ledger.

Args:
Expand All @@ -165,7 +171,9 @@ def nym_to_did(self, nym: str) -> str:
"""Format a nym with the ledger's DID prefix."""

@abstractmethod
async def rotate_public_did_keypair(self, next_seed: str = None) -> None:
async def rotate_public_did_keypair(
self, next_seed: str = None, sign_did_info: DIDInfo = None
) -> None:
"""Rotate keypair for public DID: create new key, submit to ledger, update wallet.

Args:
Expand All @@ -182,11 +190,13 @@ async def get_wallet_public_did(self) -> DIDInfo:
"""Fetch the public DID from the wallet."""

@abstractmethod
async def get_txn_author_agreement(self, reload: bool = False):
async def get_txn_author_agreement(
self, reload: bool = False, sign_did_info: DIDInfo = None
):
"""Get the current transaction author agreement, fetching it if necessary."""

@abstractmethod
async def fetch_txn_author_agreement(self):
async def fetch_txn_author_agreement(self, sign_did_info: DIDInfo = None):
"""Fetch the current AML and TAA from the ledger."""

@abstractmethod
Expand Down Expand Up @@ -226,7 +236,9 @@ async def txn_submit(
"""Write the provided (signed and possibly endorsed) transaction to the ledger."""

@abstractmethod
async def fetch_schema_by_id(self, schema_id: str) -> dict:
async def fetch_schema_by_id(
self, schema_id: str, sign_did_info: DIDInfo = None
) -> dict:
"""Get schema from ledger.

Args:
Expand Down Expand Up @@ -255,10 +267,11 @@ async def check_existing_schema(
schema_name: str,
schema_version: str,
attribute_names: Sequence[str],
sign_did_info: DIDInfo = None,
) -> Tuple[str, dict]:
"""Check if a schema has already been published."""
fetch_schema_id = f"{public_did}:2:{schema_name}:{schema_version}"
schema = await self.fetch_schema_by_id(fetch_schema_id)
schema = await self.fetch_schema_by_id(fetch_schema_id, sign_did_info)
if schema:
fetched_attrs = schema["attrNames"].copy()
fetched_attrs.sort()
Expand All @@ -279,6 +292,7 @@ async def create_and_send_schema(
attribute_names: Sequence[str],
write_ledger: bool = True,
endorser_did: str = None,
sign_did_info: DIDInfo = None,
) -> Tuple[str, dict]:
"""Send schema to ledger.

Expand All @@ -290,7 +304,7 @@ async def create_and_send_schema(

"""

public_info = await self.get_wallet_public_did()
public_info = sign_did_info or await self.get_wallet_public_did()
if not public_info:
raise BadLedgerRequestError("Cannot publish schema without a public DID")

Expand All @@ -306,7 +320,7 @@ async def create_and_send_schema(
LOGGER.warning("Schema already exists on ledger. Returning details.")
schema_id, schema_def = schema_info
else:
if await self.is_ledger_read_only():
if await self.is_ledger_read_only(sign_did_info):
raise LedgerError(
"Error cannot write schema when ledger is in read only mode, "
"or TAA is required and not accepted"
Expand Down Expand Up @@ -383,7 +397,9 @@ async def _create_schema_request(
"""Create the ledger request for publishing a schema."""

@abstractmethod
async def get_revoc_reg_def(self, revoc_reg_id: str) -> dict:
async def get_revoc_reg_def(
self, revoc_reg_id: str, sign_did_info: DIDInfo = None
) -> dict:
"""Look up a revocation registry definition by ID."""

@abstractmethod
Expand Down Expand Up @@ -417,6 +433,7 @@ async def create_and_send_credential_definition(
support_revocation: bool = False,
write_ledger: bool = True,
endorser_did: str = None,
sign_did_info: DIDInfo = None,
) -> Tuple[str, dict, bool]:
"""Send credential definition to ledger and store relevant key matter in wallet.

Expand All @@ -431,7 +448,7 @@ async def create_and_send_credential_definition(
Tuple with cred def id, cred def structure, and whether it's novel

"""
public_info = await self.get_wallet_public_did()
public_info = sign_did_info or await self.get_wallet_public_did()
if not public_info:
raise BadLedgerRequestError(
"Cannot publish credential definition without a public DID"
Expand All @@ -449,7 +466,8 @@ async def create_and_send_credential_definition(
public_info.did, schema, signature_type, test_tag
)
ledger_cred_def = await self.fetch_credential_definition(
credential_definition_id
credential_definition_id,
sign_did_info,
)
if ledger_cred_def:
LOGGER.warning(
Expand Down Expand Up @@ -501,7 +519,7 @@ async def create_and_send_credential_definition(
except IndyIssuerError as err:
raise LedgerError(err.message) from err

if await self.is_ledger_read_only():
if await self.is_ledger_read_only(sign_did_info):
raise LedgerError(
"Error cannot write cred def when ledger is in read only mode, "
"or TAA is required and not accepted"
Expand Down Expand Up @@ -543,12 +561,16 @@ async def get_credential_definition(self, credential_definition_id: str) -> dict

@abstractmethod
async def get_revoc_reg_delta(
self, revoc_reg_id: str, timestamp_from=0, timestamp_to=None
self,
revoc_reg_id: str,
timestamp_from=0,
timestamp_to=None,
sign_did_info: DIDInfo = None,
) -> Tuple[dict, int]:
"""Look up a revocation registry delta by ID."""

@abstractmethod
async def get_schema(self, schema_id: str) -> dict:
async def get_schema(self, schema_id: str, sign_did_info: DIDInfo = None) -> dict:
"""Get a schema from the cache if available, otherwise fetch from the ledger.

Args:
Expand All @@ -558,7 +580,7 @@ async def get_schema(self, schema_id: str) -> dict:

@abstractmethod
async def get_revoc_reg_entry(
self, revoc_reg_id: str, timestamp: int
self, revoc_reg_id: str, timestamp: int, sign_did_info: DIDInfo = None
) -> Tuple[dict, int]:
"""Get revocation registry entry by revocation registry ID and timestamp."""

Expand Down
Loading
Loading