Skip to content

Commit b43fc0a

Browse files
authored
Merge pull request #319 from InjectiveLabs/feat/refactor_network_mixed_secure_insecure_channels
feat/refactor_network_mixed_secure_insecure_channels
2 parents db9b6c0 + c47c94e commit b43fc0a

File tree

6 files changed

+163
-33
lines changed

6 files changed

+163
-33
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [1.5.0] - 2024-04-19
6+
### Changed
7+
- Refactoring in Network class to support mixed secure and insecure endpoints.
8+
- Marked the Network parameter `use_secure_connection` as deprecated.
9+
510
## [1.4.2] - 2024-03-19
611
### Changed
712
- Updated `aiohttp` dependency version to ">=3.9.2" to solve a security vulnerability detected by Dependabot

pyinjective/async_client.py

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def __init__(
8888
self,
8989
network: Network,
9090
insecure: Optional[bool] = None,
91-
credentials=grpc.ssl_channel_credentials(),
91+
credentials=None,
9292
):
9393
# the `insecure` parameter is ignored and will be deprecated soon. The value is taken directly from `network`
9494
if insecure is not None:
@@ -97,6 +97,13 @@ def __init__(
9797
DeprecationWarning,
9898
stacklevel=2,
9999
)
100+
# the `credentials` parameter is ignored and will be deprecated soon. The value is taken directly from `network`
101+
if credentials is not None:
102+
warn(
103+
"credentials parameter in AsyncClient is no longer used and will be deprecated",
104+
DeprecationWarning,
105+
stacklevel=2,
106+
)
100107

