From 8e7d4141f3b5a9b0f3c1fcb03f58d51157f53fe4 Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Wed, 31 Jul 2024 09:50:53 -0500 Subject: [PATCH 1/7] feat: allow ws_uri config --- docs/userguides/networks.md | 4 ++- src/ape_ethereum/provider.py | 58 +++++++++++++++++++++++-------- tests/functional/test_provider.py | 10 ++++++ 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/docs/userguides/networks.md b/docs/userguides/networks.md index e7525f711f..7bbadf7aa7 100644 --- a/docs/userguides/networks.md +++ b/docs/userguides/networks.md @@ -367,7 +367,9 @@ To configure network URIs in `node`, you can use the `ape-config.yaml` file: node: ethereum: mainnet: - uri: https://foo.node.bar + uri: https://foo.node.example.com + # You can also configure a websockets URI (used by Silverback SDK). + ws_uri: wss://bar.feed.example.com ``` ## Network Config diff --git a/src/ape_ethereum/provider.py b/src/ape_ethereum/provider.py index b4f7d14380..f277c49183 100644 --- a/src/ape_ethereum/provider.py +++ b/src/ape_ethereum/provider.py @@ -177,12 +177,17 @@ def web3(self) -> Web3: @property def http_uri(self) -> Optional[str]: + try: + web3 = self.web3 + except ProviderNotConnectedError: + return None + if ( - hasattr(self.web3.provider, "endpoint_uri") - and isinstance(self.web3.provider.endpoint_uri, str) - and self.web3.provider.endpoint_uri.startswith("http") + hasattr(web3.provider, "endpoint_uri") + and isinstance(web3.provider.endpoint_uri, str) + and web3.provider.endpoint_uri.startswith("http") ): - return self.web3.provider.endpoint_uri + return web3.provider.endpoint_uri elif uri := getattr(self, "uri", None): # NOTE: Some providers define this @@ -192,12 +197,17 @@ def http_uri(self) -> Optional[str]: @property def ws_uri(self) -> Optional[str]: + try: + web3 = self.web3 + except ProviderNotConnectedError: + return None + if ( - hasattr(self.web3.provider, "endpoint_uri") - and isinstance(self.web3.provider.endpoint_uri, str) - and self.web3.provider.endpoint_uri.startswith("ws") + hasattr(web3.provider, "endpoint_uri") + and isinstance(web3.provider.endpoint_uri, str) + and web3.provider.endpoint_uri.startswith("ws") ): - return self.web3.provider.endpoint_uri + return web3.provider.endpoint_uri return None @@ -1238,6 +1248,27 @@ def _get_random_rpc(self) -> Optional[str]: except KeyError: return None + @property + def ws_uri(self) -> Optional[str]: + if "ws_uri" in self.provider_settings: + # Use adhoc, scripted value + return self.provider_settings["ws_uri"] + + config = self.config.model_dump().get(self.network.ecosystem.name, None) + if config is None: + return super().ws_uri + + # Use value from config file + network_config = config.get(self.network.name) or DEFAULT_SETTINGS + if "ws_uri" not in network_config: + return super().ws_uri + + settings_uri = network_config.get("ws_uri") + if settings_uri and _is_ws_url(settings_uri): + return settings_uri + + return super().ws_uri + @property def connection_str(self) -> str: return self.uri or f"{self.ipc_path}" @@ -1418,9 +1449,8 @@ def _get_default_data_dir() -> Path: def _is_url(val: str) -> bool: - return ( - val.startswith("https://") - or val.startswith("http://") - or val.startswith("wss://") - or val.startswith("ws://") - ) + return val.startswith("https://") or val.startswith("http://") or _is_ws_url(val) + + +def _is_ws_url(val: str) -> bool: + return val.startswith("wss://") or val.startswith("ws://") diff --git a/tests/functional/test_provider.py b/tests/functional/test_provider.py index ac72f69a26..10a1f81cac 100644 --- a/tests/functional/test_provider.py +++ b/tests/functional/test_provider.py @@ -493,3 +493,13 @@ def test_account_balance_state(project, eth_tester_provider, owner): provider.connect() bal = provider.get_balance(owner.address) assert bal == amount + + +def test_node_ws_uri(project): + node = project.network_manager.ethereum.sepolia.get_provider("node") + assert node.ws_uri is None + + ws_uri = "ws://example.com" + with project.temp_config(node={"ethereum": {"sepolia": {"ws_uri": ws_uri}}}): + node = project.network_manager.ethereum.sepolia.get_provider("node") + assert node.ws_uri == ws_uri From de6427e70ae92b3ac5d47df857fe2976ab017602 Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Thu, 1 Aug 2024 08:57:29 -0500 Subject: [PATCH 2/7] feat: http uri --- docs/userguides/networks.md | 6 ++++ src/ape_ethereum/provider.py | 56 +++++++++++++++++++------------ tests/functional/test_provider.py | 14 +++++--- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/docs/userguides/networks.md b/docs/userguides/networks.md index 7bbadf7aa7..545fbcc4ed 100644 --- a/docs/userguides/networks.md +++ b/docs/userguides/networks.md @@ -367,7 +367,13 @@ To configure network URIs in `node`, you can use the `ape-config.yaml` file: node: ethereum: mainnet: + # For `uri`, you can use either HTTP, WS, or IPC values. + # **Most often, you only need HTTP!** uri: https://foo.node.example.com + + # For strict HTTP connections, you can configure a http_uri directly. + http_uri: https://foo.node.example.com + # You can also configure a websockets URI (used by Silverback SDK). ws_uri: wss://bar.feed.example.com ``` diff --git a/src/ape_ethereum/provider.py b/src/ape_ethereum/provider.py index f277c49183..2baf7669bc 100644 --- a/src/ape_ethereum/provider.py +++ b/src/ape_ethereum/provider.py @@ -1205,7 +1205,7 @@ class EthereumNodeProvider(Web3Provider, ABC): def uri(self) -> str: if "url" in self.provider_settings: raise ConfigError("Unknown provider setting 'url'. Did you mean 'uri'?") - elif "uri" in self.provider_settings: + elif "uri" in self.provider_settings and _is_http_url(self.provider_settings["uri"]): # Use adhoc, scripted value return self.provider_settings["uri"] @@ -1222,31 +1222,25 @@ def uri(self) -> str: # Use value from config file network_config = config.get(self.network.name) or DEFAULT_SETTINGS + key = "uri" if "url" in network_config: raise ConfigError("Unknown provider setting 'url'. Did you mean 'uri'?") - elif "uri" not in network_config: + elif "http_uri" in network_config: + key = "http_uri" + elif key not in network_config: if rpc := self._get_random_rpc(): return rpc - settings_uri = network_config.get("uri", DEFAULT_SETTINGS["uri"]) - if _is_url(settings_uri): + settings_uri = network_config.get(key, DEFAULT_SETTINGS["uri"]) + if _is_http_url(settings_uri): return settings_uri - # Likely was an IPC Path and will connect that way. - return "" + # Likely was an IPC Path (or websockets) and will connect that way. + return super().http_uri or "" - def _get_random_rpc(self) -> Optional[str]: - if self.network.is_dev: - return None - - ecosystem = self.network.ecosystem.name - network = self.network.name - - # Use public RPC if available - try: - return get_random_rpc(ecosystem, network) - except KeyError: - return None + @property + def http_uri(self) -> Optional[str]: + return self.uri @property def ws_uri(self) -> Optional[str]: @@ -1254,6 +1248,9 @@ def ws_uri(self) -> Optional[str]: # Use adhoc, scripted value return self.provider_settings["ws_uri"] + elif "uri" in self.provider_settings and _is_ws_url(self.provider_settings["uri"]): + return self.provider_settings["uri"] + config = self.config.model_dump().get(self.network.ecosystem.name, None) if config is None: return super().ws_uri @@ -1261,6 +1258,9 @@ def ws_uri(self) -> Optional[str]: # Use value from config file network_config = config.get(self.network.name) or DEFAULT_SETTINGS if "ws_uri" not in network_config: + if "uri" in network_config and _is_ws_url(network_config["uri"]): + return network_config["uri"] + return super().ws_uri settings_uri = network_config.get("ws_uri") @@ -1269,6 +1269,19 @@ def ws_uri(self) -> Optional[str]: return super().ws_uri + def _get_random_rpc(self) -> Optional[str]: + if self.network.is_dev: + return None + + ecosystem = self.network.ecosystem.name + network = self.network.name + + # Use public RPC if available + try: + return get_random_rpc(ecosystem, network) + except KeyError: + return None + @property def connection_str(self) -> str: return self.uri or f"{self.ipc_path}" @@ -1279,7 +1292,8 @@ def connection_id(self) -> Optional[str]: @property def _clean_uri(self) -> str: - return sanitize_url(self.uri) if _is_url(self.uri) else self.uri + uri = self.uri + return sanitize_url(uri) if _is_http_url(uri) or _is_ws_url(uri) else uri @property def ipc_path(self) -> Path: @@ -1448,8 +1462,8 @@ def _get_default_data_dir() -> Path: ) -def _is_url(val: str) -> bool: - return val.startswith("https://") or val.startswith("http://") or _is_ws_url(val) +def _is_http_url(val: str) -> bool: + return val.startswith("https://") or val.startswith("http://") def _is_ws_url(val: str) -> bool: diff --git a/tests/functional/test_provider.py b/tests/functional/test_provider.py index 10a1f81cac..845c152b10 100644 --- a/tests/functional/test_provider.py +++ b/tests/functional/test_provider.py @@ -495,11 +495,17 @@ def test_account_balance_state(project, eth_tester_provider, owner): assert bal == amount -def test_node_ws_uri(project): +@pytest.mark.parametrize( + "uri,key", + [("ws://example.com", "ws_uri"), ("wss://example.com", "ws_uri"), ("wss://example.com", "uri")], +) +def test_node_ws_uri(project, uri, key): node = project.network_manager.ethereum.sepolia.get_provider("node") assert node.ws_uri is None - ws_uri = "ws://example.com" - with project.temp_config(node={"ethereum": {"sepolia": {"ws_uri": ws_uri}}}): + with project.temp_config(node={"ethereum": {"sepolia": {key: uri}}}): node = project.network_manager.ethereum.sepolia.get_provider("node") - assert node.ws_uri == ws_uri + assert node.ws_uri == uri + + # Even though you can configure URI to be websockets, + assert node.uri != uri From 51fec2d62cac6536bac5d334c43881881bdc595c Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Thu, 1 Aug 2024 10:29:52 -0500 Subject: [PATCH 3/7] fix: issues found from tests --- src/ape_ethereum/provider.py | 22 ++++++++++++++-------- tests/functional/test_provider.py | 17 +++++++++++++---- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/ape_ethereum/provider.py b/src/ape_ethereum/provider.py index 2baf7669bc..8a5e0929c5 100644 --- a/src/ape_ethereum/provider.py +++ b/src/ape_ethereum/provider.py @@ -1205,9 +1205,11 @@ class EthereumNodeProvider(Web3Provider, ABC): def uri(self) -> str: if "url" in self.provider_settings: raise ConfigError("Unknown provider setting 'url'. Did you mean 'uri'?") - elif "uri" in self.provider_settings and _is_http_url(self.provider_settings["uri"]): - # Use adhoc, scripted value - return self.provider_settings["uri"] + elif uri := self.provider_settings.get("uri"): + if _is_http_url(uri) or _is_ws_url(uri): + return uri + else: + raise TypeError(f"Not an URI: {uri}") config = self.config.model_dump().get(self.network.ecosystem.name, None) if config is None: @@ -1222,17 +1224,21 @@ def uri(self) -> str: # Use value from config file network_config = config.get(self.network.name) or DEFAULT_SETTINGS - key = "uri" if "url" in network_config: raise ConfigError("Unknown provider setting 'url'. Did you mean 'uri'?") elif "http_uri" in network_config: key = "http_uri" - elif key not in network_config: - if rpc := self._get_random_rpc(): - return rpc + elif "uri" in network_config: + key = "uri" + elif "ws_uri" in network_config: + key = "ws_uri" + elif rpc := self._get_random_rpc(): + return rpc + else: + key = "uri" settings_uri = network_config.get(key, DEFAULT_SETTINGS["uri"]) - if _is_http_url(settings_uri): + if _is_http_url(settings_uri) or _is_ws_url(settings_uri): return settings_uri # Likely was an IPC Path (or websockets) and will connect that way. diff --git a/tests/functional/test_provider.py b/tests/functional/test_provider.py index 845c152b10..4f9a7d45d9 100644 --- a/tests/functional/test_provider.py +++ b/tests/functional/test_provider.py @@ -502,10 +502,19 @@ def test_account_balance_state(project, eth_tester_provider, owner): def test_node_ws_uri(project, uri, key): node = project.network_manager.ethereum.sepolia.get_provider("node") assert node.ws_uri is None - - with project.temp_config(node={"ethereum": {"sepolia": {key: uri}}}): + config = {"ethereum": {"sepolia": {key: uri}}} + with project.temp_config(node=config): node = project.network_manager.ethereum.sepolia.get_provider("node") assert node.ws_uri == uri - # Even though you can configure URI to be websockets, - assert node.uri != uri + +@pytest.mark.parametrize("http_key", ("uri", "http_uri")) +def test_node_http_uri_with_ws_uri(project, http_key): + http = "http://example.com" + ws = "ws://example.com" + # Showing `uri:` as an HTTP and `ws_uri`: as an additional ws. + with project.temp_config(node={"ethereum": {"sepolia": {http_key: http, "ws_uri": ws}}}): + node = project.network_manager.ethereum.sepolia.get_provider("node") + assert node.uri == http + assert node.http_uri == http + assert node.ws_uri == ws From a7c4fa1f336238d1de03639648669f777dd52537 Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Thu, 1 Aug 2024 11:13:40 -0500 Subject: [PATCH 4/7] feat: ipc improvements --- docs/userguides/networks.md | 5 +++ src/ape_ethereum/provider.py | 74 ++++++++++++++++++++----------- tests/functional/test_provider.py | 9 ++++ 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/docs/userguides/networks.md b/docs/userguides/networks.md index 545fbcc4ed..076ff1a691 100644 --- a/docs/userguides/networks.md +++ b/docs/userguides/networks.md @@ -365,11 +365,16 @@ To configure network URIs in `node`, you can use the `ape-config.yaml` file: ```yaml node: + # When managing or running a node, configure its IPC path directly (optional) + ipc_path: path/to/geth.ipc + ethereum: mainnet: # For `uri`, you can use either HTTP, WS, or IPC values. # **Most often, you only need HTTP!** uri: https://foo.node.example.com + # uri: wss://bar.feed.example.com + # uri: path/to/geth.ipc # For strict HTTP connections, you can configure a http_uri directly. http_uri: https://foo.node.example.com diff --git a/src/ape_ethereum/provider.py b/src/ape_ethereum/provider.py index 8a5e0929c5..99d1fd97e7 100644 --- a/src/ape_ethereum/provider.py +++ b/src/ape_ethereum/provider.py @@ -19,7 +19,7 @@ from evmchains import get_random_rpc from pydantic.dataclasses import dataclass from requests import HTTPError -from web3 import HTTPProvider, IPCProvider, Web3 +from web3 import HTTPProvider, IPCProvider, Web3, WebsocketProvider from web3.exceptions import ContractLogicError as Web3ContractLogicError from web3.exceptions import ( ExtraDataLengthError, @@ -177,9 +177,18 @@ def web3(self) -> Web3: @property def http_uri(self) -> Optional[str]: + """ + The connected HTTP URI. If using providers + like `ape-node`, configure your URI and that will + be returned here instead. + """ try: web3 = self.web3 except ProviderNotConnectedError: + if uri := getattr(self, "uri", None): + if _is_http_url(uri): + return uri + return None if ( @@ -189,9 +198,9 @@ def http_uri(self) -> Optional[str]: ): return web3.provider.endpoint_uri - elif uri := getattr(self, "uri", None): - # NOTE: Some providers define this - return uri + if uri := getattr(self, "uri", None): + if _is_http_url(uri): + return uri return None @@ -1206,7 +1215,7 @@ def uri(self) -> str: if "url" in self.provider_settings: raise ConfigError("Unknown provider setting 'url'. Did you mean 'uri'?") elif uri := self.provider_settings.get("uri"): - if _is_http_url(uri) or _is_ws_url(uri): + if _is_uri(uri): return uri else: raise TypeError(f"Not an URI: {uri}") @@ -1230,6 +1239,8 @@ def uri(self) -> str: key = "http_uri" elif "uri" in network_config: key = "uri" + elif "ipc_path" in network_config: + key = "ipc_path" elif "ws_uri" in network_config: key = "ws_uri" elif rpc := self._get_random_rpc(): @@ -1238,7 +1249,7 @@ def uri(self) -> str: key = "uri" settings_uri = network_config.get(key, DEFAULT_SETTINGS["uri"]) - if _is_http_url(settings_uri) or _is_ws_url(settings_uri): + if _is_uri(settings_uri): return settings_uri # Likely was an IPC Path (or websockets) and will connect that way. @@ -1246,7 +1257,8 @@ def uri(self) -> str: @property def http_uri(self) -> Optional[str]: - return self.uri + uri = self.uri + return uri if _is_http_url(uri) else None @property def ws_uri(self) -> Optional[str]: @@ -1303,7 +1315,15 @@ def _clean_uri(self) -> str: @property def ipc_path(self) -> Path: - return self.settings.ipc_path or self.data_dir / "geth.ipc" + if ipc := self.settings.ipc_path: + return ipc + + uri = self.uri + if _is_ipc_path(uri): + return Path(uri) + + # Default (used by geth-process). + return self.data_dir / "geth.ipc" @property def data_dir(self) -> Path: @@ -1331,7 +1351,10 @@ def _ots_api_level(self) -> Optional[int]: def _set_web3(self): # Clear cached version when connecting to another URI. self._client_version = None - self._web3 = _create_web3(self.uri, ipc_path=self.ipc_path) + if uri := self.http_uri: + self._web3 = _create_web3(uri, ipc_path=self.ipc_path, ws_uri=self.ws_uri) + else: + raise ProviderError("Missing URI.") def _complete_connect(self): client_version = self.client_version.lower() @@ -1426,25 +1449,16 @@ def connect(self): self._complete_connect() -def _create_web3(uri: str, ipc_path: Optional[Path] = None): - # Separated into helper method for testing purposes. - def http_provider(): - return HTTPProvider(uri, request_kwargs={"timeout": 30 * 60}) - - def ipc_provider(): - # NOTE: This mypy complaint seems incorrect. - if not (path := ipc_path): - raise ValueError("IPC Path required.") - - return IPCProvider(ipc_path=path) - +def _create_web3(uri: str, ipc_path: Optional[Path] = None, ws_uri: Optional[str] = None): # NOTE: This list is ordered by try-attempt. # Try ENV, then IPC, and then HTTP last. - providers = [load_provider_from_environment] - if ipc_path: - providers.append(ipc_provider) - if uri: - providers.append(http_provider) + providers: list = [load_provider_from_environment] + if ipc := ipc_path: + providers.append(IPCProvider(ipc_path=ipc)) + if http := uri: + providers.append(HTTPProvider(endpoint_uri=http, request_kwargs={"timeout": 30 * 60})) + if ws := ws_uri: + providers.append(WebsocketProvider(endpoint_uri=ws)) provider = AutoProvider(potential_providers=providers) return Web3(provider) @@ -1468,9 +1482,17 @@ def _get_default_data_dir() -> Path: ) +def _is_uri(val: str) -> bool: + return _is_http_url(val) or _is_ws_url(val) or _is_ipc_path(val) + + def _is_http_url(val: str) -> bool: return val.startswith("https://") or val.startswith("http://") def _is_ws_url(val: str) -> bool: return val.startswith("wss://") or val.startswith("ws://") + + +def _is_ipc_path(val: str) -> bool: + return val.endswith(".ipc") diff --git a/tests/functional/test_provider.py b/tests/functional/test_provider.py index 4f9a7d45d9..80620a3554 100644 --- a/tests/functional/test_provider.py +++ b/tests/functional/test_provider.py @@ -1,4 +1,5 @@ import os +from pathlib import Path from unittest import mock import pytest @@ -518,3 +519,11 @@ def test_node_http_uri_with_ws_uri(project, http_key): assert node.uri == http assert node.http_uri == http assert node.ws_uri == ws + + +def test_ipc_for_uri(project): + ipc = "path/to/example.ipc" + with project.temp_config(node={"ethereum": {"sepolia": {"uri": ipc}}}): + node = project.network_manager.ethereum.sepolia.get_provider("node") + assert node.uri == ipc + assert node.ipc_path == Path(ipc) From 3605cf0ca03134ab1764cba6954304811ccaeaba Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Thu, 1 Aug 2024 11:41:18 -0500 Subject: [PATCH 5/7] feat: ipc network specific --- docs/userguides/networks.md | 9 ++++++--- src/ape_ethereum/provider.py | 12 +++++++++--- tests/functional/test_provider.py | 18 +++++++++++++++--- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/docs/userguides/networks.md b/docs/userguides/networks.md index 076ff1a691..dea4674c8d 100644 --- a/docs/userguides/networks.md +++ b/docs/userguides/networks.md @@ -365,7 +365,7 @@ To configure network URIs in `node`, you can use the `ape-config.yaml` file: ```yaml node: - # When managing or running a node, configure its IPC path directly (optional) + # When managing or running a node, configure an IPC path globally (optional) ipc_path: path/to/geth.ipc ethereum: @@ -374,13 +374,16 @@ node: # **Most often, you only need HTTP!** uri: https://foo.node.example.com # uri: wss://bar.feed.example.com - # uri: path/to/geth.ipc + # uri: path/to/mainnet/geth.ipc # For strict HTTP connections, you can configure a http_uri directly. http_uri: https://foo.node.example.com # You can also configure a websockets URI (used by Silverback SDK). ws_uri: wss://bar.feed.example.com + + # Specify per-network IPC paths as well. + ipc_path: path/to/mainnet/geth.ipc ``` ## Network Config @@ -393,7 +396,7 @@ The following example shows how to do this. (note: even though this example uses `ethereum:mainnet`, you can use any of the L2 networks mentioned above, as they all have these config properties). ```yaml -ethereum: +ethereum: mainnet: # Ethereum mainnet in Ape uses EIP-1559 by default, # but we can change that here. Note: most plugins diff --git a/src/ape_ethereum/provider.py b/src/ape_ethereum/provider.py index 99d1fd97e7..3442ca567e 100644 --- a/src/ape_ethereum/provider.py +++ b/src/ape_ethereum/provider.py @@ -606,7 +606,7 @@ def get_receipt( transaction_hash=txn_hash, error_message=msg_str ) from err - ecosystem_config = self.network.ecosystem_config.model_dump(by_alias=True) + ecosystem_config = self.network.ecosystem_config network_config: dict = ecosystem_config.get(self.network.name, {}) max_retries = network_config.get("max_get_transaction_retries", DEFAULT_MAX_RETRIES_TX) txn = {} @@ -1269,8 +1269,8 @@ def ws_uri(self) -> Optional[str]: elif "uri" in self.provider_settings and _is_ws_url(self.provider_settings["uri"]): return self.provider_settings["uri"] - config = self.config.model_dump().get(self.network.ecosystem.name, None) - if config is None: + config: dict = self.config.get(self.network.ecosystem.name, {}) + if config == {}: return super().ws_uri # Use value from config file @@ -1318,6 +1318,12 @@ def ipc_path(self) -> Path: if ipc := self.settings.ipc_path: return ipc + config: dict = self.config.get(self.network.ecosystem.name, {}) + network_config = config.get(self.network.name, {}) + if ipc := network_config.get("ipc_path"): + return Path(ipc) + + # Check `uri:` config. uri = self.uri if _is_ipc_path(uri): return Path(uri) diff --git a/tests/functional/test_provider.py b/tests/functional/test_provider.py index 80620a3554..136893c363 100644 --- a/tests/functional/test_provider.py +++ b/tests/functional/test_provider.py @@ -508,6 +508,12 @@ def test_node_ws_uri(project, uri, key): node = project.network_manager.ethereum.sepolia.get_provider("node") assert node.ws_uri == uri + if key != "ws_uri": + assert node.uri == uri + # else: uri gets to set to random HTTP from default settings, + # but we may want to change that behavior. + # TODO: 0.9 investigate not using random if ws set. + @pytest.mark.parametrize("http_key", ("uri", "http_uri")) def test_node_http_uri_with_ws_uri(project, http_key): @@ -521,9 +527,15 @@ def test_node_http_uri_with_ws_uri(project, http_key): assert node.ws_uri == ws -def test_ipc_for_uri(project): +@pytest.mark.parametrize("key", ("uri", "ipc_path")) +def test_ipc_per_network(project, key): ipc = "path/to/example.ipc" - with project.temp_config(node={"ethereum": {"sepolia": {"uri": ipc}}}): + with project.temp_config(node={"ethereum": {"sepolia": {key: ipc}}}): node = project.network_manager.ethereum.sepolia.get_provider("node") - assert node.uri == ipc + if key != "ipc_path": + assert node.uri == ipc + # else: uri gets to set to random HTTP from default settings, + # but we may want to change that behavior. + # TODO: 0.9 investigate not using random if ipc set. + assert node.ipc_path == Path(ipc) From 4b503f5f68c94e00c9f4e2d974aab7b9ecbb52bd Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Thu, 1 Aug 2024 12:05:10 -0500 Subject: [PATCH 6/7] fix: type fudge --- src/ape_ethereum/provider.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ape_ethereum/provider.py b/src/ape_ethereum/provider.py index 3442ca567e..8c96fbf293 100644 --- a/src/ape_ethereum/provider.py +++ b/src/ape_ethereum/provider.py @@ -1460,11 +1460,13 @@ def _create_web3(uri: str, ipc_path: Optional[Path] = None, ws_uri: Optional[str # Try ENV, then IPC, and then HTTP last. providers: list = [load_provider_from_environment] if ipc := ipc_path: - providers.append(IPCProvider(ipc_path=ipc)) + providers.append(lambda: IPCProvider(ipc_path=ipc)) if http := uri: - providers.append(HTTPProvider(endpoint_uri=http, request_kwargs={"timeout": 30 * 60})) + providers.append( + lambda: HTTPProvider(endpoint_uri=http, request_kwargs={"timeout": 30 * 60}) + ) if ws := ws_uri: - providers.append(WebsocketProvider(endpoint_uri=ws)) + providers.append(lambda: WebsocketProvider(endpoint_uri=ws)) provider = AutoProvider(potential_providers=providers) return Web3(provider) From 2eda32bca8a1e725e4171481b21586a1fb0c5381 Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Fri, 2 Aug 2024 09:34:04 -0500 Subject: [PATCH 7/7] chore: space --- docs/userguides/networks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/userguides/networks.md b/docs/userguides/networks.md index dea4674c8d..232573090d 100644 --- a/docs/userguides/networks.md +++ b/docs/userguides/networks.md @@ -396,7 +396,7 @@ The following example shows how to do this. (note: even though this example uses `ethereum:mainnet`, you can use any of the L2 networks mentioned above, as they all have these config properties). ```yaml -ethereum: +ethereum: mainnet: # Ethereum mainnet in Ape uses EIP-1559 by default, # but we can change that here. Note: most plugins