Skip to content

Commit 545f4a8

Browse files
1yamAndres D. Molinsnesitor
authored
Feature: aleph settings services (#248)
* Problem: Ledger wallet users cannot use Aleph to send transactions. Solution: Implement Ledger use on SDK to allow using them. * Fix: Solved linting and types issues for code quality. * Feature: aleph settings services * Feature: use settings aggregates instead of hardcoded crn version * Fix: we should give crn_version instead of fetching it here * fix: linting issue * Fix: crn_version should be optional and given * Apply suggestion from @nesitor Co-authored-by: nesitor <amolinsdiaz@yahoo.es> * Fix: use settings.ALEPH_AGGREGATE_ADDRESS instead of hardcoded address for pricing and settings * fix: linting * fix: missing typing for ALEPH_AGGREGATE_ADDRESS in settings --------- Co-authored-by: Andres D. Molins <nesitor@gmail.com> Co-authored-by: nesitor <amolinsdiaz@yahoo.es>
1 parent b4c1f90 commit 545f4a8

File tree

6 files changed

+249
-11
lines changed

6 files changed

+249
-11
lines changed

src/aleph/sdk/client/http.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from aleph.sdk.client.services.port_forwarder import PortForwarder
4040
from aleph.sdk.client.services.pricing import Pricing
4141
from aleph.sdk.client.services.scheduler import Scheduler
42+
from aleph.sdk.client.services.settings import Settings as NetworkSettingsService
4243
from aleph.sdk.client.services.voucher import Vouchers
4344

4445
from ..conf import settings
@@ -146,7 +147,7 @@ async def __aenter__(self):
146147
self.instance = Instance(self)
147148
self.pricing = Pricing(self)
148149
self.voucher = Vouchers(self)
149-
150+
self.network_settings = NetworkSettingsService(self)
150151
return self
151152

152153
async def __aexit__(self, exc_type, exc_val, exc_tb):

src/aleph/sdk/client/services/crn.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,31 +97,27 @@ def find_gpu_on_network(self):
9797

9898
def filter_crn(
9999
self,
100-
latest_crn_version: bool = False,
100+
crn_version: Optional[str] = None,
101101
ipv6: bool = False,
102102
stream_address: bool = False,
103103
confidential: bool = False,
104104
gpu: bool = False,
105105
) -> list[CRN]:
106106
"""Filter compute resource node list, unfiltered by default.
107107
Args:
108-
latest_crn_version (bool): Filter by latest crn version.
108+
crn_version (str): Filter by specific crn version.
109109
ipv6 (bool): Filter invalid IPv6 configuration.
110110
stream_address (bool): Filter invalid payment receiver address.
111111
confidential (bool): Filter by confidential computing support.
112112
gpu (bool): Filter by GPU support.
113113
Returns:
114114
list[CRN]: List of compute resource nodes. (if no filter applied, return all)
115115
"""
116-
# current_crn_version = await fetch_latest_crn_version()
117-
# Relax current filter to allow use aleph-vm versions since 1.5.1.
118-
# TODO: Allow to specify that option on settings aggregate on maybe on GitHub
119-
current_crn_version = "1.5.1"
120116

121117
filtered_crn: list[CRN] = []
122118
for crn_ in self.crns:
123119
# Check crn version
124-
if latest_crn_version and (crn_.version or "0.0.0") < current_crn_version:
120+
if crn_version and (crn_.version or "0.0.0") < crn_version:
125121
continue
126122

127123
# Filter with ipv6 check

src/aleph/sdk/client/services/pricing.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import TYPE_CHECKING, Dict, List, Optional, Union
55

66
from aleph.sdk.client.services.base import BaseService
7+
from aleph.sdk.conf import settings
78

89
if TYPE_CHECKING:
910
pass
@@ -205,9 +206,7 @@ def __init__(self, client):
205206
async def get_pricing_aggregate(
206207
self,
207208
) -> PricingModel:
208-
result = await self.get_config(
209-
address="0xFba561a84A537fCaa567bb7A2257e7142701ae2A"
210-
)
209+
result = await self.get_config(address=settings.ALEPH_AGGREGATE_ADDRESS)
211210
return result.data[0]
212211

213212
async def get_pricing_for_services(
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from typing import List
2+
3+
from pydantic import BaseModel
4+
5+
from aleph.sdk.conf import settings
6+
7+
from .base import BaseService
8+
9+
10+
class NetworkAvailableGpu(BaseModel):
11+
name: str
12+
model: str
13+
vendor: str
14+
device_id: str
15+
16+
17+
class NetworkSettingsModel(BaseModel):
18+
compatible_gpus: List[NetworkAvailableGpu]
19+
last_crn_version: str
20+
community_wallet_address: str
21+
community_wallet_timestamp: int
22+
23+
24+
class Settings(BaseService[NetworkSettingsModel]):
25+
"""
26+
This Service handle logic around Pricing
27+
"""
28+
29+
aggregate_key = "settings"
30+
model_cls = NetworkSettingsModel
31+
32+
def __init__(self, client):
33+
super().__init__(client=client)
34+
35+
# Config from aggregate
36+
async def get_settings_aggregate(
37+
self,
38+
) -> NetworkSettingsModel:
39+
result = await self.get_config(address=settings.ALEPH_AGGREGATE_ADDRESS)
40+
return result.data[0]

src/aleph/sdk/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ class Settings(BaseSettings):
9999
VOUCHER_SOL_REGISTRY: str = "https://api.claim.twentysix.cloud/v1/registry/sol"
100100
VOUCHER_ORIGIN_ADDRESS: str = "0xB34f25f2c935bCA437C061547eA12851d719dEFb"
101101

102+
ALEPH_AGGREGATE_ADDRESS: str = "0xFba561a84A537fCaa567bb7A2257e7142701ae2A"
103+
102104
# Web3Provider settings
103105
TOKEN_DECIMALS: ClassVar[int] = 18
104106
TX_TIMEOUT: ClassVar[int] = 60 * 3
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
from unittest.mock import AsyncMock, MagicMock
2+
3+
import pytest
4+
5+
from aleph.sdk import AlephHttpClient
6+
from aleph.sdk.client.services.settings import NetworkSettingsModel, Settings
7+
8+
9+
@pytest.fixture
10+
def mock_settings_aggregate_response():
11+
return {
12+
"compatible_gpus": [
13+
{
14+
"name": "AD102GL [L40S]",
15+
"model": "L40S",
16+
"vendor": "NVIDIA",
17+
"device_id": "10de:26b9",
18+
},
19+
{
20+
"name": "GB202 [GeForce RTX 5090]",
21+
"model": "RTX 5090",
22+
"vendor": "NVIDIA",
23+
"device_id": "10de:2685",
24+
},
25+
{
26+
"name": "GB202 [GeForce RTX 5090 D]",
27+
"model": "RTX 5090",
28+
"vendor": "NVIDIA",
29+
"device_id": "10de:2687",
30+
},
31+
{
32+
"name": "AD102 [GeForce RTX 4090]",
33+
"model": "RTX 4090",
34+
"vendor": "NVIDIA",
35+
"device_id": "10de:2684",
36+
},
37+
{
38+
"name": "AD102 [GeForce RTX 4090 D]",
39+
"model": "RTX 4090",
40+
"vendor": "NVIDIA",
41+
"device_id": "10de:2685",
42+
},
43+
{
44+
"name": "GA102 [GeForce RTX 3090]",
45+
"model": "RTX 3090",
46+
"vendor": "NVIDIA",
47+
"device_id": "10de:2204",
48+
},
49+
{
50+
"name": "GA102 [GeForce RTX 3090 Ti]",
51+
"model": "RTX 3090",
52+
"vendor": "NVIDIA",
53+
"device_id": "10de:2203",
54+
},
55+
{
56+
"name": "AD104GL [RTX 4000 SFF Ada Generation]",
57+
"model": "RTX 4000 ADA",
58+
"vendor": "NVIDIA",
59+
"device_id": "10de:27b0",
60+
},
61+
{
62+
"name": "AD104GL [RTX 4000 Ada Generation]",
63+
"model": "RTX 4000 ADA",
64+
"vendor": "NVIDIA",
65+
"device_id": "10de:27b2",
66+
},
67+
{
68+
"name": "GA102GL [RTX A5000]",
69+
"model": "RTX A5000",
70+
"vendor": "NVIDIA",
71+
"device_id": "10de:2231",
72+
},
73+
{
74+
"name": "GA102GL [RTX A6000]",
75+
"model": "RTX A6000",
76+
"vendor": "NVIDIA",
77+
"device_id": "10de:2230",
78+
},
79+
{
80+
"name": "GH100 [H100]",
81+
"model": "H100",
82+
"vendor": "NVIDIA",
83+
"device_id": "10de:2336",
84+
},
85+
{
86+
"name": "GH100 [H100 NVSwitch]",
87+
"model": "H100",
88+
"vendor": "NVIDIA",
89+
"device_id": "10de:22a3",
90+
},
91+
{
92+
"name": "GH100 [H100 CNX]",
93+
"model": "H100",
94+
"vendor": "NVIDIA",
95+
"device_id": "10de:2313",
96+
},
97+
{
98+
"name": "GH100 [H100 SXM5 80GB]",
99+
"model": "H100",
100+
"vendor": "NVIDIA",
101+
"device_id": "10de:2330",
102+
},
103+
{
104+
"name": "GH100 [H100 PCIe]",
105+
"model": "H100",
106+
"vendor": "NVIDIA",
107+
"device_id": "10de:2331",
108+
},
109+
{
110+
"name": "GA100",
111+
"model": "A100",
112+
"vendor": "NVIDIA",
113+
"device_id": "10de:2080",
114+
},
115+
{
116+
"name": "GA100",
117+
"model": "A100",
118+
"vendor": "NVIDIA",
119+
"device_id": "10de:2081",
120+
},
121+
{
122+
"name": "GA100 [A100 SXM4 80GB]",
123+
"model": "A100",
124+
"vendor": "NVIDIA",
125+
"device_id": "10de:20b2",
126+
},
127+
{
128+
"name": "GA100 [A100 PCIe 80GB]",
129+
"model": "A100",
130+
"vendor": "NVIDIA",
131+
"device_id": "10de:20b5",
132+
},
133+
{
134+
"name": "GA100 [A100X]",
135+
"model": "A100",
136+
"vendor": "NVIDIA",
137+
"device_id": "10de:20b8",
138+
},
139+
{
140+
"name": "GH100 [H200 SXM 141GB]",
141+
"model": "H200",
142+
"vendor": "NVIDIA",
143+
"device_id": "10de:2335",
144+
},
145+
{
146+
"name": "GH100 [H200 NVL]",
147+
"model": "H200",
148+
"vendor": "NVIDIA",
149+
"device_id": "10de:233b",
150+
},
151+
{
152+
"name": "AD102GL [RTX 6000 ADA]",
153+
"model": "RTX 6000 ADA",
154+
"vendor": "NVIDIA",
155+
"device_id": "10de:26b1",
156+
},
157+
],
158+
"last_crn_version": "1.7.2",
159+
"community_wallet_address": "0x5aBd3258C5492fD378EBC2e0017416E199e5Da56",
160+
"community_wallet_timestamp": 1739996239,
161+
}
162+
163+
164+
@pytest.mark.asyncio
165+
async def test_get_settings_aggregate(
166+
make_mock_aiohttp_session, mock_settings_aggregate_response
167+
):
168+
client = AlephHttpClient(api_server="http://localhost")
169+
170+
# Properly mock the fetch_aggregate method using monkeypatch
171+
client._http_session = MagicMock()
172+
monkeypatch = AsyncMock(return_value=mock_settings_aggregate_response)
173+
setattr(client, "fetch_aggregate", monkeypatch)
174+
175+
settings_service = Settings(client)
176+
result = await settings_service.get_settings_aggregate()
177+
178+
assert isinstance(result, NetworkSettingsModel)
179+
assert len(result.compatible_gpus) == 24 # We have 24 GPUs in the mock data
180+
181+
rtx4000_gpu = next(
182+
gpu for gpu in result.compatible_gpus if gpu.device_id == "10de:27b0"
183+
)
184+
assert rtx4000_gpu.name == "AD104GL [RTX 4000 SFF Ada Generation]"
185+
assert rtx4000_gpu.model == "RTX 4000 ADA"
186+
assert rtx4000_gpu.vendor == "NVIDIA"
187+
188+
assert result.last_crn_version == "1.7.2"
189+
assert (
190+
result.community_wallet_address == "0x5aBd3258C5492fD378EBC2e0017416E199e5Da56"
191+
)
192+
assert result.community_wallet_timestamp == 1739996239
193+
194+
# Verify that fetch_aggregate was called with the correct parameters
195+
assert monkeypatch.call_count == 1
196+
assert (
197+
monkeypatch.call_args.kwargs["address"]
198+
== "0xFba561a84A537fCaa567bb7A2257e7142701ae2A"
199+
)
200+
assert monkeypatch.call_args.kwargs["key"] == "settings"

0 commit comments

Comments
 (0)