101108
self.addr = ""
102109
self.number = 0
@@ -105,11 +112,7 @@ def __init__(
105112
self.network = network
106113

107114
# chain stubs
108-
self.chain_channel = (
109-
grpc.aio.secure_channel(network.grpc_endpoint, credentials)
110-
if (network.use_secure_connection and credentials is not None)
111-
else grpc.aio.insecure_channel(network.grpc_endpoint)
112-
)
115+
self.chain_channel = self.network.create_chain_grpc_channel()
113116

114117
self.stubCosmosTendermint = tendermint_query_grpc.ServiceStub(self.chain_channel)
115118
self.stubAuth = auth_query_grpc.QueryStub(self.chain_channel)
@@ -121,11 +124,7 @@ def __init__(
121124
self.timeout_height = 1
122125

123126
# exchange stubs
124-
self.exchange_channel = (
125-
grpc.aio.secure_channel(network.grpc_exchange_endpoint, credentials)
126-
if (network.use_secure_connection and credentials is not None)
127-
else grpc.aio.insecure_channel(network.grpc_exchange_endpoint)
128-
)
127+
self.exchange_channel = self.network.create_exchange_grpc_channel()
129128
self.stubMeta = exchange_meta_rpc_grpc.InjectiveMetaRPCStub(self.exchange_channel)
130129
self.stubExchangeAccount = exchange_accounts_rpc_grpc.InjectiveAccountsRPCStub(self.exchange_channel)
131130
self.stubOracle = oracle_rpc_grpc.InjectiveOracleRPCStub(self.exchange_channel)
@@ -138,18 +137,10 @@ def __init__(
138137
self.stubPortfolio = portfolio_rpc_grpc.InjectivePortfolioRPCStub(self.exchange_channel)
139138

140139
# explorer stubs
141-
self.explorer_channel = (
142-
grpc.aio.secure_channel(network.grpc_explorer_endpoint, credentials)
143-
if (network.use_secure_connection and credentials is not None)
144-
else grpc.aio.insecure_channel(network.grpc_explorer_endpoint)
145-
)
140+
self.explorer_channel = self.network.create_explorer_grpc_channel()
146141
self.stubExplorer = explorer_rpc_grpc.InjectiveExplorerRPCStub(self.explorer_channel)
147142

148-
self.chain_stream_channel = (
149-
grpc.aio.secure_channel(network.chain_stream_endpoint, credentials)
150-
if (network.use_secure_connection and credentials is not None)
151-
else grpc.aio.insecure_channel(network.chain_stream_endpoint)
152-
)
143+
self.chain_stream_channel = self.network.create_chain_stream_grpc_channel()
153144
self.chain_stream_stub = stream_rpc_grpc.StreamStub(channel=self.chain_stream_channel)
154145

155146
self._timeout_height_sync_task = None

pyinjective/core/network.py

Lines changed: 101 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
from abc import ABC, abstractmethod
55
from http.cookies import SimpleCookie
66
from typing import Callable, Optional, Tuple
7+
from warnings import warn
8+
9+
import grpc
10+
from grpc import ChannelCredentials
711

812

913
class CookieAssistant(ABC):
@@ -181,8 +185,20 @@ def __init__(
181185
fee_denom: str,
182186
env: str,
183187
cookie_assistant: CookieAssistant,
184-
use_secure_connection: bool = False,
188+
use_secure_connection: Optional[bool] = None,
189+
grpc_channel_credentials: Optional[ChannelCredentials] = None,
190+
grpc_exchange_channel_credentials: Optional[ChannelCredentials] = None,
191+
grpc_explorer_channel_credentials: Optional[ChannelCredentials] = None,
192+
chain_stream_channel_credentials: Optional[ChannelCredentials] = None,
185193
):
194+
# the `use_secure_connection` parameter is ignored and will be deprecated soon.
195+
if use_secure_connection is not None:
196+
warn(
197+
"use_secure_connection parameter in Network is no longer used and will be deprecated",
198+
DeprecationWarning,
199+
stacklevel=2,
200+
)
201+
186202
self.lcd_endpoint = lcd_endpoint
187203
self.tm_websocket_endpoint = tm_websocket_endpoint
188204
self.grpc_endpoint = grpc_endpoint
@@ -193,7 +209,10 @@ def __init__(
193209
self.fee_denom = fee_denom
194210
self.env = env
195211
self.cookie_assistant = cookie_assistant
196-
self.use_secure_connection = use_secure_connection
212+
self.grpc_channel_credentials = grpc_channel_credentials
213+
self.grpc_exchange_channel_credentials = grpc_exchange_channel_credentials
214+
self.grpc_explorer_channel_credentials = grpc_explorer_channel_credentials
215+
self.chain_stream_channel_credentials = chain_stream_channel_credentials
197216

198217
@classmethod
199218
def devnet(cls):
@@ -219,6 +238,11 @@ def testnet(cls, node="lb"):
219238
if node not in nodes:
220239
raise ValueError("Must be one of {}".format(nodes))
221240

241+
grpc_channel_credentials = grpc.ssl_channel_credentials()
242+
grpc_exchange_channel_credentials = grpc.ssl_channel_credentials()
243+
grpc_explorer_channel_credentials = grpc.ssl_channel_credentials()
244+
chain_stream_channel_credentials = grpc.ssl_channel_credentials()
245+
222246
if node == "lb":
223247
lcd_endpoint = "https://testnet.sentry.lcd.injective.network:443"
224248
tm_websocket_endpoint = "wss://testnet.sentry.tm.injective.network:443/websocket"
@@ -227,7 +251,6 @@ def testnet(cls, node="lb"):
227251
grpc_explorer_endpoint = "testnet.sentry.explorer.grpc.injective.network:443"
228252
chain_stream_endpoint = "testnet.sentry.chain.stream.injective.network:443"
229253
cookie_assistant = BareMetalLoadBalancedCookieAssistant()
230-
use_secure_connection = True
231254
else:
232255
lcd_endpoint = "https://testnet.lcd.injective.network:443"
233256
tm_websocket_endpoint = "wss://testnet.tm.injective.network:443/websocket"
@@ -236,7 +259,6 @@ def testnet(cls, node="lb"):
236259
grpc_explorer_endpoint = "testnet.explorer.grpc.injective.network:443"
237260
chain_stream_endpoint = "testnet.chain.stream.injective.network:443"
238261
cookie_assistant = DisabledCookieAssistant()
239-
use_secure_connection = True
240262

241263
return cls(
242264
lcd_endpoint=lcd_endpoint,
@@ -249,7 +271,10 @@ def testnet(cls, node="lb"):
249271
fee_denom="inj",
250272
env="testnet",
251273
cookie_assistant=cookie_assistant,
252-
use_secure_connection=use_secure_connection,
274+
grpc_channel_credentials=grpc_channel_credentials,
275+
grpc_exchange_channel_credentials=grpc_exchange_channel_credentials,
276+
grpc_explorer_channel_credentials=grpc_explorer_channel_credentials,
277+
chain_stream_channel_credentials=chain_stream_channel_credentials,
253278
)
254279

255280
@classmethod
@@ -267,7 +292,10 @@ def mainnet(cls, node="lb"):
267292
grpc_explorer_endpoint = "sentry.explorer.grpc.injective.network:443"
268293
chain_stream_endpoint = "sentry.chain.stream.injective.network:443"
269294
cookie_assistant = BareMetalLoadBalancedCookieAssistant()
270-
use_secure_connection = True
295+
grpc_channel_credentials = grpc.ssl_channel_credentials()
296+
grpc_exchange_channel_credentials = grpc.ssl_channel_credentials()
297+
grpc_explorer_channel_credentials = grpc.ssl_channel_credentials()
298+
chain_stream_channel_credentials = grpc.ssl_channel_credentials()
271299

272300
return cls(
273301
lcd_endpoint=lcd_endpoint,
@@ -280,7 +308,10 @@ def mainnet(cls, node="lb"):
280308
fee_denom="inj",
281309
env="mainnet",
282310
cookie_assistant=cookie_assistant,
283-
use_secure_connection=use_secure_connection,
311+
grpc_channel_credentials=grpc_channel_credentials,
312+
grpc_exchange_channel_credentials=grpc_exchange_channel_credentials,
313+
grpc_explorer_channel_credentials=grpc_explorer_channel_credentials,
314+
chain_stream_channel_credentials=chain_stream_channel_credentials,
284315
)
285316

286317
@classmethod
@@ -296,7 +327,6 @@ def local(cls):
296327
fee_denom="inj",
297328
env="local",
298329
cookie_assistant=DisabledCookieAssistant(),
299-
use_secure_connection=False,
300330
)
301331

302332
@classmethod
@@ -311,8 +341,20 @@ def custom(
311341
chain_id,
312342
env,
313343
cookie_assistant: Optional[CookieAssistant] = None,
314-
use_secure_connection: bool = False,
344+
use_secure_connection: Optional[bool] = None,
345+
grpc_channel_credentials: Optional[ChannelCredentials] = None,
346+
grpc_exchange_channel_credentials: Optional[ChannelCredentials] = None,
347+
grpc_explorer_channel_credentials: Optional[ChannelCredentials] = None,
348+
chain_stream_channel_credentials: Optional[ChannelCredentials] = None,
315349
):
350+
# the `use_secure_connection` parameter is ignored and will be deprecated soon.
351+
if use_secure_connection is not None:
352+
warn(
353+
"use_secure_connection parameter in Network is no longer used and will be deprecated",
354+
DeprecationWarning,
355+
stacklevel=2,
356+
)
357+
316358
assistant = cookie_assistant or DisabledCookieAssistant()
317359
return cls(
318360
lcd_endpoint=lcd_endpoint,
@@ -325,7 +367,37 @@ def custom(
325367
fee_denom="inj",
326368
env=env,
327369
cookie_assistant=assistant,
328-
use_secure_connection=use_secure_connection,
370+
grpc_channel_credentials=grpc_channel_credentials,
371+
grpc_exchange_channel_credentials=grpc_exchange_channel_credentials,
372+
grpc_explorer_channel_credentials=grpc_explorer_channel_credentials,
373+
chain_stream_channel_credentials=chain_stream_channel_credentials,
374+
)
375+
376+
@classmethod
377+
def custom_chain_and_public_indexer_mainnet(
378+
cls,
379+
lcd_endpoint,
380+
tm_websocket_endpoint,
381+
grpc_endpoint,
382+
chain_stream_endpoint,
383+
cookie_assistant: Optional[CookieAssistant] = None,
384+
):
385+
mainnet_network = cls.mainnet()
386+
387+
return cls.custom(
388+
lcd_endpoint=lcd_endpoint,
389+
tm_websocket_endpoint=tm_websocket_endpoint,
390+
grpc_endpoint=grpc_endpoint,
391+
grpc_exchange_endpoint=mainnet_network.grpc_exchange_endpoint,
392+
grpc_explorer_endpoint=mainnet_network.grpc_explorer_endpoint,
393+
chain_stream_endpoint=chain_stream_endpoint,
394+
chain_id="injective-1",
395+
env="mainnet",
396+
cookie_assistant=cookie_assistant,
397+
grpc_channel_credentials=None,
398+
grpc_exchange_channel_credentials=mainnet_network.grpc_exchange_channel_credentials,
399+
grpc_explorer_channel_credentials=mainnet_network.grpc_explorer_channel_credentials,
400+
chain_stream_channel_credentials=None,
329401
)
330402

331403
def string(self):
@@ -336,3 +408,22 @@ async def chain_metadata(self, metadata_query_provider: Callable) -> Tuple[Tuple
336408

337409
async def exchange_metadata(self, metadata_query_provider: Callable) -> Tuple[Tuple[str, str]]:
338410
return await self.cookie_assistant.exchange_metadata(metadata_query_provider=metadata_query_provider)
411+
412+
def create_chain_grpc_channel(self) -> grpc.Channel:
413+
return self._create_grpc_channel(self.grpc_endpoint, self.grpc_channel_credentials)
414+
415+
def create_exchange_grpc_channel(self) -> grpc.Channel:
416+
return self._create_grpc_channel(self.grpc_exchange_endpoint, self.grpc_exchange_channel_credentials)
417+
418+
def create_explorer_grpc_channel(self) -> grpc.Channel:
419+
return self._create_grpc_channel(self.grpc_explorer_endpoint, self.grpc_explorer_channel_credentials)
420+
421+
def create_chain_stream_grpc_channel(self) -> grpc.Channel:
422+
return self._create_grpc_channel(self.chain_stream_endpoint, self.chain_stream_channel_credentials)
423+
424+
def _create_grpc_channel(self, endpoint: str, credentials: Optional[ChannelCredentials]) -> grpc.Channel:
425+
if credentials is None:
426+
channel = grpc.aio.insecure_channel(endpoint)
427+
else:
428+
channel = grpc.aio.secure_channel(endpoint, credentials)
429+
return channel

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "injective-py"
3-
version = "1.4.2"
3+
version = "1.5.0"
44
description = "Injective Python SDK, with Exchange API Client"
55
authors = ["Injective Labs <contact@injectivelabs.org>"]
66
license = "Apache-2.0"
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from warnings import catch_warnings
2+
3+
from pyinjective.core.network import DisabledCookieAssistant, Network
4+
5+
6+
class TestNetworkDeprecationWarnings:
7+
def test_use_secure_connection_parameter_deprecation_warning(self):
8+
with catch_warnings(record=True) as all_warnings:
9+
Network(
10+
lcd_endpoint="lcd_endpoint",
11+
tm_websocket_endpoint="tm_websocket_endpoint",
12+
grpc_endpoint="grpc_endpoint",
13+
grpc_exchange_endpoint="grpc_exchange_endpoint",
14+
grpc_explorer_endpoint="grpc_explorer_endpoint",
15+
chain_stream_endpoint="chain_stream_endpoint",
16+
chain_id="chain_id",
17+
fee_denom="fee_denom",
18+
env="env",
19+
cookie_assistant=DisabledCookieAssistant(),
20+
use_secure_connection=True,
21+
)
22+
23+
deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)]
24+
assert len(deprecation_warnings) == 1
25+
assert (
26+
str(deprecation_warnings[0].message)
27+
== "use_secure_connection parameter in Network is no longer used and will be deprecated"
28+
)

tests/test_async_client_deprecation_warnings.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from warnings import catch_warnings
22

3+
import grpc
34
import pytest
45

56
from pyinjective.async_client import AsyncClient
@@ -579,7 +580,7 @@ async def test_get_oracle_prices_deprecation_warning(
579580
assert str(deprecation_warnings[0].message) == "This method is deprecated. Use fetch_oracle_price instead"
580581

581582
@pytest.mark.asyncio
582-
async def test_stream_keepalive_deprecation_warning(
583+
async def test_stream_oracle_prices_deprecation_warning(
583584
self,
584585
oracle_servicer,
585586
):
@@ -1682,3 +1683,17 @@ async def test_chain_stream_deprecation_warning(
16821683
assert (
16831684
str(deprecation_warnings[0].message) == "This method is deprecated. Use listen_chain_stream_updates instead"
16841685
)
1686+
1687+
def test_credentials_parameter_deprecation_warning(
1688+
self,
1689+
auth_servicer,
1690+
):
1691+
with catch_warnings(record=True) as all_warnings:
1692+
AsyncClient(network=Network.local(), credentials=grpc.ssl_channel_credentials())
1693+
1694+
deprecation_warnings = [warning for warning in all_warnings if issubclass(warning.category, DeprecationWarning)]
1695+
assert len(deprecation_warnings) == 1
1696+
assert (
1697+
str(deprecation_warnings[0].message)
1698+
== "credentials parameter in AsyncClient is no longer used and will be deprecated"
1699+
)

0 commit comments

Comments
 (0)