golem-vm-provider 0.1.53__tar.gz → 0.1.55__tar.gz
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.
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/PKG-INFO +66 -29
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/README.md +65 -28
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/config.py +111 -14
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/golem_base_advertiser.py +1 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/main.py +3 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/payments/monitor.py +27 -7
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/security/l2_faucet.py +4 -1
- golem_vm_provider-0.1.55/provider/service.py +148 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/pyproject.toml +1 -1
- golem_vm_provider-0.1.53/provider/service.py +0 -86
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/__init__.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/api/__init__.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/api/models.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/api/routes.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/container.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/data/deployments/l2.json +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/__init__.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/advertiser.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/golem_base_utils.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/multi_advertiser.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/resource_monitor.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/resource_tracker.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/service.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/network/port_verifier.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/payments/blockchain_service.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/payments/stream_map.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/security/ethereum.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/security/faucet.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/utils/__init__.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/utils/ascii_art.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/utils/logging.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/utils/port_display.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/utils/pricing.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/utils/retry.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/utils/setup.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/vm/__init__.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/vm/cloud_init.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/vm/models.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/vm/multipass.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/vm/multipass_adapter.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/vm/name_mapper.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/vm/port_manager.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/vm/provider.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/vm/proxy_manager.py +0 -0
- {golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/vm/service.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: golem-vm-provider
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.55
|
4
4
|
Summary: VM on Golem Provider Node - Run your own provider node to offer VMs on the Golem Network
|
5
5
|
Keywords: golem,vm,provider,cloud,decentralized
|
6
6
|
Author: Phillip Jensen
|
@@ -45,7 +45,35 @@ Description-Content-Type: text/markdown
|
|
45
45
|
|
46
46
|
# VM on Golem Provider Node
|
47
47
|
|
48
|
-
|
48
|
+
Earn by renting out your machine’s compute — like Airbnb for servers. The Provider service runs VMs for requestors, verifies payments via streaming, and lets you withdraw earnings.
|
49
|
+
|
50
|
+
## Quick Start (Host and Earn)
|
51
|
+
|
52
|
+
1) Install (Python 3.11+ recommended):
|
53
|
+
|
54
|
+
```bash
|
55
|
+
pip install golem-vm-provider
|
56
|
+
```
|
57
|
+
|
58
|
+
2) Start the provider (testnet by default is fine):
|
59
|
+
|
60
|
+
```bash
|
61
|
+
golem-provider start --network testnet
|
62
|
+
```
|
63
|
+
|
64
|
+
3) Set pricing in USD (GLM rates auto‑compute):
|
65
|
+
|
66
|
+
```bash
|
67
|
+
golem-provider pricing set --usd-per-core 12 --usd-per-mem 4 --usd-per-disk 0.1
|
68
|
+
```
|
69
|
+
|
70
|
+
4) On testnets, optionally fund gas for withdrawals:
|
71
|
+
|
72
|
+
```bash
|
73
|
+
golem-provider wallet faucet-l2
|
74
|
+
```
|
75
|
+
|
76
|
+
You are now discoverable to requestors and will earn as your VMs run.
|
49
77
|
|
50
78
|
## System Architecture
|
51
79
|
|
@@ -178,26 +206,26 @@ sequenceDiagram
|
|
178
206
|
- Clean connection handling
|
179
207
|
- Automatic proxy cleanup
|
180
208
|
|
181
|
-
## Installation
|
209
|
+
## Installation (from source / development)
|
182
210
|
|
183
211
|
1. Prerequisites:
|
212
|
+
- Python 3.11+
|
213
|
+
- Multipass
|
214
|
+
- Poetry (for development)
|
184
215
|
|
185
|
-
|
186
|
-
- Multipass
|
187
|
-
- Poetry
|
216
|
+
2. Install from source:
|
188
217
|
|
189
|
-
|
218
|
+
```bash
|
219
|
+
cd provider-server
|
220
|
+
poetry install
|
221
|
+
```
|
190
222
|
|
191
|
-
|
192
|
-
cd provider-server
|
193
|
-
poetry install
|
194
|
-
```
|
223
|
+
3. Local environment (optional):
|
195
224
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
```
|
225
|
+
```bash
|
226
|
+
cp .env.example .env
|
227
|
+
# Edit .env to tweak defaults if needed
|
228
|
+
```
|
201
229
|
|
202
230
|
## Configuration
|
203
231
|
|
@@ -227,9 +255,9 @@ GOLEM_PROVIDER_PORT_RANGE_START={start_port} # Default: 50800
|
|
227
255
|
GOLEM_PROVIDER_PORT_RANGE_END={end_port} # Default: 50900
|
228
256
|
GOLEM_PROVIDER_PUBLIC_IP="auto"
|
229
257
|
|
230
|
-
#
|
231
|
-
GOLEM_PROVIDER_DISCOVERY_URL="http://discovery.golem.network:9001"
|
232
|
-
GOLEM_PROVIDER_ADVERTISEMENT_INTERVAL=240
|
258
|
+
# Legacy discovery (optional; not required in normal operation)
|
259
|
+
# GOLEM_PROVIDER_DISCOVERY_URL="http://discovery.golem.network:9001"
|
260
|
+
# GOLEM_PROVIDER_ADVERTISEMENT_INTERVAL=240
|
233
261
|
|
234
262
|
# Network Selection
|
235
263
|
# Adds an annotation to on-chain advertisements and can be used by requestors to filter
|
@@ -266,7 +294,7 @@ When enabled, the provider verifies each VM creation request’s `stream_id` and
|
|
266
294
|
- deposit is zero, stream not started, or stream halted
|
267
295
|
- (Optional) remaining runway < `STREAM_MIN_REMAINING_SECONDS`
|
268
296
|
|
269
|
-
## API Reference
|
297
|
+
## API Reference (for integrators)
|
270
298
|
|
271
299
|
### Create VM
|
272
300
|
|
@@ -372,11 +400,11 @@ Notes:
|
|
372
400
|
### Starting the Provider
|
373
401
|
|
374
402
|
```bash
|
375
|
-
#
|
376
|
-
|
403
|
+
# Production mode
|
404
|
+
golem-provider start
|
377
405
|
|
378
|
-
#
|
379
|
-
GOLEM_PROVIDER_ENVIRONMENT=development
|
406
|
+
# Development mode with extra logs and reload
|
407
|
+
GOLEM_PROVIDER_ENVIRONMENT=development golem-provider start --network testnet
|
380
408
|
```
|
381
409
|
|
382
410
|
### Mode vs. Network
|
@@ -390,6 +418,9 @@ GOLEM_PROVIDER_ENVIRONMENT=development poetry run golem-provider start --network
|
|
390
418
|
- Pair with appropriate RPC envs (`GOLEM_PROVIDER_GOLEM_BASE_RPC_URL`, `GOLEM_PROVIDER_GOLEM_BASE_WS_URL`).
|
391
419
|
- Does not change dev ergonomics (logging, reload, or port verification behavior).
|
392
420
|
|
421
|
+
- Payments Network (`GOLEM_PROVIDER_PAYMENTS_NETWORK`)
|
422
|
+
- Selects the payments chain profile (e.g., `l2.holesky`, `mainnet`). Determines default payments RPC, faucet enablement, and symbols.
|
423
|
+
|
393
424
|
Common setups:
|
394
425
|
- Local dev on testnet: `GOLEM_PROVIDER_ENVIRONMENT=development` plus `--network testnet`.
|
395
426
|
- Staging on testnet: keep `ENVIRONMENT=production`, set `--network testnet` and testnet RPCs.
|
@@ -406,17 +437,20 @@ The provider will:
|
|
406
437
|
4. Begin resource advertisement
|
407
438
|
5. Listen for VM requests
|
408
439
|
|
440
|
+
Notes:
|
441
|
+
- Advertisements include both `golem_network` (testnet/mainnet) and `golem_payments_network` (e.g., `l2.holesky`). Requestors default to matching both; they can list all payments networks with a CLI flag.
|
442
|
+
|
409
443
|
### Faucet
|
410
444
|
|
411
445
|
- L3 (Golem Base adverts): provider auto-requests funds on startup from `FAUCET_URL` (defaults to EthWarsaw Holesky) protected by CAPTCHA at `CAPTCHA_URL/05381a2cef5e`.
|
412
|
-
- L2 (payments): Use the CLI to request native ETH:
|
446
|
+
- L2 (payments): Use the CLI to request native ETH (enabled only on testnet profiles):
|
413
447
|
|
414
448
|
```bash
|
415
|
-
|
449
|
+
golem-provider wallet faucet-l2
|
416
450
|
```
|
417
451
|
|
418
452
|
Defaults:
|
419
|
-
-
|
453
|
+
- Faucet URL and enablement come from the active payments profile. On `mainnet` (or other profiles without faucet) the command is disabled.
|
420
454
|
- CAPTCHA: `https://cap.gobas.me/05381a2cef5e`
|
421
455
|
- Override with env: `GOLEM_PROVIDER_L2_FAUCET_URL`, `GOLEM_PROVIDER_L2_CAPTCHA_URL`, `GOLEM_PROVIDER_L2_CAPTCHA_API_KEY`.
|
422
456
|
|
@@ -460,10 +494,10 @@ Configure monitor and withdraw via CLI:
|
|
460
494
|
|
461
495
|
```bash
|
462
496
|
# Set monitor to require 1h remaining, check every 30s
|
463
|
-
|
497
|
+
golem-provider config monitor --enable true --interval 30 --min-remaining 3600
|
464
498
|
|
465
499
|
# Enable auto-withdraw every 15 minutes when >= 1e15 wei
|
466
|
-
|
500
|
+
golem-provider config withdraw --enable true --interval 900 --min-wei 1000000000000000
|
467
501
|
```
|
468
502
|
|
469
503
|
### Resource Advertisement Flow
|
@@ -476,6 +510,7 @@ sequenceDiagram
|
|
476
510
|
participant DS as Discovery Service
|
477
511
|
|
478
512
|
P->>RT: Initialize
|
513
|
+
P->>RT: Sync with existing VMs
|
479
514
|
RT->>AD: Register Callback
|
480
515
|
loop Every 4 minutes
|
481
516
|
AD->>RT: Get Resources
|
@@ -485,6 +520,8 @@ sequenceDiagram
|
|
485
520
|
end
|
486
521
|
```
|
487
522
|
|
523
|
+
On startup, the provider syncs the resource tracker with all VMs currently running on the host (via Multipass). This ensures advertisements reflect already-allocated CPU, RAM, and storage after restarts, preventing false “outdated advertisement” updates when existing VMs are consuming resources. The sync is based on actual VMs present, independent of any still-open payment streams.
|
524
|
+
|
488
525
|
### Monitoring
|
489
526
|
|
490
527
|
The provider includes comprehensive logging:
|
@@ -1,6 +1,34 @@
|
|
1
1
|
# VM on Golem Provider Node
|
2
2
|
|
3
|
-
|
3
|
+
Earn by renting out your machine’s compute — like Airbnb for servers. The Provider service runs VMs for requestors, verifies payments via streaming, and lets you withdraw earnings.
|
4
|
+
|
5
|
+
## Quick Start (Host and Earn)
|
6
|
+
|
7
|
+
1) Install (Python 3.11+ recommended):
|
8
|
+
|
9
|
+
```bash
|
10
|
+
pip install golem-vm-provider
|
11
|
+
```
|
12
|
+
|
13
|
+
2) Start the provider (testnet by default is fine):
|
14
|
+
|
15
|
+
```bash
|
16
|
+
golem-provider start --network testnet
|
17
|
+
```
|
18
|
+
|
19
|
+
3) Set pricing in USD (GLM rates auto‑compute):
|
20
|
+
|
21
|
+
```bash
|
22
|
+
golem-provider pricing set --usd-per-core 12 --usd-per-mem 4 --usd-per-disk 0.1
|
23
|
+
```
|
24
|
+
|
25
|
+
4) On testnets, optionally fund gas for withdrawals:
|
26
|
+
|
27
|
+
```bash
|
28
|
+
golem-provider wallet faucet-l2
|
29
|
+
```
|
30
|
+
|
31
|
+
You are now discoverable to requestors and will earn as your VMs run.
|
4
32
|
|
5
33
|
## System Architecture
|
6
34
|
|
@@ -133,26 +161,26 @@ sequenceDiagram
|
|
133
161
|
- Clean connection handling
|
134
162
|
- Automatic proxy cleanup
|
135
163
|
|
136
|
-
## Installation
|
164
|
+
## Installation (from source / development)
|
137
165
|
|
138
166
|
1. Prerequisites:
|
167
|
+
- Python 3.11+
|
168
|
+
- Multipass
|
169
|
+
- Poetry (for development)
|
139
170
|
|
140
|
-
|
141
|
-
- Multipass
|
142
|
-
- Poetry
|
171
|
+
2. Install from source:
|
143
172
|
|
144
|
-
|
173
|
+
```bash
|
174
|
+
cd provider-server
|
175
|
+
poetry install
|
176
|
+
```
|
145
177
|
|
146
|
-
|
147
|
-
cd provider-server
|
148
|
-
poetry install
|
149
|
-
```
|
178
|
+
3. Local environment (optional):
|
150
179
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
```
|
180
|
+
```bash
|
181
|
+
cp .env.example .env
|
182
|
+
# Edit .env to tweak defaults if needed
|
183
|
+
```
|
156
184
|
|
157
185
|
## Configuration
|
158
186
|
|
@@ -182,9 +210,9 @@ GOLEM_PROVIDER_PORT_RANGE_START={start_port} # Default: 50800
|
|
182
210
|
GOLEM_PROVIDER_PORT_RANGE_END={end_port} # Default: 50900
|
183
211
|
GOLEM_PROVIDER_PUBLIC_IP="auto"
|
184
212
|
|
185
|
-
#
|
186
|
-
GOLEM_PROVIDER_DISCOVERY_URL="http://discovery.golem.network:9001"
|
187
|
-
GOLEM_PROVIDER_ADVERTISEMENT_INTERVAL=240
|
213
|
+
# Legacy discovery (optional; not required in normal operation)
|
214
|
+
# GOLEM_PROVIDER_DISCOVERY_URL="http://discovery.golem.network:9001"
|
215
|
+
# GOLEM_PROVIDER_ADVERTISEMENT_INTERVAL=240
|
188
216
|
|
189
217
|
# Network Selection
|
190
218
|
# Adds an annotation to on-chain advertisements and can be used by requestors to filter
|
@@ -221,7 +249,7 @@ When enabled, the provider verifies each VM creation request’s `stream_id` and
|
|
221
249
|
- deposit is zero, stream not started, or stream halted
|
222
250
|
- (Optional) remaining runway < `STREAM_MIN_REMAINING_SECONDS`
|
223
251
|
|
224
|
-
## API Reference
|
252
|
+
## API Reference (for integrators)
|
225
253
|
|
226
254
|
### Create VM
|
227
255
|
|
@@ -327,11 +355,11 @@ Notes:
|
|
327
355
|
### Starting the Provider
|
328
356
|
|
329
357
|
```bash
|
330
|
-
#
|
331
|
-
|
358
|
+
# Production mode
|
359
|
+
golem-provider start
|
332
360
|
|
333
|
-
#
|
334
|
-
GOLEM_PROVIDER_ENVIRONMENT=development
|
361
|
+
# Development mode with extra logs and reload
|
362
|
+
GOLEM_PROVIDER_ENVIRONMENT=development golem-provider start --network testnet
|
335
363
|
```
|
336
364
|
|
337
365
|
### Mode vs. Network
|
@@ -345,6 +373,9 @@ GOLEM_PROVIDER_ENVIRONMENT=development poetry run golem-provider start --network
|
|
345
373
|
- Pair with appropriate RPC envs (`GOLEM_PROVIDER_GOLEM_BASE_RPC_URL`, `GOLEM_PROVIDER_GOLEM_BASE_WS_URL`).
|
346
374
|
- Does not change dev ergonomics (logging, reload, or port verification behavior).
|
347
375
|
|
376
|
+
- Payments Network (`GOLEM_PROVIDER_PAYMENTS_NETWORK`)
|
377
|
+
- Selects the payments chain profile (e.g., `l2.holesky`, `mainnet`). Determines default payments RPC, faucet enablement, and symbols.
|
378
|
+
|
348
379
|
Common setups:
|
349
380
|
- Local dev on testnet: `GOLEM_PROVIDER_ENVIRONMENT=development` plus `--network testnet`.
|
350
381
|
- Staging on testnet: keep `ENVIRONMENT=production`, set `--network testnet` and testnet RPCs.
|
@@ -361,17 +392,20 @@ The provider will:
|
|
361
392
|
4. Begin resource advertisement
|
362
393
|
5. Listen for VM requests
|
363
394
|
|
395
|
+
Notes:
|
396
|
+
- Advertisements include both `golem_network` (testnet/mainnet) and `golem_payments_network` (e.g., `l2.holesky`). Requestors default to matching both; they can list all payments networks with a CLI flag.
|
397
|
+
|
364
398
|
### Faucet
|
365
399
|
|
366
400
|
- L3 (Golem Base adverts): provider auto-requests funds on startup from `FAUCET_URL` (defaults to EthWarsaw Holesky) protected by CAPTCHA at `CAPTCHA_URL/05381a2cef5e`.
|
367
|
-
- L2 (payments): Use the CLI to request native ETH:
|
401
|
+
- L2 (payments): Use the CLI to request native ETH (enabled only on testnet profiles):
|
368
402
|
|
369
403
|
```bash
|
370
|
-
|
404
|
+
golem-provider wallet faucet-l2
|
371
405
|
```
|
372
406
|
|
373
407
|
Defaults:
|
374
|
-
-
|
408
|
+
- Faucet URL and enablement come from the active payments profile. On `mainnet` (or other profiles without faucet) the command is disabled.
|
375
409
|
- CAPTCHA: `https://cap.gobas.me/05381a2cef5e`
|
376
410
|
- Override with env: `GOLEM_PROVIDER_L2_FAUCET_URL`, `GOLEM_PROVIDER_L2_CAPTCHA_URL`, `GOLEM_PROVIDER_L2_CAPTCHA_API_KEY`.
|
377
411
|
|
@@ -415,10 +449,10 @@ Configure monitor and withdraw via CLI:
|
|
415
449
|
|
416
450
|
```bash
|
417
451
|
# Set monitor to require 1h remaining, check every 30s
|
418
|
-
|
452
|
+
golem-provider config monitor --enable true --interval 30 --min-remaining 3600
|
419
453
|
|
420
454
|
# Enable auto-withdraw every 15 minutes when >= 1e15 wei
|
421
|
-
|
455
|
+
golem-provider config withdraw --enable true --interval 900 --min-wei 1000000000000000
|
422
456
|
```
|
423
457
|
|
424
458
|
### Resource Advertisement Flow
|
@@ -431,6 +465,7 @@ sequenceDiagram
|
|
431
465
|
participant DS as Discovery Service
|
432
466
|
|
433
467
|
P->>RT: Initialize
|
468
|
+
P->>RT: Sync with existing VMs
|
434
469
|
RT->>AD: Register Callback
|
435
470
|
loop Every 4 minutes
|
436
471
|
AD->>RT: Get Resources
|
@@ -440,6 +475,8 @@ sequenceDiagram
|
|
440
475
|
end
|
441
476
|
```
|
442
477
|
|
478
|
+
On startup, the provider syncs the resource tracker with all VMs currently running on the host (via Multipass). This ensures advertisements reflect already-allocated CPU, RAM, and storage after restarts, preventing false “outdated advertisement” updates when existing VMs are consuming resources. The sync is based on actual VMs present, independent of any still-open payment streams.
|
479
|
+
|
443
480
|
### Monitoring
|
444
481
|
|
445
482
|
The provider includes comprehensive logging:
|
@@ -57,6 +57,17 @@ class Settings(BaseSettings):
|
|
57
57
|
# Logical network selector for annotation and client defaults
|
58
58
|
NETWORK: str = "mainnet" # one of: "testnet", "mainnet"
|
59
59
|
|
60
|
+
# Payments chain selection (modular network profiles). Keep default on l2.holesky
|
61
|
+
PAYMENTS_NETWORK: str = Field(
|
62
|
+
default="l2.holesky",
|
63
|
+
description="Payments network profile (e.g., 'l2.holesky', 'kaolin.holesky', 'mainnet')"
|
64
|
+
)
|
65
|
+
|
66
|
+
@field_validator("PAYMENTS_NETWORK", mode='before')
|
67
|
+
@classmethod
|
68
|
+
def prefer_payments_network_env(cls, v: str) -> str:
|
69
|
+
return os.environ.get("GOLEM_PROVIDER_PAYMENTS_NETWORK", v)
|
70
|
+
|
60
71
|
@property
|
61
72
|
def DEV_MODE(self) -> bool:
|
62
73
|
return self.ENVIRONMENT == "development"
|
@@ -138,8 +149,8 @@ class Settings(BaseSettings):
|
|
138
149
|
|
139
150
|
# Polygon / Payments
|
140
151
|
POLYGON_RPC_URL: str = Field(
|
141
|
-
default="
|
142
|
-
description="EVM RPC URL for streaming payments
|
152
|
+
default="",
|
153
|
+
description="EVM RPC URL for streaming payments; defaults from PAYMENTS_NETWORK profile"
|
143
154
|
)
|
144
155
|
STREAM_PAYMENT_ADDRESS: str = Field(
|
145
156
|
default="",
|
@@ -181,8 +192,8 @@ class Settings(BaseSettings):
|
|
181
192
|
|
182
193
|
# L2 payments faucet (native ETH)
|
183
194
|
L2_FAUCET_URL: str = Field(
|
184
|
-
default="
|
185
|
-
description="
|
195
|
+
default="",
|
196
|
+
description="Faucet base URL (no trailing /api). Only used on testnets; defaults from PAYMENTS_NETWORK profile"
|
186
197
|
)
|
187
198
|
L2_CAPTCHA_URL: str = Field(
|
188
199
|
default="https://cap.gobas.me",
|
@@ -193,17 +204,42 @@ class Settings(BaseSettings):
|
|
193
204
|
description="CAPTCHA API key path segment"
|
194
205
|
)
|
195
206
|
|
207
|
+
@field_validator("L2_CAPTCHA_URL", mode='before')
|
208
|
+
@classmethod
|
209
|
+
def prefer_l2_captcha_url(cls, v: str) -> str:
|
210
|
+
return os.environ.get("GOLEM_PROVIDER_L2_CAPTCHA_URL", v)
|
211
|
+
|
212
|
+
@field_validator("L2_CAPTCHA_API_KEY", mode='before')
|
213
|
+
@classmethod
|
214
|
+
def prefer_l2_captcha_key(cls, v: str) -> str:
|
215
|
+
return os.environ.get("GOLEM_PROVIDER_L2_CAPTCHA_API_KEY", v)
|
216
|
+
|
196
217
|
@field_validator("POLYGON_RPC_URL", mode='before')
|
197
218
|
@classmethod
|
198
|
-
def prefer_custom_env(cls, v: str) -> str:
|
219
|
+
def prefer_custom_env(cls, v: str, values: dict) -> str:
|
199
220
|
# Accept alternative aliases for payments RPC
|
200
221
|
for key in ("GOLEM_PROVIDER_L2_RPC_URL", "GOLEM_PROVIDER_KAOLIN_RPC_URL"):
|
201
222
|
if os.environ.get(key):
|
202
223
|
return os.environ[key]
|
203
|
-
|
224
|
+
if v:
|
225
|
+
return v
|
226
|
+
# Default from profile
|
227
|
+
pn = values.data.get("PAYMENTS_NETWORK") or "l2.holesky"
|
228
|
+
return Settings._profile_defaults(pn)["rpc_url"]
|
229
|
+
|
230
|
+
@field_validator("L2_FAUCET_URL", mode='before')
|
231
|
+
@classmethod
|
232
|
+
def prefer_faucet_env(cls, v: str, values: dict) -> str:
|
233
|
+
for key in ("GOLEM_PROVIDER_L2_FAUCET_URL",):
|
234
|
+
if os.environ.get(key):
|
235
|
+
return os.environ[key]
|
236
|
+
if v:
|
237
|
+
return v
|
238
|
+
pn = values.data.get("PAYMENTS_NETWORK") or "l2.holesky"
|
239
|
+
return Settings._profile_defaults(pn).get("faucet_url", "")
|
204
240
|
|
205
241
|
@staticmethod
|
206
|
-
def
|
242
|
+
def _load_deployment(network: str) -> tuple[str | None, str | None]:
|
207
243
|
"""Try to load default StreamPayment + token from contracts/deployments/l2.json.
|
208
244
|
|
209
245
|
Returns (stream_payment_address, glm_token_address) or (None, None) if not found.
|
@@ -212,15 +248,15 @@ class Settings(BaseSettings):
|
|
212
248
|
# Allow override via env
|
213
249
|
base = os.environ.get("GOLEM_DEPLOYMENTS_DIR")
|
214
250
|
if base:
|
215
|
-
path = Path(base) / "
|
251
|
+
path = Path(base) / f"{Settings._deployment_basename(network)}.json"
|
216
252
|
else:
|
217
253
|
# repo root = ../../ from this file
|
218
|
-
path = Path(__file__).resolve().parents[2] / "contracts" / "deployments" / "
|
254
|
+
path = Path(__file__).resolve().parents[2] / "contracts" / "deployments" / f"{Settings._deployment_basename(network)}.json"
|
219
255
|
if not path.exists():
|
220
256
|
# Try package resource fallback
|
221
257
|
try:
|
222
258
|
import importlib.resources as ir
|
223
|
-
with ir.files("provider.data.deployments").joinpath("
|
259
|
+
with ir.files("provider.data.deployments").joinpath(f"{Settings._deployment_basename(network)}.json").open("r") as fh: # type: ignore[attr-defined]
|
224
260
|
data = json.load(fh)
|
225
261
|
except Exception:
|
226
262
|
return None, None
|
@@ -235,29 +271,90 @@ class Settings(BaseSettings):
|
|
235
271
|
pass
|
236
272
|
return None, None
|
237
273
|
|
274
|
+
# Backwards-compat helper used by tests expecting this method name
|
275
|
+
@staticmethod
|
276
|
+
def _load_l2_deployment() -> tuple[str | None, str | None]:
|
277
|
+
return Settings._load_deployment("l2.holesky")
|
278
|
+
|
279
|
+
@staticmethod
|
280
|
+
def _deployment_basename(network: str) -> str:
|
281
|
+
n = (network or "").lower()
|
282
|
+
if n in ("l2", "l2.holesky"):
|
283
|
+
return "l2"
|
284
|
+
if "." in n:
|
285
|
+
return n.split(".")[0]
|
286
|
+
return n or "l2"
|
287
|
+
|
288
|
+
@staticmethod
|
289
|
+
def _profile_defaults(network: str) -> dict[str, str | bool]:
|
290
|
+
n = (network or "l2.holesky").lower()
|
291
|
+
profiles = {
|
292
|
+
"l2.holesky": {
|
293
|
+
"rpc_url": "https://l2.holesky.golemdb.io/rpc",
|
294
|
+
"faucet_url": "https://l2.holesky.golemdb.io/faucet",
|
295
|
+
"faucet_enabled": True,
|
296
|
+
"token_symbol": "GLM",
|
297
|
+
"gas_symbol": "ETH",
|
298
|
+
},
|
299
|
+
"mainnet": {
|
300
|
+
"rpc_url": "",
|
301
|
+
"faucet_url": "",
|
302
|
+
"faucet_enabled": False,
|
303
|
+
"token_symbol": "GLM",
|
304
|
+
"gas_symbol": "ETH",
|
305
|
+
},
|
306
|
+
}
|
307
|
+
return profiles.get(n, profiles["l2.holesky"]) # default to current standard
|
308
|
+
|
238
309
|
@field_validator("STREAM_PAYMENT_ADDRESS", mode='before')
|
239
310
|
@classmethod
|
240
|
-
def default_stream_addr(cls, v: str) -> str:
|
311
|
+
def default_stream_addr(cls, v: str, values: dict) -> str:
|
241
312
|
# Disable payments during pytest to keep unit tests independent
|
242
313
|
if os.environ.get("PYTEST_CURRENT_TEST"):
|
243
314
|
return "0x0000000000000000000000000000000000000000"
|
244
315
|
if v:
|
245
316
|
return v
|
246
|
-
|
317
|
+
pn = values.data.get("PAYMENTS_NETWORK") or "l2.holesky"
|
318
|
+
addr, _ = Settings._load_deployment(pn)
|
247
319
|
return addr or "0x0000000000000000000000000000000000000000"
|
248
320
|
|
249
321
|
@field_validator("GLM_TOKEN_ADDRESS", mode='before')
|
250
322
|
@classmethod
|
251
|
-
def default_token_addr(cls, v: str) -> str:
|
323
|
+
def default_token_addr(cls, v: str, values: dict) -> str:
|
252
324
|
if os.environ.get("PYTEST_CURRENT_TEST"):
|
253
325
|
return "0x0000000000000000000000000000000000000000"
|
254
326
|
if v:
|
255
327
|
return v
|
256
|
-
|
328
|
+
pn = values.data.get("PAYMENTS_NETWORK") or "l2.holesky"
|
329
|
+
_, token = Settings._load_deployment(pn)
|
257
330
|
return token or "0x0000000000000000000000000000000000000000"
|
258
331
|
|
259
332
|
# VM Settings
|
260
333
|
MAX_VMS: int = 10
|
334
|
+
|
335
|
+
# Optional human-friendly symbols from profile
|
336
|
+
TOKEN_SYMBOL: str = Field(default="", description="Payment token symbol, e.g., GLM")
|
337
|
+
GAS_TOKEN_SYMBOL: str = Field(default="", description="Gas token symbol, e.g., ETH")
|
338
|
+
|
339
|
+
@field_validator("TOKEN_SYMBOL", mode='before')
|
340
|
+
@classmethod
|
341
|
+
def default_token_symbol(cls, v: str, values: dict) -> str:
|
342
|
+
if v:
|
343
|
+
return v
|
344
|
+
pn = values.data.get("PAYMENTS_NETWORK") or "l2.holesky"
|
345
|
+
return str(Settings._profile_defaults(pn).get("token_symbol", ""))
|
346
|
+
|
347
|
+
@field_validator("GAS_TOKEN_SYMBOL", mode='before')
|
348
|
+
@classmethod
|
349
|
+
def default_gas_symbol(cls, v: str, values: dict) -> str:
|
350
|
+
if v:
|
351
|
+
return v
|
352
|
+
pn = values.data.get("PAYMENTS_NETWORK") or "l2.holesky"
|
353
|
+
return str(Settings._profile_defaults(pn).get("gas_symbol", ""))
|
354
|
+
|
355
|
+
@property
|
356
|
+
def FAUCET_ENABLED(self) -> bool:
|
357
|
+
return bool(self._profile_defaults(self.PAYMENTS_NETWORK).get("faucet_enabled", False))
|
261
358
|
DEFAULT_VM_IMAGE: str = "ubuntu:24.04"
|
262
359
|
VM_DATA_DIR: str = ""
|
263
360
|
SSH_KEY_DIR: str = ""
|
{golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/golem_base_advertiser.py
RENAMED
@@ -68,6 +68,7 @@ class GolemBaseAdvertiser(Advertiser):
|
|
68
68
|
string_annotations = [
|
69
69
|
Annotation(key="golem_type", value="provider"),
|
70
70
|
Annotation(key="golem_network", value=settings.NETWORK),
|
71
|
+
Annotation(key="golem_payments_network", value=settings.PAYMENTS_NETWORK),
|
71
72
|
Annotation(key="golem_provider_id", value=settings.PROVIDER_ID),
|
72
73
|
Annotation(key="golem_ip_address", value=ip_address),
|
73
74
|
Annotation(key="golem_country", value=settings.PROVIDER_COUNTRY),
|
@@ -149,6 +149,9 @@ def wallet_faucet_l2():
|
|
149
149
|
from .config import settings
|
150
150
|
from .security.l2_faucet import L2FaucetService
|
151
151
|
try:
|
152
|
+
if not bool(getattr(settings, "FAUCET_ENABLED", False)):
|
153
|
+
print("Faucet is disabled for current payments network.")
|
154
|
+
raise typer.Exit(code=0)
|
152
155
|
addr = settings.PROVIDER_ID
|
153
156
|
async def _run():
|
154
157
|
svc = L2FaucetService(settings)
|
@@ -56,21 +56,41 @@ class StreamMonitor:
|
|
56
56
|
logger.warning(f"stream {stream_id} lookup failed: {e}")
|
57
57
|
continue
|
58
58
|
# Stop VM if remaining runway < threshold
|
59
|
-
remaining = max(s["stopTime"] - now, 0)
|
59
|
+
remaining = max(int(s["stopTime"]) - int(now), 0)
|
60
60
|
logger.debug(
|
61
61
|
f"stream {stream_id} for VM {vm_id}: start={s['startTime']} stop={s['stopTime']} "
|
62
62
|
f"rate={s['ratePerSecond']} withdrawn={s['withdrawn']} halted={s['halted']} remaining={remaining}s"
|
63
63
|
)
|
64
|
-
|
65
|
-
|
64
|
+
# If stream is force-halted, delete immediately to free all resources
|
65
|
+
if bool(s.get("halted")):
|
66
|
+
logger.info(
|
67
|
+
f"Deleting VM {vm_id} due to halted stream (id={stream_id}, now={now})"
|
68
|
+
)
|
69
|
+
try:
|
70
|
+
await self.vm_service.delete_vm(vm_id)
|
71
|
+
except Exception as e:
|
72
|
+
logger.warning(f"delete_vm failed for {vm_id}: {e}")
|
73
|
+
try:
|
74
|
+
await self.stream_map.remove(vm_id)
|
75
|
+
except Exception as e:
|
76
|
+
logger.debug(f"failed to remove vm {vm_id} from stream map: {e}")
|
77
|
+
continue
|
78
|
+
|
79
|
+
# Only stop a VM when runway is completely empty
|
80
|
+
if remaining == 0:
|
81
|
+
logger.info(
|
82
|
+
f"Stopping VM {vm_id} as stream runway is exhausted (id={stream_id}, now={now}, stop={s.get('stopTime')})"
|
83
|
+
)
|
66
84
|
try:
|
67
85
|
await self.vm_service.stop_vm(vm_id)
|
68
86
|
except Exception as e:
|
69
87
|
logger.warning(f"stop_vm failed for {vm_id}: {e}")
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
88
|
+
continue
|
89
|
+
|
90
|
+
# Otherwise, do not stop; just log health and consider withdrawals
|
91
|
+
logger.debug(
|
92
|
+
f"VM {vm_id} stream {stream_id} healthy (remaining={remaining}s)"
|
93
|
+
)
|
74
94
|
# Withdraw if enough vested and configured
|
75
95
|
if self._get("STREAM_WITHDRAW_ENABLED", False) and self.client:
|
76
96
|
vested = max(min(now, s["stopTime"]) - s["startTime"], 0) * s["ratePerSecond"]
|
@@ -38,6 +38,10 @@ class L2FaucetService:
|
|
38
38
|
|
39
39
|
Returns tx hash string on payout, or None if skipped/failed.
|
40
40
|
"""
|
41
|
+
# Respect profile gating only if explicitly present and false
|
42
|
+
if hasattr(self.cfg, "FAUCET_ENABLED") and not bool(getattr(self.cfg, "FAUCET_ENABLED")):
|
43
|
+
logger.info("Faucet disabled for current payments network; skipping.")
|
44
|
+
return None
|
41
45
|
bal = self._balance_eth(address)
|
42
46
|
if bal > 0.01:
|
43
47
|
logger.info(f"Sufficient L2 funds ({bal} ETH), skipping faucet.")
|
@@ -60,4 +64,3 @@ class L2FaucetService:
|
|
60
64
|
if tx:
|
61
65
|
logger.success(f"L2 faucet sent tx: {tx}")
|
62
66
|
return tx
|
63
|
-
|
@@ -0,0 +1,148 @@
|
|
1
|
+
import asyncio
|
2
|
+
from fastapi import FastAPI
|
3
|
+
|
4
|
+
from .utils.logging import setup_logger
|
5
|
+
from .vm.service import VMService
|
6
|
+
from .discovery.service import AdvertisementService
|
7
|
+
from .utils.pricing import PricingAutoUpdater
|
8
|
+
|
9
|
+
logger = setup_logger(__name__)
|
10
|
+
|
11
|
+
|
12
|
+
class ProviderService:
|
13
|
+
"""Service for managing the provider's lifecycle."""
|
14
|
+
|
15
|
+
def __init__(self, vm_service: VMService, advertisement_service: AdvertisementService, port_manager):
|
16
|
+
self.vm_service = vm_service
|
17
|
+
self.advertisement_service = advertisement_service
|
18
|
+
self.port_manager = port_manager
|
19
|
+
self._pricing_updater: PricingAutoUpdater | None = None
|
20
|
+
self._stream_monitor = None
|
21
|
+
|
22
|
+
async def setup(self, app: FastAPI):
|
23
|
+
"""Setup and initialize the provider components."""
|
24
|
+
from .config import settings
|
25
|
+
from .utils.ascii_art import startup_animation
|
26
|
+
from .security.faucet import FaucetClient
|
27
|
+
|
28
|
+
try:
|
29
|
+
# Display startup animation
|
30
|
+
await startup_animation()
|
31
|
+
|
32
|
+
logger.process("🔄 Initializing provider...")
|
33
|
+
|
34
|
+
# Setup directories
|
35
|
+
self._setup_directories()
|
36
|
+
|
37
|
+
# Initialize services
|
38
|
+
await self.port_manager.initialize()
|
39
|
+
await self.vm_service.provider.initialize()
|
40
|
+
|
41
|
+
# Before starting advertisement, sync allocated resources with existing VMs
|
42
|
+
try:
|
43
|
+
vm_resources = await self.vm_service.get_all_vms_resources()
|
44
|
+
await self.vm_service.resource_tracker.sync_with_multipass(vm_resources)
|
45
|
+
except Exception as e:
|
46
|
+
logger.warning(f"Failed to sync resources with existing VMs: {e}")
|
47
|
+
|
48
|
+
# Cross-check running VMs against payment streams. If a VM has no
|
49
|
+
# active stream, it is no longer rented: terminate it and free resources.
|
50
|
+
try:
|
51
|
+
# Only perform checks if payments are configured
|
52
|
+
if settings.STREAM_PAYMENT_ADDRESS and not settings.STREAM_PAYMENT_ADDRESS.lower().endswith("0000000000000000000000000000000000000000") and settings.POLYGON_RPC_URL:
|
53
|
+
stream_map = app.container.stream_map()
|
54
|
+
reader = app.container.stream_reader()
|
55
|
+
|
56
|
+
# Use the most recent view of VMs from the previous sync
|
57
|
+
vm_ids = list(vm_resources.keys()) if 'vm_resources' in locals() else []
|
58
|
+
for vm_id in vm_ids:
|
59
|
+
try:
|
60
|
+
stream_id = await stream_map.get(vm_id)
|
61
|
+
except Exception:
|
62
|
+
stream_id = None
|
63
|
+
|
64
|
+
if stream_id is None:
|
65
|
+
reason = "no stream mapped"
|
66
|
+
should_terminate = True
|
67
|
+
else:
|
68
|
+
try:
|
69
|
+
ok, msg = reader.verify_stream(int(stream_id), settings.PROVIDER_ID)
|
70
|
+
should_terminate = not ok
|
71
|
+
reason = msg if not ok else "ok"
|
72
|
+
except Exception as e:
|
73
|
+
# If verification cannot be performed, be conservative and keep the VM
|
74
|
+
logger.warning(f"Stream verification error for VM {vm_id} (stream {stream_id}): {e}")
|
75
|
+
should_terminate = False
|
76
|
+
reason = f"verification error: {e}"
|
77
|
+
|
78
|
+
if should_terminate:
|
79
|
+
logger.info(
|
80
|
+
f"Deleting VM {vm_id}: inactive stream (stream_id={stream_id}, reason={reason})"
|
81
|
+
)
|
82
|
+
try:
|
83
|
+
await self.vm_service.delete_vm(vm_id)
|
84
|
+
except Exception as e:
|
85
|
+
logger.warning(f"Failed to delete VM {vm_id}: {e}")
|
86
|
+
try:
|
87
|
+
await stream_map.remove(vm_id)
|
88
|
+
except Exception:
|
89
|
+
pass
|
90
|
+
|
91
|
+
# Re-sync after any terminations to ensure ads reflect capacity
|
92
|
+
try:
|
93
|
+
vm_resources = await self.vm_service.get_all_vms_resources()
|
94
|
+
await self.vm_service.resource_tracker.sync_with_multipass(vm_resources)
|
95
|
+
except Exception as e:
|
96
|
+
logger.warning(f"Post-termination resource sync failed: {e}")
|
97
|
+
else:
|
98
|
+
logger.info("Payments not configured; skipping startup stream checks")
|
99
|
+
except Exception as e:
|
100
|
+
logger.warning(f"Failed to reconcile VMs with payment streams: {e}")
|
101
|
+
|
102
|
+
await self.advertisement_service.start()
|
103
|
+
# Start pricing auto-updater; trigger re-advertise after updates
|
104
|
+
async def _on_price_updated(platform: str, glm_usd):
|
105
|
+
await self.advertisement_service.trigger_update()
|
106
|
+
self._pricing_updater = PricingAutoUpdater(on_updated_callback=_on_price_updated)
|
107
|
+
asyncio.create_task(self._pricing_updater.start())
|
108
|
+
|
109
|
+
# Start stream monitor if enabled
|
110
|
+
from .container import Container
|
111
|
+
from .config import settings as cfg
|
112
|
+
if cfg.STREAM_MONITOR_ENABLED or cfg.STREAM_WITHDRAW_ENABLED:
|
113
|
+
self._stream_monitor = app.container.stream_monitor()
|
114
|
+
self._stream_monitor.start()
|
115
|
+
|
116
|
+
# Check wallet balance and request funds if needed
|
117
|
+
faucet_client = FaucetClient(
|
118
|
+
faucet_url=settings.FAUCET_URL,
|
119
|
+
captcha_url=settings.CAPTCHA_URL,
|
120
|
+
captcha_api_key=settings.CAPTCHA_API_KEY,
|
121
|
+
)
|
122
|
+
await faucet_client.get_funds(settings.PROVIDER_ID)
|
123
|
+
|
124
|
+
logger.success("✨ Provider setup complete")
|
125
|
+
except Exception as e:
|
126
|
+
logger.error(f"Startup failed: {e}")
|
127
|
+
await self.cleanup()
|
128
|
+
raise
|
129
|
+
|
130
|
+
async def cleanup(self):
|
131
|
+
"""Cleanup provider components."""
|
132
|
+
logger.process("🔄 Cleaning up provider...")
|
133
|
+
await self.advertisement_service.stop()
|
134
|
+
await self.vm_service.provider.cleanup()
|
135
|
+
if self._pricing_updater:
|
136
|
+
self._pricing_updater.stop()
|
137
|
+
if self._stream_monitor:
|
138
|
+
await self._stream_monitor.stop()
|
139
|
+
logger.success("✨ Provider cleanup complete")
|
140
|
+
|
141
|
+
def _setup_directories(self):
|
142
|
+
"""Create necessary directories for the provider."""
|
143
|
+
from .config import settings
|
144
|
+
from pathlib import Path
|
145
|
+
|
146
|
+
Path(settings.VM_DATA_DIR).mkdir(parents=True, exist_ok=True)
|
147
|
+
Path(settings.SSH_KEY_DIR).mkdir(parents=True, exist_ok=True)
|
148
|
+
Path(settings.CLOUD_INIT_DIR).mkdir(parents=True, exist_ok=True)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "golem-vm-provider"
|
3
|
-
version = "0.1.
|
3
|
+
version = "0.1.55"
|
4
4
|
description = "VM on Golem Provider Node - Run your own provider node to offer VMs on the Golem Network"
|
5
5
|
authors = ["Phillip Jensen <phillip+vm-on-golem@golemgrid.com>"]
|
6
6
|
readme = "README.md"
|
@@ -1,86 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
from fastapi import FastAPI
|
3
|
-
|
4
|
-
from .utils.logging import setup_logger
|
5
|
-
from .vm.service import VMService
|
6
|
-
from .discovery.service import AdvertisementService
|
7
|
-
from .utils.pricing import PricingAutoUpdater
|
8
|
-
|
9
|
-
logger = setup_logger(__name__)
|
10
|
-
|
11
|
-
|
12
|
-
class ProviderService:
|
13
|
-
"""Service for managing the provider's lifecycle."""
|
14
|
-
|
15
|
-
def __init__(self, vm_service: VMService, advertisement_service: AdvertisementService, port_manager):
|
16
|
-
self.vm_service = vm_service
|
17
|
-
self.advertisement_service = advertisement_service
|
18
|
-
self.port_manager = port_manager
|
19
|
-
self._pricing_updater: PricingAutoUpdater | None = None
|
20
|
-
self._stream_monitor = None
|
21
|
-
|
22
|
-
async def setup(self, app: FastAPI):
|
23
|
-
"""Setup and initialize the provider components."""
|
24
|
-
from .config import settings
|
25
|
-
from .utils.ascii_art import startup_animation
|
26
|
-
from .security.faucet import FaucetClient
|
27
|
-
|
28
|
-
try:
|
29
|
-
# Display startup animation
|
30
|
-
await startup_animation()
|
31
|
-
|
32
|
-
logger.process("🔄 Initializing provider...")
|
33
|
-
|
34
|
-
# Setup directories
|
35
|
-
self._setup_directories()
|
36
|
-
|
37
|
-
# Initialize services
|
38
|
-
await self.port_manager.initialize()
|
39
|
-
await self.vm_service.provider.initialize()
|
40
|
-
await self.advertisement_service.start()
|
41
|
-
# Start pricing auto-updater; trigger re-advertise after updates
|
42
|
-
async def _on_price_updated(platform: str, glm_usd):
|
43
|
-
await self.advertisement_service.trigger_update()
|
44
|
-
self._pricing_updater = PricingAutoUpdater(on_updated_callback=_on_price_updated)
|
45
|
-
asyncio.create_task(self._pricing_updater.start())
|
46
|
-
|
47
|
-
# Start stream monitor if enabled
|
48
|
-
from .container import Container
|
49
|
-
from .config import settings as cfg
|
50
|
-
if cfg.STREAM_MONITOR_ENABLED or cfg.STREAM_WITHDRAW_ENABLED:
|
51
|
-
self._stream_monitor = app.container.stream_monitor()
|
52
|
-
self._stream_monitor.start()
|
53
|
-
|
54
|
-
# Check wallet balance and request funds if needed
|
55
|
-
faucet_client = FaucetClient(
|
56
|
-
faucet_url=settings.FAUCET_URL,
|
57
|
-
captcha_url=settings.CAPTCHA_URL,
|
58
|
-
captcha_api_key=settings.CAPTCHA_API_KEY,
|
59
|
-
)
|
60
|
-
await faucet_client.get_funds(settings.PROVIDER_ID)
|
61
|
-
|
62
|
-
logger.success("✨ Provider setup complete")
|
63
|
-
except Exception as e:
|
64
|
-
logger.error(f"Startup failed: {e}")
|
65
|
-
await self.cleanup()
|
66
|
-
raise
|
67
|
-
|
68
|
-
async def cleanup(self):
|
69
|
-
"""Cleanup provider components."""
|
70
|
-
logger.process("🔄 Cleaning up provider...")
|
71
|
-
await self.advertisement_service.stop()
|
72
|
-
await self.vm_service.provider.cleanup()
|
73
|
-
if self._pricing_updater:
|
74
|
-
self._pricing_updater.stop()
|
75
|
-
if self._stream_monitor:
|
76
|
-
await self._stream_monitor.stop()
|
77
|
-
logger.success("✨ Provider cleanup complete")
|
78
|
-
|
79
|
-
def _setup_directories(self):
|
80
|
-
"""Create necessary directories for the provider."""
|
81
|
-
from .config import settings
|
82
|
-
from pathlib import Path
|
83
|
-
|
84
|
-
Path(settings.VM_DATA_DIR).mkdir(parents=True, exist_ok=True)
|
85
|
-
Path(settings.SSH_KEY_DIR).mkdir(parents=True, exist_ok=True)
|
86
|
-
Path(settings.CLOUD_INIT_DIR).mkdir(parents=True, exist_ok=True)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/golem_base_utils.py
RENAMED
File without changes
|
{golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/multi_advertiser.py
RENAMED
File without changes
|
{golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/resource_monitor.py
RENAMED
File without changes
|
{golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/discovery/resource_tracker.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{golem_vm_provider-0.1.53 → golem_vm_provider-0.1.55}/provider/payments/blockchain_service.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|