olas-operate-middleware 0.9.0__py3-none-any.whl → 0.10.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {olas_operate_middleware-0.9.0.dist-info → olas_operate_middleware-0.10.1.dist-info}/METADATA +1 -1
- {olas_operate_middleware-0.9.0.dist-info → olas_operate_middleware-0.10.1.dist-info}/RECORD +30 -30
- operate/bridge/bridge_manager.py +2 -3
- operate/bridge/providers/native_bridge_provider.py +1 -1
- operate/bridge/providers/provider.py +2 -3
- operate/bridge/providers/relay_provider.py +9 -1
- operate/cli.py +123 -43
- operate/constants.py +5 -0
- operate/keys.py +26 -14
- operate/ledger/profiles.py +1 -3
- operate/migration.py +288 -21
- operate/operate_types.py +9 -6
- operate/quickstart/analyse_logs.py +1 -4
- operate/quickstart/claim_staking_rewards.py +0 -3
- operate/quickstart/reset_configs.py +0 -3
- operate/quickstart/reset_password.py +0 -3
- operate/quickstart/reset_staking.py +2 -4
- operate/quickstart/run_service.py +3 -5
- operate/quickstart/stop_service.py +0 -3
- operate/quickstart/terminate_on_chain_service.py +0 -3
- operate/services/deployment_runner.py +170 -38
- operate/services/health_checker.py +3 -2
- operate/services/manage.py +90 -123
- operate/services/service.py +15 -225
- operate/utils/__init__.py +44 -0
- operate/utils/gnosis.py +22 -12
- operate/wallet/master.py +16 -20
- {olas_operate_middleware-0.9.0.dist-info → olas_operate_middleware-0.10.1.dist-info}/LICENSE +0 -0
- {olas_operate_middleware-0.9.0.dist-info → olas_operate_middleware-0.10.1.dist-info}/WHEEL +0 -0
- {olas_operate_middleware-0.9.0.dist-info → olas_operate_middleware-0.10.1.dist-info}/entry_points.txt +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
operate/__init__.py,sha256=ZQhHXOo_1L9Q5Ub_2FrZ-vu3BvORBrKgK8QcJyAsYa4,870
|
|
2
2
|
operate/account/__init__.py,sha256=suJ_vBMO7hLCvLYe3MVDtLXTNDd6P03og7bvUN7fZsE,804
|
|
3
3
|
operate/account/user.py,sha256=y7DqqDpqgHjbVmnfL_cN0Me_JWl3Dh6GSVt2-9FdRVw,3044
|
|
4
|
-
operate/bridge/bridge_manager.py,sha256=
|
|
4
|
+
operate/bridge/bridge_manager.py,sha256=sUfhB1pZvBrF-kBfDOfFVoNeesCe7wd4_YahUF3FZDU,17119
|
|
5
5
|
operate/bridge/providers/lifi_provider.py,sha256=FpAlBAA_gOt-oOHKhGaOQhhTZIL-hgYYo4IIw1FN7mo,14153
|
|
6
|
-
operate/bridge/providers/native_bridge_provider.py,sha256=
|
|
7
|
-
operate/bridge/providers/provider.py,sha256=
|
|
8
|
-
operate/bridge/providers/relay_provider.py,sha256=
|
|
9
|
-
operate/cli.py,sha256=
|
|
10
|
-
operate/constants.py,sha256=
|
|
6
|
+
operate/bridge/providers/native_bridge_provider.py,sha256=gG8bSyxUoAVEF6_J9tn1qKRv1PnXuMJdMwUAVJ4GJz8,24647
|
|
7
|
+
operate/bridge/providers/provider.py,sha256=i54RL7m4wMSADM_D_V_quQump_ipPTmByUc-c-AOLPQ,19687
|
|
8
|
+
operate/bridge/providers/relay_provider.py,sha256=U_l7qP8jCbGYvPaoUf82MAS8V8OoizqSLTuJs763JGY,17075
|
|
9
|
+
operate/cli.py,sha256=EalpBA15TXX5i3tD-2KIQOxkFwEOqOEiGMbjh36cOHw,51168
|
|
10
|
+
operate/constants.py,sha256=syGWEVyw07zK50gPS4OSSwyAbt9R6P8IttDimDt9vCY,2746
|
|
11
11
|
operate/data/README.md,sha256=jGPyZTvg2LCGdllvmYxmFMkkkiXb6YWatbqIkcX3kv4,879
|
|
12
12
|
operate/data/__init__.py,sha256=ttC51Yqk9c4ehpIgs1Qbe7aJvzkrbbdZ1ClaCxJYByE,864
|
|
13
13
|
operate/data/contracts/__init__.py,sha256=_th54_WvL0ibGy-b6St0Ne9DX-fyjsh-tNOKDn-cWrg,809
|
|
@@ -53,41 +53,41 @@ operate/data/contracts/uniswap_v2_erc20/contract.py,sha256=MwBks4QmZ3XouMT_TqWLn
|
|
|
53
53
|
operate/data/contracts/uniswap_v2_erc20/contract.yaml,sha256=XUdz-XtKtmZgLfItbO8usP-QPbtUkAxKGn0hL7OftAg,741
|
|
54
54
|
operate/data/contracts/uniswap_v2_erc20/tests/__init__.py,sha256=3Arw8dsCsJz6hVOl0t9UjFASHXbV9yp3hw6x4HqgXpU,847
|
|
55
55
|
operate/data/contracts/uniswap_v2_erc20/tests/test_contract.py,sha256=FzZbw9OTcr_yvjOXpk9YcO-K40eyDARyybcfSHDg2Ps,13392
|
|
56
|
-
operate/keys.py,sha256=
|
|
56
|
+
operate/keys.py,sha256=y8QMQcKOqvL62egbJyX6FgFgnxdT3tbxHrRVCmWXJMI,4371
|
|
57
57
|
operate/ledger/__init__.py,sha256=ksyctDd5PU_SToN9e-_N9fAap9ZNCHw48j5hHep-erA,3353
|
|
58
|
-
operate/ledger/profiles.py,sha256=
|
|
59
|
-
operate/migration.py,sha256=
|
|
58
|
+
operate/ledger/profiles.py,sha256=fQ9vqnXCIBZa3VHZKIvrJ-Jhn_SckFUcPC94JM5brQ8,12343
|
|
59
|
+
operate/migration.py,sha256=YIJ9P8CdW2IsMm4gW9GdAJ7EKMnUfUMUB5TItiQ0dH8,15323
|
|
60
60
|
operate/operate_http/__init__.py,sha256=dxCIVSUos23M4R-PFZZG6k5QrOlEiK0SxhCYSFNxh7U,4711
|
|
61
61
|
operate/operate_http/exceptions.py,sha256=4UFzrn-GyDD71RhkaOyFPBynL6TrrtP3eywaaU3o4fc,1339
|
|
62
|
-
operate/operate_types.py,sha256=
|
|
62
|
+
operate/operate_types.py,sha256=DmQBVu-WPYGrrRwKU30QmF99JheFQo666GxP5ObHgAw,8033
|
|
63
63
|
operate/pearl.py,sha256=yrTpSXLu_ML3qT-uNxq3kScOyo31JyxBujiSMfMUbcg,1690
|
|
64
|
-
operate/quickstart/analyse_logs.py,sha256=
|
|
65
|
-
operate/quickstart/claim_staking_rewards.py,sha256=
|
|
66
|
-
operate/quickstart/reset_configs.py,sha256=
|
|
67
|
-
operate/quickstart/reset_password.py,sha256=
|
|
68
|
-
operate/quickstart/reset_staking.py,sha256=
|
|
69
|
-
operate/quickstart/run_service.py,sha256=
|
|
70
|
-
operate/quickstart/stop_service.py,sha256=
|
|
71
|
-
operate/quickstart/terminate_on_chain_service.py,sha256=
|
|
64
|
+
operate/quickstart/analyse_logs.py,sha256=K11AWWevkddUIUzTe75J3fYVS6aLfi6kT_dAI9OjrX8,4195
|
|
65
|
+
operate/quickstart/claim_staking_rewards.py,sha256=AqfLMRef2YijQtWPaTuGwX2sOItNEkoyoi6Q9SICp_I,4026
|
|
66
|
+
operate/quickstart/reset_configs.py,sha256=ipPpbYyB9gQ4KOKS-xBrRi8fT5LvwctSkQi-8XiUMig,3341
|
|
67
|
+
operate/quickstart/reset_password.py,sha256=p_gNmhWD4hb-QXUAiQRalPtVTVyB5TEPhs7GnScYzqs,2535
|
|
68
|
+
operate/quickstart/reset_staking.py,sha256=GLGUzSz6H_5lUXb9j9jFrgni_vtDXnWpPKK53favXbg,5077
|
|
69
|
+
operate/quickstart/run_service.py,sha256=fKeHtEiRmOg5wt3skKvKpxHhO-u-fpoF7_5YUnAM9Sg,27224
|
|
70
|
+
operate/quickstart/stop_service.py,sha256=gyLgPNG6IkI6eyRkIVWEVo9p15hLJyZouFPEVCK2t6I,2036
|
|
71
|
+
operate/quickstart/terminate_on_chain_service.py,sha256=5ENU8_mkj06i80lKUX-v1QbLU0YzKeOZDUL1e_jzySE,2914
|
|
72
72
|
operate/quickstart/utils.py,sha256=rmd9e7whQIsYpRKqWBEQxMA_SHrivBg6DppFY5ECtQQ,9135
|
|
73
73
|
operate/resource.py,sha256=E59oIVqf6B6nN4LTmf_o2iCgLFAogTLPjm_cK6kMVxg,6305
|
|
74
74
|
operate/services/__init__.py,sha256=isrThS-Ccu5Sc15JZgkN4uTAVaSg-NwUUSDeTyJEqLk,855
|
|
75
75
|
operate/services/agent_runner.py,sha256=6tJePUJmlRxlIugT2fDaCJHSrQlDnl1t9pbg3-7EmCQ,7560
|
|
76
|
-
operate/services/deployment_runner.py,sha256=
|
|
77
|
-
operate/services/health_checker.py,sha256=
|
|
78
|
-
operate/services/manage.py,sha256=
|
|
76
|
+
operate/services/deployment_runner.py,sha256=Su73o7cdH6fkQfj468K77J04a_TWiokJwbMyVQ25xko,27067
|
|
77
|
+
operate/services/health_checker.py,sha256=2KSEDxG3YmGolUDU--648ny0UJpTAAKvxkcr_VZQv-I,9654
|
|
78
|
+
operate/services/manage.py,sha256=qaLLwAhksZXvc1Jbbmej9jkF7ObSAGJsIWaPhgfSUoM,108048
|
|
79
79
|
operate/services/protocol.py,sha256=RQssnJyjHc0k1CyZCj3jxHueyJyS3nmFYw4dVQaKXzA,60157
|
|
80
|
-
operate/services/service.py,sha256=
|
|
80
|
+
operate/services/service.py,sha256=ltKox10YC1VINGqdlVqy2nPXkR7XCHoysSGKMngPTSU,39669
|
|
81
81
|
operate/services/utils/__init__.py,sha256=TvioaZ1mfTRUSCtrQoLNAp4WMVXyqEJqFJM4PxSQCRU,24
|
|
82
82
|
operate/services/utils/mech.py,sha256=W2x4dqodivNKXjWU-Brp40QhoUHsIMyNAO7-caMoR0Q,3821
|
|
83
83
|
operate/services/utils/tendermint.py,sha256=3h9nDb2Z89T0RwUr_AaVjqtymQmsu3u6DAVCfL_k1U0,25591
|
|
84
|
-
operate/utils/__init__.py,sha256=
|
|
85
|
-
operate/utils/gnosis.py,sha256=
|
|
84
|
+
operate/utils/__init__.py,sha256=DZNUgg0V9yfNfDrUynp10PErSieJkoxU0AKvsEFIhAw,4670
|
|
85
|
+
operate/utils/gnosis.py,sha256=CS07ZqvrO7uelkFe09VMyPBcLzKONUI1ZqFvi41BDhc,17924
|
|
86
86
|
operate/utils/ssl.py,sha256=O5DrDoZD4T4qQuHP8GLwWUVxQ-1qXeefGp6uDJiF2lM,4308
|
|
87
87
|
operate/wallet/__init__.py,sha256=NGiozD3XhvkBi7_FaOWQ8x1thZPK4uGpokJaeDY_o2w,813
|
|
88
|
-
operate/wallet/master.py,sha256=
|
|
89
|
-
olas_operate_middleware-0.
|
|
90
|
-
olas_operate_middleware-0.
|
|
91
|
-
olas_operate_middleware-0.
|
|
92
|
-
olas_operate_middleware-0.
|
|
93
|
-
olas_operate_middleware-0.
|
|
88
|
+
operate/wallet/master.py,sha256=MGXynIV0LQU3n28AceK7RlaxAtfsVowsXzisesG4iJM,30760
|
|
89
|
+
olas_operate_middleware-0.10.1.dist-info/LICENSE,sha256=mdBDB-mWKV5Cz4ejBzBiKqan6Z8zVLAh9xwM64O2FW4,11339
|
|
90
|
+
olas_operate_middleware-0.10.1.dist-info/METADATA,sha256=-wfA1j-OSW-M2y-jxSEYO0lEHq8czpmQB2wcgF6pnc4,2034
|
|
91
|
+
olas_operate_middleware-0.10.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
92
|
+
olas_operate_middleware-0.10.1.dist-info/entry_points.txt,sha256=dM1g2I7ODApKQFcgl5J4NGA7pfBTo6qsUTXM-j2OLlw,44
|
|
93
|
+
olas_operate_middleware-0.10.1.dist-info/RECORD,,
|
operate/bridge/bridge_manager.py
CHANGED
|
@@ -29,7 +29,6 @@ from dataclasses import dataclass
|
|
|
29
29
|
from pathlib import Path
|
|
30
30
|
from typing import cast
|
|
31
31
|
|
|
32
|
-
from aea.helpers.logging import setup_logger
|
|
33
32
|
from deepdiff import DeepDiff
|
|
34
33
|
from web3 import Web3
|
|
35
34
|
|
|
@@ -187,13 +186,13 @@ class BridgeManager:
|
|
|
187
186
|
self,
|
|
188
187
|
path: Path,
|
|
189
188
|
wallet_manager: MasterWalletManager,
|
|
190
|
-
logger:
|
|
189
|
+
logger: logging.Logger,
|
|
191
190
|
quote_validity_period: int = DEFAULT_BUNDLE_VALIDITY_PERIOD,
|
|
192
191
|
) -> None:
|
|
193
192
|
"""Initialize bridge manager."""
|
|
194
193
|
self.path = path
|
|
195
194
|
self.wallet_manager = wallet_manager
|
|
196
|
-
self.logger = logger
|
|
195
|
+
self.logger = logger
|
|
197
196
|
self.quote_validity_period = quote_validity_period
|
|
198
197
|
self.path.mkdir(exist_ok=True)
|
|
199
198
|
(self.path / EXECUTED_BUNDLES_PATH).mkdir(exist_ok=True)
|
|
@@ -417,7 +417,7 @@ class NativeBridgeProvider(Provider):
|
|
|
417
417
|
bridge_contract_adaptor: BridgeContractAdaptor,
|
|
418
418
|
provider_id: str,
|
|
419
419
|
wallet_manager: MasterWalletManager,
|
|
420
|
-
logger:
|
|
420
|
+
logger: logging.Logger,
|
|
421
421
|
) -> None:
|
|
422
422
|
"""Initialize the provider."""
|
|
423
423
|
self.bridge_contract_adaptor = bridge_contract_adaptor
|
|
@@ -31,7 +31,6 @@ from dataclasses import dataclass
|
|
|
31
31
|
from math import ceil
|
|
32
32
|
|
|
33
33
|
from aea.crypto.base import LedgerApi
|
|
34
|
-
from aea.helpers.logging import setup_logger
|
|
35
34
|
from autonomy.chain.tx import TxSettler
|
|
36
35
|
from web3 import Web3
|
|
37
36
|
from web3.middleware import geth_poa_middleware
|
|
@@ -145,12 +144,12 @@ class Provider(ABC):
|
|
|
145
144
|
self,
|
|
146
145
|
wallet_manager: MasterWalletManager,
|
|
147
146
|
provider_id: str,
|
|
148
|
-
logger:
|
|
147
|
+
logger: logging.Logger,
|
|
149
148
|
) -> None:
|
|
150
149
|
"""Initialize the provider."""
|
|
151
150
|
self.wallet_manager = wallet_manager
|
|
152
151
|
self.provider_id = provider_id
|
|
153
|
-
self.logger = logger
|
|
152
|
+
self.logger = logger
|
|
154
153
|
|
|
155
154
|
def description(self) -> str:
|
|
156
155
|
"""Get a human-readable description of the provider."""
|
|
@@ -396,7 +396,15 @@ class RelayProvider(Provider):
|
|
|
396
396
|
)
|
|
397
397
|
from_ledger_api = self._from_ledger_api(provider_request)
|
|
398
398
|
to_ledger_api = self._to_ledger_api(provider_request)
|
|
399
|
-
|
|
399
|
+
|
|
400
|
+
if (
|
|
401
|
+
response_json["requests"][0]["data"]["outTxs"][0]["chainId"]
|
|
402
|
+
== response_json["requests"][0]["data"]["inTxs"][0]["chainId"]
|
|
403
|
+
):
|
|
404
|
+
to_tx_hash = from_tx_hash # Should match response_json["requests"][0]["data"]["inTxs"][0]["hash"]
|
|
405
|
+
else:
|
|
406
|
+
to_tx_hash = response_json["requests"][0]["data"]["outTxs"][0]["hash"]
|
|
407
|
+
|
|
400
408
|
execution_data.message = response_json.get("details", None)
|
|
401
409
|
execution_data.to_tx_hash = to_tx_hash
|
|
402
410
|
execution_data.elapsed_time = Provider._tx_timestamp(
|
operate/cli.py
CHANGED
|
@@ -28,10 +28,13 @@ import traceback
|
|
|
28
28
|
import typing as t
|
|
29
29
|
import uuid
|
|
30
30
|
from concurrent.futures import ThreadPoolExecutor
|
|
31
|
+
from contextlib import asynccontextmanager, suppress
|
|
31
32
|
from http import HTTPStatus
|
|
32
33
|
from pathlib import Path
|
|
33
34
|
from types import FrameType
|
|
34
35
|
|
|
36
|
+
import psutil
|
|
37
|
+
import requests
|
|
35
38
|
from aea.helpers.logging import setup_logger
|
|
36
39
|
from clea import group, params, run
|
|
37
40
|
from compose.project import ProjectError
|
|
@@ -68,6 +71,7 @@ from operate.quickstart.reset_staking import reset_staking
|
|
|
68
71
|
from operate.quickstart.run_service import run_service
|
|
69
72
|
from operate.quickstart.stop_service import stop_service
|
|
70
73
|
from operate.quickstart.terminate_on_chain_service import terminate_service
|
|
74
|
+
from operate.services.deployment_runner import stop_deployment_manager
|
|
71
75
|
from operate.services.health_checker import HealthChecker
|
|
72
76
|
from operate.utils import subtract_dicts
|
|
73
77
|
from operate.utils.gnosis import get_assets_balances
|
|
@@ -82,6 +86,7 @@ ACCOUNT_NOT_FOUND_ERROR = JSONResponse(
|
|
|
82
86
|
content={"error": "User account not found."},
|
|
83
87
|
status_code=HTTPStatus.NOT_FOUND,
|
|
84
88
|
)
|
|
89
|
+
TRY_TO_SHUTDOWN_PREVIOUS_INSTANCE = True
|
|
85
90
|
|
|
86
91
|
|
|
87
92
|
def service_not_found_error(service_config_id: str) -> JSONResponse:
|
|
@@ -108,7 +113,7 @@ class OperateApp:
|
|
|
108
113
|
self.setup()
|
|
109
114
|
|
|
110
115
|
self.logger = logger or setup_logger(name="operate")
|
|
111
|
-
|
|
116
|
+
services.manage.KeysManager(
|
|
112
117
|
path=self._keys,
|
|
113
118
|
logger=self.logger,
|
|
114
119
|
)
|
|
@@ -116,7 +121,8 @@ class OperateApp:
|
|
|
116
121
|
|
|
117
122
|
mm = MigrationManager(self._path, self.logger)
|
|
118
123
|
mm.migrate_user_account()
|
|
119
|
-
mm.
|
|
124
|
+
mm.migrate_services(self.service_manager())
|
|
125
|
+
mm.migrate_wallets(self.wallet_manager)
|
|
120
126
|
mm.migrate_qs_configs()
|
|
121
127
|
|
|
122
128
|
def create_user_account(self, password: str) -> UserAccount:
|
|
@@ -164,7 +170,6 @@ class OperateApp:
|
|
|
164
170
|
"""Load service manager."""
|
|
165
171
|
return services.manage.ServiceManager(
|
|
166
172
|
path=self._services,
|
|
167
|
-
keys_manager=self.keys_manager,
|
|
168
173
|
wallet_manager=self.wallet_manager,
|
|
169
174
|
logger=self.logger,
|
|
170
175
|
skip_dependency_check=skip_dependency_check,
|
|
@@ -185,6 +190,7 @@ class OperateApp:
|
|
|
185
190
|
manager = MasterWalletManager(
|
|
186
191
|
path=self._path / "wallets",
|
|
187
192
|
password=self.password,
|
|
193
|
+
logger=self.logger,
|
|
188
194
|
)
|
|
189
195
|
manager.setup()
|
|
190
196
|
return manager
|
|
@@ -195,6 +201,7 @@ class OperateApp:
|
|
|
195
201
|
manager = BridgeManager(
|
|
196
202
|
path=self._path / "bridge",
|
|
197
203
|
wallet_manager=self.wallet_manager,
|
|
204
|
+
logger=self.logger,
|
|
198
205
|
)
|
|
199
206
|
return manager
|
|
200
207
|
|
|
@@ -230,26 +237,16 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
230
237
|
logger.warning("Healthchecker is off!!!")
|
|
231
238
|
operate = OperateApp(home=home, logger=logger)
|
|
232
239
|
|
|
233
|
-
operate.service_manager().log_directories()
|
|
234
|
-
logger.info("Migrating service configs...")
|
|
235
|
-
operate.service_manager().migrate_service_configs()
|
|
236
|
-
logger.info("Migrating service configs done.")
|
|
237
|
-
operate.service_manager().log_directories()
|
|
238
|
-
|
|
239
|
-
logger.info("Migrating wallet configs...")
|
|
240
|
-
operate.wallet_manager.migrate_wallet_configs()
|
|
241
|
-
logger.info("Migrating wallet configs done.")
|
|
242
|
-
|
|
243
240
|
funding_jobs: t.Dict[str, asyncio.Task] = {}
|
|
244
241
|
health_checker = HealthChecker(
|
|
245
|
-
operate.service_manager(), number_of_fails=number_of_fails
|
|
242
|
+
operate.service_manager(), number_of_fails=number_of_fails, logger=logger
|
|
246
243
|
)
|
|
247
244
|
# Create shutdown endpoint
|
|
248
245
|
shutdown_endpoint = uuid.uuid4().hex
|
|
249
246
|
(operate._path / "operate.kill").write_text( # pylint: disable=protected-access
|
|
250
247
|
shutdown_endpoint
|
|
251
248
|
)
|
|
252
|
-
thread_pool_executor = ThreadPoolExecutor()
|
|
249
|
+
thread_pool_executor = ThreadPoolExecutor(max_workers=12)
|
|
253
250
|
|
|
254
251
|
async def run_in_executor(fn: t.Callable, *args: t.Any) -> t.Any:
|
|
255
252
|
loop = asyncio.get_event_loop()
|
|
@@ -301,6 +298,12 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
301
298
|
logger.info("Stopping services on startup done.")
|
|
302
299
|
|
|
303
300
|
def pause_all_services() -> None:
|
|
301
|
+
service_manager = operate.service_manager()
|
|
302
|
+
if not service_manager.validate_services():
|
|
303
|
+
logger.error(
|
|
304
|
+
"Some services are not valid. Only pausing the valid services."
|
|
305
|
+
)
|
|
306
|
+
|
|
304
307
|
service_config_ids = [
|
|
305
308
|
i["service_config_id"] for i in operate.service_manager().json
|
|
306
309
|
]
|
|
@@ -319,7 +322,12 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
319
322
|
if deployment.status == DeploymentStatus.DELETED:
|
|
320
323
|
continue
|
|
321
324
|
logger.info(f"stopping service {service_config_id}")
|
|
322
|
-
|
|
325
|
+
try:
|
|
326
|
+
deployment.stop(force=True)
|
|
327
|
+
except Exception: # pylint: disable=broad-except
|
|
328
|
+
logger.exception(
|
|
329
|
+
f"Deployment {service_config_id} stopping failed. but continue"
|
|
330
|
+
)
|
|
323
331
|
logger.info(f"Cancelling funding job for {service_config_id}")
|
|
324
332
|
cancel_funding_job(service_config_id=service_config_id)
|
|
325
333
|
health_checker.stop_for_service(service_config_id=service_config_id)
|
|
@@ -338,7 +346,51 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
338
346
|
# stop all services at middleware exit
|
|
339
347
|
atexit.register(pause_all_services)
|
|
340
348
|
|
|
341
|
-
|
|
349
|
+
@asynccontextmanager
|
|
350
|
+
async def lifespan(app: FastAPI):
|
|
351
|
+
# Load the ML model
|
|
352
|
+
watchdog_task = set_parent_watchdog(app)
|
|
353
|
+
yield
|
|
354
|
+
# Clean up the ML models and release the resources
|
|
355
|
+
|
|
356
|
+
with suppress(Exception):
|
|
357
|
+
watchdog_task.cancel()
|
|
358
|
+
|
|
359
|
+
with suppress(Exception):
|
|
360
|
+
await watchdog_task
|
|
361
|
+
|
|
362
|
+
app = FastAPI(lifespan=lifespan)
|
|
363
|
+
|
|
364
|
+
def set_parent_watchdog(app):
|
|
365
|
+
async def stop_app():
|
|
366
|
+
logger.info("Stopping services on demand...")
|
|
367
|
+
|
|
368
|
+
stop_deployment_manager() # TODO: make it async?
|
|
369
|
+
await run_in_executor(pause_all_services)
|
|
370
|
+
|
|
371
|
+
logger.info("Stopping services on demand done.")
|
|
372
|
+
app._server.should_exit = True # pylint: disable=protected-access
|
|
373
|
+
logger.info("Stopping app.")
|
|
374
|
+
|
|
375
|
+
async def check_parent_alive():
|
|
376
|
+
try:
|
|
377
|
+
logger.info(
|
|
378
|
+
f"Parent alive check task started: ppid is {os.getppid()} and own pid is {os.getpid()}"
|
|
379
|
+
)
|
|
380
|
+
while True:
|
|
381
|
+
parent = psutil.Process(os.getpid()).parent()
|
|
382
|
+
if not parent:
|
|
383
|
+
logger.info("Parent is not alive, going to stop")
|
|
384
|
+
await stop_app()
|
|
385
|
+
return
|
|
386
|
+
await asyncio.sleep(3)
|
|
387
|
+
|
|
388
|
+
except Exception: # pylint: disable=broad-except
|
|
389
|
+
logger.exception("Parent alive check crashed!")
|
|
390
|
+
|
|
391
|
+
loop = asyncio.get_running_loop()
|
|
392
|
+
task = loop.create_task(check_parent_alive())
|
|
393
|
+
return task
|
|
342
394
|
|
|
343
395
|
app.add_middleware(
|
|
344
396
|
CORSMiddleware,
|
|
@@ -382,16 +434,17 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
382
434
|
async def _kill_server(request: Request) -> JSONResponse:
|
|
383
435
|
"""Kill backend server from inside."""
|
|
384
436
|
os.kill(os.getpid(), signal.SIGINT)
|
|
437
|
+
return JSONResponse(content={})
|
|
385
438
|
|
|
386
439
|
@app.get("/shutdown")
|
|
387
440
|
async def _shutdown(request: Request) -> JSONResponse:
|
|
388
441
|
"""Kill backend server from inside."""
|
|
389
442
|
logger.info("Stopping services on demand...")
|
|
390
|
-
pause_all_services
|
|
443
|
+
await run_in_executor(pause_all_services)
|
|
391
444
|
logger.info("Stopping services on demand done.")
|
|
392
445
|
app._server.should_exit = True # pylint: disable=protected-access
|
|
393
446
|
await asyncio.sleep(0.3)
|
|
394
|
-
return {"stopped": True}
|
|
447
|
+
return JSONResponse(content={"stopped": True})
|
|
395
448
|
|
|
396
449
|
@app.get("/api")
|
|
397
450
|
@with_retries
|
|
@@ -777,6 +830,21 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
777
830
|
"""Get all services."""
|
|
778
831
|
return JSONResponse(content=operate.service_manager().json)
|
|
779
832
|
|
|
833
|
+
@app.get("/api/v2/services/validate")
|
|
834
|
+
@with_retries
|
|
835
|
+
async def _validate_services(request: Request) -> JSONResponse:
|
|
836
|
+
"""Validate all services."""
|
|
837
|
+
service_manager = operate.service_manager()
|
|
838
|
+
service_ids = service_manager.get_all_service_ids()
|
|
839
|
+
_services = [
|
|
840
|
+
service.service_config_id
|
|
841
|
+
for service in service_manager.get_all_services()[0]
|
|
842
|
+
]
|
|
843
|
+
|
|
844
|
+
return JSONResponse(
|
|
845
|
+
content={service_id: service_id in _services for service_id in service_ids}
|
|
846
|
+
)
|
|
847
|
+
|
|
780
848
|
@app.get("/api/v2/service/{service_config_id}")
|
|
781
849
|
@with_retries
|
|
782
850
|
async def _get_service(request: Request) -> JSONResponse:
|
|
@@ -954,38 +1022,40 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
954
1022
|
service = service_manager.load(service_config_id=service_config_id)
|
|
955
1023
|
|
|
956
1024
|
# terminate the service on chain
|
|
957
|
-
for chain in service.chain_configs:
|
|
1025
|
+
for chain, chain_config in service.chain_configs.items():
|
|
958
1026
|
service_manager.terminate_service_on_chain_from_safe(
|
|
959
1027
|
service_config_id=service_config_id,
|
|
960
1028
|
chain=chain,
|
|
961
1029
|
withdrawal_address=withdrawal_address,
|
|
962
1030
|
)
|
|
963
1031
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1032
|
+
# drain the master safe and master signer for the home chain
|
|
1033
|
+
chain = Chain(service.home_chain)
|
|
1034
|
+
master_wallet = service_manager.wallet_manager.load(
|
|
1035
|
+
ledger_type=chain.ledger_type
|
|
1036
|
+
)
|
|
969
1037
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1038
|
+
# drain the master safe
|
|
1039
|
+
logger.info(
|
|
1040
|
+
f"Draining the Master Safe {master_wallet.safes[chain]} on chain {chain.value} (withdrawal address {withdrawal_address})."
|
|
1041
|
+
)
|
|
1042
|
+
master_wallet.drain(
|
|
1043
|
+
withdrawal_address=withdrawal_address,
|
|
1044
|
+
chain=chain,
|
|
1045
|
+
from_safe=True,
|
|
1046
|
+
rpc=chain_config.ledger_config.rpc,
|
|
1047
|
+
)
|
|
979
1048
|
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1049
|
+
# drain the master signer
|
|
1050
|
+
logger.info(
|
|
1051
|
+
f"Draining the Master Signer {master_wallet.address} on chain {chain.value} (withdrawal address {withdrawal_address})."
|
|
1052
|
+
)
|
|
1053
|
+
master_wallet.drain(
|
|
1054
|
+
withdrawal_address=withdrawal_address,
|
|
1055
|
+
chain=chain,
|
|
1056
|
+
from_safe=False,
|
|
1057
|
+
rpc=chain_config.ledger_config.rpc,
|
|
1058
|
+
)
|
|
989
1059
|
except Exception as e: # pylint: disable=broad-except
|
|
990
1060
|
logger.error(f"Withdrawal failed: {e}\n{traceback.format_exc()}")
|
|
991
1061
|
return JSONResponse(
|
|
@@ -1136,6 +1206,16 @@ def _daemon(
|
|
|
1136
1206
|
}
|
|
1137
1207
|
)
|
|
1138
1208
|
|
|
1209
|
+
# try automatically shutdown previous instance
|
|
1210
|
+
if TRY_TO_SHUTDOWN_PREVIOUS_INSTANCE:
|
|
1211
|
+
url = f"http{'s' if ssl_keyfile and ssl_certfile else ''}://{host}:{port}/shutdown"
|
|
1212
|
+
logger.info(f"trying to stop previous instance with {url}")
|
|
1213
|
+
try:
|
|
1214
|
+
requests.get(url, timeout=3, verify=False) # nosec
|
|
1215
|
+
logger.info("previous instance stopped")
|
|
1216
|
+
except Exception: # pylint: disable=broad-except
|
|
1217
|
+
logger.exception("failed to stop previous instance. probably not running")
|
|
1218
|
+
|
|
1139
1219
|
server = Server(Config(**config_kwargs))
|
|
1140
1220
|
app._server = server # pylint: disable=protected-access
|
|
1141
1221
|
server.run()
|
operate/constants.py
CHANGED
|
@@ -48,3 +48,8 @@ MECH_ACTIVITY_CHECKER_JSON_URL = "https://raw.githubusercontent.com/valory-xyz/a
|
|
|
48
48
|
SERVICE_REGISTRY_TOKEN_UTILITY_JSON_URL = "https://raw.githubusercontent.com/valory-xyz/open-autonomy/refs/tags/v0.18.4/packages/valory/contracts/service_registry_token_utility/build/ServiceRegistryTokenUtility.json" # nosec
|
|
49
49
|
MECH_AGENT_FACTORY_JSON_URL = "https://raw.githubusercontent.com/valory-xyz/ai-registry-mech/main/abis/0.8.25/AgentFactory.json"
|
|
50
50
|
MECH_MARKETPLACE_JSON_URL = "https://raw.githubusercontent.com/valory-xyz/mech-quickstart/refs/heads/main/contracts/MechMarketplace.json"
|
|
51
|
+
NO_STAKING_PROGRAM_ID = "no_staking"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
DEPLOYMENT_START_TRIES_NUM = 3
|
|
55
|
+
IPFS_CHECK_URL = "https://gateway.autonolas.tech/ipfs/bafybeigcllaxn4ycjjvika3zd6eicksuriez2wtg67gx7pamhcazl3tv54/echo/README.md"
|
operate/keys.py
CHANGED
|
@@ -20,18 +20,18 @@
|
|
|
20
20
|
"""Keys manager."""
|
|
21
21
|
|
|
22
22
|
import json
|
|
23
|
-
import logging
|
|
24
23
|
import os
|
|
25
24
|
import shutil
|
|
26
|
-
import
|
|
25
|
+
import tempfile
|
|
27
26
|
from dataclasses import dataclass
|
|
28
27
|
from pathlib import Path
|
|
28
|
+
from typing import Any
|
|
29
29
|
|
|
30
|
-
from aea.helpers.logging import setup_logger
|
|
31
30
|
from aea_ledger_ethereum.ethereum import EthereumCrypto
|
|
32
31
|
|
|
33
32
|
from operate.operate_types import LedgerType
|
|
34
33
|
from operate.resource import LocalResource
|
|
34
|
+
from operate.utils import SingletonMeta
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
@dataclass
|
|
@@ -48,25 +48,21 @@ class Key(LocalResource):
|
|
|
48
48
|
return super().load(path) # type: ignore
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class KeysManager:
|
|
51
|
+
class KeysManager(metaclass=SingletonMeta):
|
|
55
52
|
"""Keys manager."""
|
|
56
53
|
|
|
57
|
-
def __init__(
|
|
58
|
-
self,
|
|
59
|
-
path: Path,
|
|
60
|
-
logger: t.Optional[logging.Logger] = None,
|
|
61
|
-
) -> None:
|
|
54
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
62
55
|
"""
|
|
63
56
|
Initialize keys manager
|
|
64
57
|
|
|
65
58
|
:param path: Path to keys storage.
|
|
66
59
|
:param logger: logging.Logger object.
|
|
67
60
|
"""
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
if "path" not in kwargs:
|
|
62
|
+
raise ValueError("Path must be provided for KeysManager")
|
|
63
|
+
|
|
64
|
+
self.path = kwargs["path"]
|
|
65
|
+
self.logger = kwargs["logger"]
|
|
70
66
|
|
|
71
67
|
def setup(self) -> None:
|
|
72
68
|
"""Setup service manager."""
|
|
@@ -83,6 +79,22 @@ class KeysManager:
|
|
|
83
79
|
)
|
|
84
80
|
)
|
|
85
81
|
|
|
82
|
+
def get_crypto_instance(self, address: str) -> EthereumCrypto:
|
|
83
|
+
"""Get EthereumCrypto instance for the given address."""
|
|
84
|
+
key: Key = Key.from_json( # type: ignore
|
|
85
|
+
obj=json.loads(
|
|
86
|
+
(self.path / address).read_text(
|
|
87
|
+
encoding="utf-8",
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt") as temp_file:
|
|
92
|
+
temp_file.write(key.private_key)
|
|
93
|
+
temp_file.flush()
|
|
94
|
+
crypto = EthereumCrypto(private_key_path=temp_file.name)
|
|
95
|
+
|
|
96
|
+
return crypto
|
|
97
|
+
|
|
86
98
|
def create(self) -> str:
|
|
87
99
|
"""Creates new key."""
|
|
88
100
|
crypto = EthereumCrypto()
|
operate/ledger/profiles.py
CHANGED
|
@@ -21,12 +21,10 @@
|
|
|
21
21
|
|
|
22
22
|
import typing as t
|
|
23
23
|
|
|
24
|
-
from operate.constants import ZERO_ADDRESS
|
|
24
|
+
from operate.constants import NO_STAKING_PROGRAM_ID, ZERO_ADDRESS
|
|
25
25
|
from operate.operate_types import Chain, ContractAddresses
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
NO_STAKING_PROGRAM_ID = "no_staking"
|
|
29
|
-
|
|
30
28
|
CONTRACTS: t.Dict[Chain, ContractAddresses] = {
|
|
31
29
|
Chain.GNOSIS: ContractAddresses(
|
|
32
30
|
{
|