diff --git a/acapy_agent/askar/profile.py b/acapy_agent/askar/profile.py index e562ff88ff..bbc1881007 100644 --- a/acapy_agent/askar/profile.py +++ b/acapy_agent/askar/profile.py @@ -41,15 +41,27 @@ def __init__( *, profile_id: Optional[str] = None, ): - """Create a new AskarProfile instance.""" + """Private constructor. Use 'create' to instantiate.""" super().__init__( context=context, name=profile_id or opened.name, created=opened.created ) self.opened = opened self.ledger_pool: Optional[IndyVdrLedgerPool] = None self.profile_id = profile_id - self.init_ledger_pool() - self.bind_providers() + + @classmethod + async def create( + cls, + opened: AskarOpenStore, + context: Optional[InjectionContext] = None, + *, + profile_id: Optional[str] = None, + ) -> "AskarProfile": + """Asynchronously create a new AskarProfile instance.""" + profile = cls(opened, context, profile_id=profile_id) + await profile.init_ledger_pool() + await profile.bind_providers() + return profile @property def name(self) -> str: @@ -66,7 +78,7 @@ async def remove(self): if self.profile_id: await self.store.remove_profile(self.profile_id) - def init_ledger_pool(self): + async def init_ledger_pool(self): """Initialize the ledger pool.""" if self.settings.get("ledger.disabled"): LOGGER.info("Ledger support is disabled") @@ -80,8 +92,8 @@ def init_ledger_pool(self): LOGGER.warning("Note: setting ledger to read-only mode") genesis_transactions = self.settings.get("ledger.genesis_transactions") cache = self.context.injector.inject_or(BaseCache) - self.ledger_pool = IndyVdrLedgerPool( - pool_name, + self.ledger_pool = await IndyVdrLedgerPool.get_or_create( + name=pool_name, keepalive=keepalive, cache=cache, genesis_transactions=genesis_transactions, @@ -89,7 +101,7 @@ def init_ledger_pool(self): socks_proxy=socks_proxy, ) - def bind_providers(self): + async def bind_providers(self): """Initialize the profile-level instance providers.""" injector = self._context.injector @@ -136,23 +148,17 @@ def bind_providers(self): settings=self.settings ) cache = self.context.injector.inject_or(BaseCache) + ledger_pool = await IndyVdrLedgerPool.get_or_create( + name=write_ledger_config.get("pool_name") + or write_ledger_config.get("id"), + keepalive=write_ledger_config.get("keepalive"), + cache=cache, + genesis_transactions=write_ledger_config.get("genesis_transactions"), + read_only=write_ledger_config.get("read_only"), + socks_proxy=write_ledger_config.get("socks_proxy"), + ) injector.bind_provider( - BaseLedger, - ClassProvider( - IndyVdrLedger, - IndyVdrLedgerPool( - write_ledger_config.get("pool_name") - or write_ledger_config.get("id"), - keepalive=write_ledger_config.get("keepalive"), - cache=cache, - genesis_transactions=write_ledger_config.get( - "genesis_transactions" - ), - read_only=write_ledger_config.get("read_only"), - socks_proxy=write_ledger_config.get("socks_proxy"), - ), - ref(self), - ), + BaseLedger, ClassProvider(IndyVdrLedger, ledger_pool, ref(self)) ) self.settings["ledger.write_ledger"] = write_ledger_config.get("id") if ( @@ -329,7 +335,7 @@ async def provision( opened = await store_config.open_store( provision=True, in_memory=config.get("test") ) - return AskarProfile(opened, context) + return await AskarProfile.create(opened, context) async def open( self, context: InjectionContext, config: Mapping[str, Any] = None @@ -339,7 +345,7 @@ async def open( opened = await store_config.open_store( provision=False, in_memory=config.get("test") ) - return AskarProfile(opened, context) + return await AskarProfile.create(opened, context) @classmethod async def generate_store_key(self, seed: Optional[str] = None) -> str: diff --git a/acapy_agent/askar/profile_anon.py b/acapy_agent/askar/profile_anon.py index 90c6e7a09d..ecca03aea2 100644 --- a/acapy_agent/askar/profile_anon.py +++ b/acapy_agent/askar/profile_anon.py @@ -43,15 +43,27 @@ def __init__( *, profile_id: Optional[str] = None, ): - """Create a new AskarProfile instance.""" + """Create a new AskarAnoncredsProfile instance.""" super().__init__( context=context, name=profile_id or opened.name, created=opened.created ) self.opened = opened self.ledger_pool: Optional[IndyVdrLedgerPool] = None self.profile_id = profile_id - self.init_ledger_pool() - self.bind_providers() + + @classmethod + async def create( + cls, + opened: AskarOpenStore, + context: Optional[InjectionContext] = None, + *, + profile_id: Optional[str] = None, + ) -> "AskarAnoncredsProfile": + """Asynchronously create a new AskarAnoncredsProfile instance.""" + profile = cls(opened, context, profile_id=profile_id) + await profile.init_ledger_pool() + await profile.bind_providers() + return profile @property def name(self) -> str: @@ -68,7 +80,7 @@ async def remove(self): if self.profile_id: await self.store.remove_profile(self.profile_id) - def init_ledger_pool(self): + async def init_ledger_pool(self): """Initialize the ledger pool.""" if self.settings.get("ledger.disabled"): LOGGER.info("Ledger support is disabled") @@ -82,8 +94,8 @@ def init_ledger_pool(self): LOGGER.warning("Note: setting ledger to read-only mode") genesis_transactions = self.settings.get("ledger.genesis_transactions") cache = self.context.injector.inject_or(BaseCache) - self.ledger_pool = IndyVdrLedgerPool( - pool_name, + self.ledger_pool = await IndyVdrLedgerPool.get_or_create( + name=pool_name, keepalive=keepalive, cache=cache, genesis_transactions=genesis_transactions, @@ -91,7 +103,7 @@ def init_ledger_pool(self): socks_proxy=socks_proxy, ) - def bind_providers(self): + async def bind_providers(self): """Initialize the profile-level instance providers.""" injector = self._context.injector @@ -125,23 +137,17 @@ def bind_providers(self): settings=self.settings ) cache = self.context.injector.inject_or(BaseCache) + ledger_pool = await IndyVdrLedgerPool.get_or_create( + name=write_ledger_config.get("pool_name") + or write_ledger_config.get("id"), + keepalive=write_ledger_config.get("keepalive"), + cache=cache, + genesis_transactions=write_ledger_config.get("genesis_transactions"), + read_only=write_ledger_config.get("read_only"), + socks_proxy=write_ledger_config.get("socks_proxy"), + ) injector.bind_provider( - BaseLedger, - ClassProvider( - IndyVdrLedger, - IndyVdrLedgerPool( - write_ledger_config.get("pool_name") - or write_ledger_config.get("id"), - keepalive=write_ledger_config.get("keepalive"), - cache=cache, - genesis_transactions=write_ledger_config.get( - "genesis_transactions" - ), - read_only=write_ledger_config.get("read_only"), - socks_proxy=write_ledger_config.get("socks_proxy"), - ), - ref(self), - ), + BaseLedger, ClassProvider(IndyVdrLedger, ledger_pool, ref(self)) ) self.settings["ledger.write_ledger"] = write_ledger_config.get("id") if ( @@ -282,7 +288,7 @@ async def provision( opened = await store_config.open_store( provision=True, in_memory=config.get("test") ) - return AskarAnoncredsProfile(opened, context) + return await AskarAnoncredsProfile.create(opened, context) async def open( self, context: InjectionContext, config: Mapping[str, Any] = None @@ -292,7 +298,7 @@ async def open( opened = await store_config.open_store( provision=False, in_memory=config.get("test") ) - return AskarAnoncredsProfile(opened, context) + return await AskarAnoncredsProfile.create(opened, context) @classmethod async def generate_store_key(self, seed: Optional[str] = None) -> str: diff --git a/acapy_agent/askar/tests/test_profile.py b/acapy_agent/askar/tests/test_profile.py index 15bbbba1ef..1ecbe0ac47 100644 --- a/acapy_agent/askar/tests/test_profile.py +++ b/acapy_agent/askar/tests/test_profile.py @@ -17,7 +17,7 @@ def open_store(): @pytest.mark.asyncio async def test_init_success(open_store): - askar_profile = AskarProfile( + askar_profile = await AskarProfile.create( open_store, ) @@ -45,7 +45,7 @@ async def test_init_multi_ledger(open_store): ] } ) - askar_profile = AskarProfile( + askar_profile = await AskarProfile.create( open_store, context=context, ) @@ -68,7 +68,7 @@ async def test_remove_success(open_store): "wallet.askar_profile": profile_id, "ledger.genesis_transactions": mock.MagicMock(), } - askar_profile = AskarProfile(openStore, context, profile_id=profile_id) + askar_profile = await AskarProfile.create(openStore, context, profile_id=profile_id) remove_profile_stub = asyncio.Future() remove_profile_stub.set_result(True) openStore.store.remove_profile.return_value = remove_profile_stub @@ -83,7 +83,7 @@ async def test_remove_profile_not_removed_if_wallet_type_not_askar_profile(open_ openStore = open_store context = InjectionContext() context.settings = {"multitenant.wallet_type": "basic"} - askar_profile = AskarProfile(openStore, context) + askar_profile = await AskarProfile.create(openStore, context) await askar_profile.remove() @@ -95,7 +95,7 @@ async def test_profile_manager_transaction(): profile = "profileId" with mock.patch("acapy_agent.askar.profile.AskarProfile") as AskarProfile: - askar_profile = AskarProfile(None, True, profile_id=profile) + askar_profile = await AskarProfile.create(None, True, profile_id=profile) askar_profile.profile_id = profile askar_profile_transaction = mock.MagicMock() askar_profile.store.transaction.return_value = askar_profile_transaction diff --git a/acapy_agent/ledger/indy_vdr.py b/acapy_agent/ledger/indy_vdr.py index 5a9b7a2ba0..b81e4952d0 100644 --- a/acapy_agent/ledger/indy_vdr.py +++ b/acapy_agent/ledger/indy_vdr.py @@ -11,7 +11,7 @@ from io import StringIO from pathlib import Path from time import time -from typing import List, Optional, Tuple, Union +from typing import Dict, List, Optional, Tuple, Union from indy_vdr import Pool, Request, VdrError, ledger, open_pool @@ -40,36 +40,48 @@ def _normalize_txns(txns: str) -> str: """Normalize a set of genesis transactions.""" + LOGGER.debug("Normalizing genesis transactions") lines = StringIO() for line in txns.splitlines(): line = line.strip() if line: lines.write(line) lines.write("\n") + LOGGER.debug("Finished normalizing genesis transactions") return lines.getvalue() def _write_safe(path: Path, content: str): """Atomically write to a file path.""" + LOGGER.debug("Writing content safely to path: %s", path) dir_path = path.parent with tempfile.NamedTemporaryFile(dir=dir_path, delete=False) as tmp: + LOGGER.debug("Created temporary file: %s", tmp.name) tmp.write(content.encode("utf-8")) tmp_name = tmp.name + LOGGER.debug("Renaming temporary file to target path") os.rename(tmp_name, path) + LOGGER.debug("Successfully wrote content to: %s", path) def _hash_txns(txns: str) -> str: """Obtain a hash of a set of genesis transactions.""" - return hashlib.sha256(txns.encode("utf-8")).hexdigest()[-16:] + LOGGER.debug("Calculating hash of genesis transactions") + hash_value = hashlib.sha256(txns.encode("utf-8")).hexdigest()[-16:] + LOGGER.debug("Generated transaction hash: %s", hash_value) + return hash_value class IndyVdrLedgerPool: - """Indy-VDR ledger pool manager.""" + """Indy-VDR ledger pool manager with singleton behavior based on configuration.""" + + _instances: Dict[tuple, "IndyVdrLedgerPool"] = {} + _lock = asyncio.Lock() def __init__( self, - name: str, *, + name: str, keepalive: int = 0, cache: Optional[BaseCache] = None, cache_duration: int = 600, @@ -77,69 +89,225 @@ def __init__( read_only: bool = False, socks_proxy: Optional[str] = None, ): - """Initialize an IndyLedger instance. + """Private constructor. Use 'create_instance' to instantiate.""" + LOGGER.debug( + "Initializing IndyVdrLedgerPool with name: %s, keepalive: %s, " + "cache_duration: %s, read_only: %s", + name, + keepalive, + cache_duration, + read_only, + ) - Args: - name: The pool ledger configuration name - keepalive: How many seconds to keep the ledger open - cache: The cache instance to use - cache_duration: The TTL for ledger cache entries - genesis_transactions: The ledger genesis transaction as a string - read_only: Prevent any ledger write operations - socks_proxy: Specifies socks proxy for ZMQ to connect to ledger pool - """ - self.ref_count = 0 - self.ref_lock = asyncio.Lock() + # Instance attributes + self.name = name self.keepalive = keepalive - self.close_task: asyncio.Future = None self.cache = cache - self.cache_duration: int = cache_duration + self.cache_duration = cache_duration + self.genesis_transactions = genesis_transactions + self.read_only = read_only + self.socks_proxy = socks_proxy + + self.ref_count = 0 + self.ref_lock = asyncio.Lock() + self.close_task: Optional[asyncio.Task] = None self.handle: Optional[Pool] = None - self.name = name self.cfg_path_cache: Optional[Path] = None self.genesis_hash_cache: Optional[str] = None self.genesis_txns_cache = genesis_transactions self.init_config = bool(genesis_transactions) self.taa_cache: Optional[str] = None - self.read_only: bool = read_only - self.socks_proxy: str = socks_proxy + + LOGGER.debug("Pool %s initialization staged", name) + + @classmethod + async def get_or_create( + cls, + *, + name: str, + keepalive: int = 0, + cache: Optional[BaseCache] = None, + cache_duration: int = 600, + genesis_transactions: Optional[str] = None, + read_only: bool = False, + socks_proxy: Optional[str] = None, + ) -> "IndyVdrLedgerPool": + """Asynchronously get or create the singleton instance based on configuration. + + Args: + name: The pool ledger configuration name. + keepalive: How many seconds to keep the ledger open. + cache: The cache instance to use. + cache_duration: The TTL for ledger cache entries. + genesis_transactions: The ledger genesis transaction as a string. + read_only: Prevent any ledger write operations. + socks_proxy: Specifies socks proxy for ZMQ to connect to ledger pool. + + Returns: + An initialized instance of IndyVdrLedgerPool. + """ + LOGGER.debug( + "Creating or retrieving IndyVdrLedgerPool instance with params: name=%s, " + "keepalive=%s, cache_duration=%s, read_only=%s, socks_proxy=%s", + name, + keepalive, + cache_duration, + read_only, + socks_proxy, + ) + + config_key = (name, keepalive, cache_duration, read_only, socks_proxy) + LOGGER.debug("Generated config key: %s", config_key) + + async with cls._lock: + if config_key not in cls._instances: + LOGGER.debug( + "No existing instance found for config key, creating new instance" + ) + instance = cls( + name=name, + keepalive=keepalive, + cache=cache, + cache_duration=cache_duration, + genesis_transactions=genesis_transactions, + read_only=read_only, + socks_proxy=socks_proxy, + ) + try: + LOGGER.debug("Initializing new IndyVdrLedgerPool instance") + await instance.initialize() + except Exception as e: + LOGGER.exception( + "Initialization failed for IndyVdrLedgerPool with config: %s", + config_key, + exc_info=e, + ) + raise + cls._instances[config_key] = instance + LOGGER.debug( + "Successfully created and stored new IndyVdrLedgerPool instance: %s", + config_key, + ) + else: + LOGGER.debug( + "Found existing IndyVdrLedgerPool instance for config: %s", config_key + ) + instance = cls._instances[config_key] + + async with instance.ref_lock: + instance.ref_count += 1 + LOGGER.debug( + "Incremented reference count to %s for instance %s", + instance.ref_count, + config_key, + ) + + LOGGER.debug( + "Returning IndyVdrLedgerPool instance with ref_count: %s", + instance.ref_count, + ) + return instance + + async def initialize(self): + """Initialize the ledger pool.""" + LOGGER.debug("Beginning pool initialization") + if self.init_config: + LOGGER.debug("Creating pool config with genesis transactions") + await self.create_pool_config(self.genesis_txns_cache, recreate=True) + self.init_config = False + LOGGER.debug("Opening pool connection") + await self.open() + LOGGER.debug("Pool initialization complete") + + @classmethod + async def release_instance(cls, instance: "IndyVdrLedgerPool"): + """Release a reference to the instance and possibly remove it from the registry. + + Args: + instance: The IndyVdrLedgerPool instance to release. + """ + LOGGER.debug("Beginning instance release process for pool: %s", instance.name) + config_key = ( + instance.name, + instance.keepalive, + instance.cache_duration, + instance.genesis_transactions, + instance.read_only, + instance.socks_proxy, + ) + LOGGER.debug("Generated config key for release: %s", config_key) + + async with cls._lock: + async with instance.ref_lock: + instance.ref_count -= 1 + LOGGER.debug( + "Decremented reference count to %s for instance %s", + instance.ref_count, + config_key, + ) + if instance.ref_count <= 0: + LOGGER.debug( + "Reference count is zero or negative, cleaning up instance" + ) + await instance.close() + del cls._instances[config_key] + LOGGER.debug( + "Successfully removed IndyVdrLedgerPool instance: %s", config_key + ) + else: + LOGGER.debug( + "Instance still has active references: %s", instance.ref_count + ) @property def cfg_path(self) -> Path: """Get the path to the configuration file, ensuring it's created.""" if not self.cfg_path_cache: + LOGGER.debug("Creating configuration path cache") self.cfg_path_cache = storage_path("vdr", create=True) + LOGGER.debug("Configuration path set to: %s", self.cfg_path_cache) return self.cfg_path_cache @property def genesis_hash(self) -> str: """Get the hash of the configured genesis transactions.""" if not self.genesis_hash_cache: + LOGGER.debug("Calculating genesis transactions hash") self.genesis_hash_cache = _hash_txns(self.genesis_txns) + LOGGER.debug("Genesis hash calculated: %s", self.genesis_hash_cache) return self.genesis_hash_cache @property def genesis_txns(self) -> str: """Get the configured genesis transactions.""" if not self.genesis_txns_cache: + LOGGER.debug("Loading genesis transactions from file") try: path = self.cfg_path.joinpath(self.name, "genesis") + LOGGER.debug("Reading genesis file from: %s", path) self.genesis_txns_cache = _normalize_txns(open(path).read()) + LOGGER.debug("Successfully loaded genesis transactions") except FileNotFoundError: + LOGGER.error("Pool config '%s' not found", self.name) raise LedgerConfigError("Pool config '%s' not found", self.name) from None return self.genesis_txns_cache async def create_pool_config(self, genesis_transactions: str, recreate: bool = False): """Create the pool ledger configuration.""" + LOGGER.debug("Creating pool config for '%s', recreate=%s", self.name, recreate) cfg_pool = self.cfg_path.joinpath(self.name) cfg_pool.mkdir(exist_ok=True) + LOGGER.debug("Created pool configuration directory: %s", cfg_pool) + genesis = _normalize_txns(genesis_transactions) if not genesis: + LOGGER.error("Empty genesis transactions provided") raise LedgerConfigError("Empty genesis transactions") genesis_path = cfg_pool.joinpath("genesis") try: + LOGGER.debug("Checking existing genesis file: %s", genesis_path) cmp_genesis = open(genesis_path).read() if _normalize_txns(cmp_genesis) == genesis: LOGGER.debug( @@ -148,66 +316,94 @@ async def create_pool_config(self, genesis_transactions: str, recreate: bool = F ) return elif not recreate: + LOGGER.error( + "Pool ledger '%s' exists with different genesis transactions", + self.name, + ) raise LedgerConfigError( f"Pool ledger '{self.name}' exists with " "different genesis transactions" ) except FileNotFoundError: + LOGGER.debug("No existing genesis file found") pass try: + LOGGER.debug("Writing genesis transactions to: %s", genesis_path) _write_safe(genesis_path, genesis) except OSError as err: + LOGGER.exception("Error writing genesis transactions", exc_info=err) raise LedgerConfigError("Error writing genesis transactions") from err - LOGGER.debug("Wrote pool ledger config '%s'", self.name) + LOGGER.debug("Successfully wrote pool ledger config '%s'", self.name) self.genesis_txns_cache = genesis async def open(self): """Open the pool ledger, creating it if necessary.""" + LOGGER.debug("Opening pool ledger: %s", self.name) if self.init_config: + LOGGER.debug("Initializing pool config with genesis transactions") await self.create_pool_config(self.genesis_txns_cache, recreate=True) self.init_config = False genesis_hash = self.genesis_hash + LOGGER.debug("Using genesis hash: %s", genesis_hash) cfg_pool = self.cfg_path.joinpath(self.name) cfg_pool.mkdir(exist_ok=True) cache_path = cfg_pool.joinpath(f"cache-{genesis_hash}") try: + LOGGER.debug("Attempting to read cached transactions from: %s", cache_path) txns = open(cache_path).read() cached = True + LOGGER.debug("Successfully read cached transactions") except FileNotFoundError: + LOGGER.debug("No cached transactions found, using genesis transactions") txns = self.genesis_txns cached = False + LOGGER.debug("Opening pool with transactions, socks_proxy=%s", self.socks_proxy) self.handle = await open_pool(transactions=txns, socks_proxy=self.socks_proxy) + LOGGER.debug("Pool opened successfully") + upd_txns = _normalize_txns(await self.handle.get_transactions()) if not cached or upd_txns != txns: + LOGGER.debug("Updating cached transactions") try: _write_safe(cache_path, upd_txns) + LOGGER.debug("Successfully wrote updated cached transactions") except OSError: LOGGER.exception("Error writing cached genesis transactions") async def close(self): """Close the pool ledger.""" if self.handle: + LOGGER.debug("Attempting to close pool ledger") exc = None for attempt in range(3): try: + LOGGER.debug("Close attempt %s/3", attempt + 1) self.handle.close() except VdrError as err: + LOGGER.warning( + "Error closing pool ledger (attempt %s/3): %s", + attempt + 1, + str(err), + ) await asyncio.sleep(0.01) exc = err continue self.handle = None exc = None + LOGGER.debug("Successfully closed pool ledger") break if exc: - LOGGER.exception("Exception when closing pool ledger", exc_info=exc) + LOGGER.exception( + "Failed to close pool ledger after 3 attempts", exc_info=exc + ) self.ref_count += 1 # if we are here, we should have self.ref_lock self.close_task = None raise LedgerError("Exception when closing pool ledger") from exc @@ -227,18 +423,43 @@ async def context_close(self): async def closer(timeout: int): """Close the pool ledger after a timeout.""" - await asyncio.sleep(timeout) - async with self.ref_lock: - if not self.ref_count: - LOGGER.debug("Closing pool ledger after timeout") - await self.close() + try: + LOGGER.debug( + "Coroutine will sleep for %d seconds before closing the pool.", + timeout, + ) + await asyncio.sleep(timeout) + async with self.ref_lock: + if not self.ref_count: + LOGGER.debug( + "No more references. Proceeding to close the pool ledger." + ) + await self.close() + else: + LOGGER.debug( + "Reference count is %d. Not closing the pool yet.", + self.ref_count, + ) + except Exception as e: + LOGGER.exception( + "Exception occurred in closer coroutine during pool closure.", + exc_info=e, + ) async with self.ref_lock: self.ref_count -= 1 + LOGGER.debug("Decremented ref_count to %d.", self.ref_count) if not self.ref_count: if self.keepalive: - self.close_task = asyncio.ensure_future(closer(self.keepalive)) + LOGGER.debug( + "Scheduling closer coroutine with keepalive=%s", + self.keepalive, + ) + self.close_task = asyncio.create_task(closer(self.keepalive)) else: + LOGGER.debug( + "No keepalive set. Proceeding to close the pool immediately." + ) await self.close() diff --git a/acapy_agent/ledger/multiple_ledger/tests/test_indy_ledger_requests.py b/acapy_agent/ledger/multiple_ledger/tests/test_indy_ledger_requests.py index 4feb805b31..917a48e923 100644 --- a/acapy_agent/ledger/multiple_ledger/tests/test_indy_ledger_requests.py +++ b/acapy_agent/ledger/multiple_ledger/tests/test_indy_ledger_requests.py @@ -24,7 +24,8 @@ async def asyncSetUp(self): "genesis_transactions": "genesis_transactions", } ] - self.ledger = IndyVdrLedger(IndyVdrLedgerPool("test_prod_1"), self.profile) + pool = await IndyVdrLedgerPool.get_or_create(name="test_prod_1") + self.ledger = IndyVdrLedger(pool, self.profile) mock_ledger_manger = mock.MagicMock(BaseMultipleLedgerManager, autospec=True) mock_ledger_manger.extract_did_from_identifier = mock.MagicMock( return_value="WgWxqztrNooG92RXvxSTWv" diff --git a/acapy_agent/ledger/multiple_ledger/tests/test_indy_vdr_manager.py b/acapy_agent/ledger/multiple_ledger/tests/test_indy_vdr_manager.py index c567b33cf2..1451a5fabb 100644 --- a/acapy_agent/ledger/multiple_ledger/tests/test_indy_vdr_manager.py +++ b/acapy_agent/ledger/multiple_ledger/tests/test_indy_vdr_manager.py @@ -63,17 +63,19 @@ async def asyncSetUp(self): self.context.injector.bind_instance(BaseResponder, self.responder) self.production_ledger = OrderedDict() self.non_production_ledger = OrderedDict() - test_prod_ledger = IndyVdrLedger(IndyVdrLedgerPool("test_prod_1"), self.profile) + test_prod_ledger = IndyVdrLedger( + await IndyVdrLedgerPool.get_or_create(name="test_prod_1"), self.profile + ) writable_ledgers = set() self.production_ledger["test_prod_1"] = test_prod_ledger self.production_ledger["test_prod_2"] = IndyVdrLedger( - IndyVdrLedgerPool("test_prod_2"), self.profile + await IndyVdrLedgerPool.get_or_create(name="test_prod_2"), self.profile ) self.non_production_ledger["test_non_prod_1"] = IndyVdrLedger( - IndyVdrLedgerPool("test_non_prod_1"), self.profile + await IndyVdrLedgerPool.get_or_create(name="test_non_prod_1"), self.profile ) self.non_production_ledger["test_non_prod_2"] = IndyVdrLedger( - IndyVdrLedgerPool("test_non_prod_2"), self.profile + await IndyVdrLedgerPool.get_or_create(name="test_non_prod_2"), self.profile ) writable_ledgers.add("test_prod_1") writable_ledgers.add("test_prod_2") @@ -195,10 +197,10 @@ async def test_get_ledger_by_did_self_cert_b( ): self.non_production_ledger = OrderedDict() self.non_production_ledger["test_non_prod_1"] = IndyVdrLedger( - IndyVdrLedgerPool("test_non_prod_1"), self.profile + await IndyVdrLedgerPool.get_or_create(name="test_non_prod_1"), self.profile ) self.non_production_ledger["test_non_prod_2"] = IndyVdrLedger( - IndyVdrLedgerPool("test_non_prod_2"), self.profile + await IndyVdrLedgerPool.get_or_create(name="test_non_prod_2"), self.profile ) self.manager = MultiIndyVDRLedgerManager( self.profile, @@ -387,10 +389,10 @@ async def test_lookup_did_in_configured_ledgers_self_cert_non_prod( ): self.non_production_ledger = OrderedDict() self.non_production_ledger["test_non_prod_1"] = IndyVdrLedger( - IndyVdrLedgerPool("test_non_prod_1"), self.profile + await IndyVdrLedgerPool.get_or_create(name="test_non_prod_1"), self.profile ) self.non_production_ledger["test_non_prod_2"] = IndyVdrLedger( - IndyVdrLedgerPool("test_non_prod_2"), self.profile + await IndyVdrLedgerPool.get_or_create(name="test_non_prod_2"), self.profile ) self.manager = MultiIndyVDRLedgerManager( self.profile, @@ -420,10 +422,10 @@ async def test_get_ledger_by_did_not_self_cert_non_prod( ): self.non_production_ledger = OrderedDict() self.non_production_ledger["test_non_prod_1"] = IndyVdrLedger( - IndyVdrLedgerPool("test_non_prod_1"), self.profile + await IndyVdrLedgerPool.get_or_create(name="test_non_prod_1"), self.profile ) self.non_production_ledger["test_non_prod_2"] = IndyVdrLedger( - IndyVdrLedgerPool("test_non_prod_2"), self.profile + await IndyVdrLedgerPool.get_or_create(name="test_non_prod_2"), self.profile ) self.manager = MultiIndyVDRLedgerManager( self.profile, diff --git a/acapy_agent/ledger/multiple_ledger/tests/test_manager_provider.py b/acapy_agent/ledger/multiple_ledger/tests/test_manager_provider.py index ce9cc002a6..639c46c37f 100644 --- a/acapy_agent/ledger/multiple_ledger/tests/test_manager_provider.py +++ b/acapy_agent/ledger/multiple_ledger/tests/test_manager_provider.py @@ -57,7 +57,8 @@ async def test_provide_askar_manager(self): context = InjectionContext() profile = await create_test_profile() context.injector.bind_instance( - BaseLedger, IndyVdrLedger(IndyVdrLedgerPool("name"), profile) + BaseLedger, + IndyVdrLedger(await IndyVdrLedgerPool.get_or_create(name="name"), profile), ) provider = MultiIndyLedgerManagerProvider(profile) context.settings["ledger.ledger_config_list"] = LEDGER_CONFIG diff --git a/acapy_agent/ledger/tests/test_indy_vdr.py b/acapy_agent/ledger/tests/test_indy_vdr.py index 9b0ee8ce3c..079c444a39 100644 --- a/acapy_agent/ledger/tests/test_indy_vdr.py +++ b/acapy_agent/ledger/tests/test_indy_vdr.py @@ -43,7 +43,9 @@ async def ledger(): profile.context.injector.bind_instance(BaseCache, InMemoryCache()) profile.context.injector.bind_instance(KeyTypes, KeyTypes()) - ledger = IndyVdrLedger(IndyVdrLedgerPool("test-ledger"), profile) + ledger = IndyVdrLedger( + await IndyVdrLedgerPool.get_or_create(name="test-ledger"), profile + ) async def open(): ledger.pool.handle = mock.MagicMock(indy_vdr.Pool) diff --git a/acapy_agent/multitenant/manager.py b/acapy_agent/multitenant/manager.py index 1a6bda9030..8137e9dbe9 100644 --- a/acapy_agent/multitenant/manager.py +++ b/acapy_agent/multitenant/manager.py @@ -88,7 +88,7 @@ async def get_wallet_profile( # return anoncreds profile if explicitly set as wallet type if profile.context.settings.get("wallet.type") == "askar-anoncreds": - return AskarAnoncredsProfile( + return await AskarAnoncredsProfile.create( profile.opened, profile.context, ) diff --git a/acapy_agent/multitenant/single_wallet_askar_manager.py b/acapy_agent/multitenant/single_wallet_askar_manager.py index 56e9051a13..b6515765ac 100644 --- a/acapy_agent/multitenant/single_wallet_askar_manager.py +++ b/acapy_agent/multitenant/single_wallet_askar_manager.py @@ -109,13 +109,13 @@ async def get_wallet_profile( # return anoncreds profile if explicitly set as wallet type if profile_context.settings.get("wallet.type") == "askar-anoncreds": - return AskarAnoncredsProfile( + return await AskarAnoncredsProfile.create( self._multitenant_profile.opened, profile_context, profile_id=wallet_record.wallet_id, ) - return AskarProfile( + return await AskarProfile.create( self._multitenant_profile.opened, profile_context, profile_id=wallet_record.wallet_id, diff --git a/acapy_agent/multitenant/tests/test_single_wallet_askar_manager.py b/acapy_agent/multitenant/tests/test_single_wallet_askar_manager.py index 322a8517ec..c59f098f18 100644 --- a/acapy_agent/multitenant/tests/test_single_wallet_askar_manager.py +++ b/acapy_agent/multitenant/tests/test_single_wallet_askar_manager.py @@ -52,7 +52,7 @@ async def test_get_wallet_profile_should_open_store_and_return_profile_with_wall ) as AskarProfile, ): sub_wallet_profile_context = InjectionContext() - sub_wallet_profile = AskarProfile(None, None) + sub_wallet_profile = await AskarProfile.create(None, None) sub_wallet_profile.context.copy.return_value = sub_wallet_profile_context def side_effect(context, provision): @@ -127,7 +127,7 @@ async def test_get_anoncreds_wallet_profile_should_open_store_and_return_anoncre ) as AskarAnoncredsProfile, ): sub_wallet_profile_context = InjectionContext() - sub_wallet_profile = AskarAnoncredsProfile(None, None) + sub_wallet_profile = await AskarAnoncredsProfile.create(None, None) sub_wallet_profile.context.copy.return_value = sub_wallet_profile_context def side_effect(context, provision): @@ -150,7 +150,7 @@ async def test_get_wallet_profile_should_create_profile(self): with mock.patch( "acapy_agent.multitenant.single_wallet_askar_manager.AskarProfile" ) as AskarProfile: - sub_wallet_profile = AskarProfile(None, None) + sub_wallet_profile = await AskarProfile.create(None, None) sub_wallet_profile.context.copy.return_value = InjectionContext() sub_wallet_profile.store.create_profile.return_value = create_profile_stub self.manager._multitenant_profile = sub_wallet_profile @@ -176,7 +176,7 @@ async def test_get_wallet_profile_should_use_custom_subwallet_name(self): with mock.patch( "acapy_agent.multitenant.single_wallet_askar_manager.AskarProfile" ) as AskarProfile: - sub_wallet_profile = AskarProfile(None, None) + sub_wallet_profile = await AskarProfile.create(None, None) sub_wallet_profile.context.copy.return_value = InjectionContext() def side_effect(context, provision): @@ -207,7 +207,7 @@ async def test_open_profiles(self): with mock.patch( "acapy_agent.multitenant.single_wallet_askar_manager.AskarProfile" ) as AskarProfile: - sub_wallet_profile = AskarProfile(None, None) + sub_wallet_profile = await AskarProfile.create(None, None) sub_wallet_profile.context.copy.return_value = InjectionContext() sub_wallet_profile.store.create_profile.return_value = create_profile_stub self.manager._multitenant_profile = sub_wallet_profile diff --git a/acapy_agent/storage/tests/test_askar_storage.py b/acapy_agent/storage/tests/test_askar_storage.py index c959c6e3fa..e9ddfce247 100644 --- a/acapy_agent/storage/tests/test_askar_storage.py +++ b/acapy_agent/storage/tests/test_askar_storage.py @@ -385,7 +385,7 @@ async def test_askar_storage_search_session(self): profile = "profileId" with mock.patch("acapy_agent.storage.askar.AskarProfile") as AskarProfile: - askar_profile = AskarProfile(None, True) + askar_profile = await AskarProfile.create(None, True) askar_profile_scan = mock.MagicMock() askar_profile.store.scan.return_value = askar_profile_scan askar_profile.settings.get.return_value = profile diff --git a/acapy_agent/utils/testing.py b/acapy_agent/utils/testing.py index 2ee34cf125..169bfb3cd8 100644 --- a/acapy_agent/utils/testing.py +++ b/acapy_agent/utils/testing.py @@ -38,11 +38,11 @@ async def create_test_profile( opened = await store_config.open_store(provision=True, in_memory=True) if settings.get("wallet.type") == "askar-anoncreds": - return AskarAnoncredsProfile( + return await AskarAnoncredsProfile.create( opened=opened, context=context, ) - return AskarProfile( + return await AskarProfile.create( opened=opened, context=context, )