docs(snapshot): sync workspace documentation

This commit is contained in:
u1
2026-03-29 13:14:30 +02:00
parent 93a6e4aa2f
commit 0d3d110026
37 changed files with 8500 additions and 123 deletions

168
rpc/README.md Normal file
View File

@@ -0,0 +1,168 @@
# Baremetal RPC + VPS + Vast (Drift / DLOB / boty)
Ten folder zbiera w jednym miejscu ustalenia dot. topologii:
- **Bare metal**: prywatny Solana RPC (opcjonalnie z Geyser/Yellowstone dla feedów realtime).
- **VPS**: “app/trading box” (k3s) z DLOB, statystykami, API i executorem transakcji.
- **Vast (GPU, min 5090)**: trening transformera + ewentualnie inference, ale **bez sekretów**.
Dokumenty powiązane:
- `doc/dlob-services.md` — jak działają serwisy DLOB na VPS (k3s) i przepływ danych.
- `doc/bots.md` — architektura botów (data plane / execution plane / model plane).
- `doc/rpc/bot-executor-api.md` — minimalne endpointy i auth dla control plane / executora.
- `doc/rpc/baremetal-monitoring.md` — jakie metryki zbieramy na RPC boxie i jak to wdrażamy (IaC).
- `doc/rpc/baremetal-iac.md` — jak utrzymywać `mevnode-baremetal` jako IaC z runnera na VPS.
## Założenia (najważniejsze)
1) **RPC box ma być “lean”**: na bare metalu uruchamiamy tylko Solana RPC + minimum infrastruktury (VPN, firewall, monitoring).
2) **Drift/DLOB i reszta “biznesu” na VPS**: tam są publishery DLOB, Redis, warstwa persistence do Postgresa, DB, API, UI i executor.
3) **Vast = model plane**: trening (i ewentualnie inference) robimy na GPU, ale Vast **nigdy nie dostaje kluczy** ani tokenów do środków.
4) **Start od 2 marketów**: na początek ograniczamy DLOB do małej listy rynków, np. `PERP_MARKETS_TO_LOAD=0,75` (indeksy marketów PERP).
## Topologia (skrót)
```
(public)
┌────────────────────────────────────────────────────┐
│ Internet / UI │
│ trade-frontend + GraphQL (Hasura) + control-plane │
└───────────────▲────────────────────────────────────┘
│ HTTPS (auth), brak “sign & send”
┌──────────────────┴───────────────────────────────────────────────────┐
│ VPS (k3s / trade-staging) │
│ │
│ Data plane: │
│ - dlob-publisher-hot/all → dlob-redis │
│ - hot/all writers → Postgres → Hasura (GraphQL/WS) │
│ │
│ Execution plane: │
│ - bot-executor (jedyny komponent z kluczami, podpisuje transakcje) │
│ - trade-api (tokeny, admin ops, pomocnicze endpointy) │
│ │
│ Monitoring: Prometheus/Grafana/Alertmanager │
└──────────────────▲───────────────────────────────────────────────────┘
│ WireGuard (private)
│ RPC/WS + opcjonalnie gRPC (Geyser)
┌──────────────────┴───────────────────────────────────────────────────┐
│ Bare metal (RPC box) │
│ - agave/solana-validator jako prywatny RPC (bez publicznego dostępu) │
│ - (opcjonalnie) Geyser/Yellowstone gRPC plugin │
│ - wireguard + firewall + chrony + eksportery │
└──────────────────────────────────────────────────────────────────────┘
(public, outbound)
┌──────────────────────────────────────────────────────────────────────┐
│ Vast (GPU, min 5090) │
│ - trening transformera na zebranych danych │
│ - ewentualnie inference endpoint │
│ - brak sekretów (brak kluczy, brak tokenów do środków) │
└──────────────────────────────────────────────────────────────────────┘
```
## Bare metal: co instalować i dlaczego
Minimalny zestaw (zgodnie z regułą “keep it lean”):
- **Solana RPC node** (validator w trybie RPC/non-voting).
- **WireGuard**: RPC dostępny tylko prywatnie (VPS + admin).
- **Firewall**: zablokowane porty RPC/WS na publicznym interfejsie; allow tylko na interfejsie WG.
- **Chrony**: stabilny czas.
- **Monitoring**:
- `node_exporter` (CPU/RAM/dysk/iowait/sieć),
- `solana-exporter` lub równoważny probe health przez RPC.
- **Higiena dysk/logów**: rotacja logów, limity journald, monitoring NVMe.
Opcjonalnie (kolejny poziom “pro”):
- **Geyser / Yellowstone gRPC**: realtime stream kont/tx/slotów (mniejsze opóźnienia niż polling).
### Geyser + Drift DLOB (praktycznie)
Jeśli uruchamiasz Yellowstone gRPC na RPC boxie, to na VPS możesz przełączyć `dlob-publisher`
na feed gRPC (zamiast Solana WS), a jednocześnie dalej trzymać prywatny dostęp po WireGuard.
- RPC HTTP (JSON-RPC): `ENDPOINT=http://<rpc_wg_ip>:8899`
- RPC WS (pubsub): `WS_ENDPOINT=ws://<rpc_wg_ip>:8900`
- Yellowstone gRPC: `GRPC_ENDPOINT=http://<rpc_wg_ip>:10000` (+ `TOKEN`, jeśli włączasz auth)
Konfiguracja DLOB (VPS) w praktyce (skrót):
- `PERP_MARKETS_TO_LOAD=0,75` (start od 2 marketów)
- `USE_ORDER_SUBSCRIBER=true`
- `USE_GRPC=true` + `GRPC_ENDPOINT` + `TOKEN` + `GRPC_CLIENT=yellowstone`
- (opcjonalnie) `DISABLE_GPA_REFRESH=true` żeby ograniczyć polling
Więcej: `doc/rpc/geyser-dlob.md`.
Uwaga o 192 GB RAM:
- Na mainnet łatwo “dobić” pamięć jeśli włączysz ciężkie indeksy kont / rozbudowane API / wielu klientów.
- Dlatego tym bardziej trzymamy RPC jako **prywatny** (mała liczba klientów: DLOB + executor + admin) i przenosimy obliczenia na VPS.
## VPS (k3s): co działa i jak jest używane
W `trade-staging` (k3s) mamy dwa krytyczne “plany”:
### Data plane (market data + statsy)
Opis szczegółowy: `doc/dlob-services.md`.
- `dlob-publisher-hot` i `dlob-publisher-all`: budują DLOB “off your RPC” i publikują snapshoty do Redis.
- Na start ogranicz rynki hot-setu przez `PERP_MARKETS_TO_LOAD`.
- `dlob-redis`: szybki cache dla publisherów i writerów.
- `dlob-hot-redis-to-postgres-raw-writer`, `dlob-hot-postgres-to-postgres-derived-writer`, `dlob-all-redis-to-postgres-derived-writer`:
- zapisują raw `hot` i derived `hot/all` do Postgresa,
- Hasura wystawia te dane jako GraphQL + subscriptions.
### Execution plane (transakcje na Drift)
Opis szczegółowy: `doc/bots.md` (separation of concerns + kill switch).
- **`bot-executor`**:
- jedyny komponent z kluczami (seed/keypair),
- wykonuje `place/modify/cancel/close` + limity ryzyka + kill switch,
- komunikuje się z DB (config/desired state + event log).
### Jak wystawić API na zewnątrz (propozycja)
Kluczowa zasada:
- **Nie wystawiamy publicznie “sign & send tx”**.
Wystawiamy tylko control plane:
- ustawianie `bot_config` (desired state / kill switch),
- odczyt `bot_state` / `bot_events`,
- market data / statsy przez Hasurę (GraphQL) i/lub własne read-only endpointy.
Warstwa dostępu (rekomendacja):
- Sieć: WireGuard / allowlist IP.
- Aplikacja: tokeny + scopes.
- (opcjonalnie) mTLS/HMAC między serwisami.
Executor czyta “desired state” z DB i sam podpisuje transakcje w klastrze.
## IaC (Git) dla bare metalu
Konfigurację RPC boxa (Solana RPC + Geyser + WireGuard + firewall + exporters) warto trzymać w Git
i wdrażać z VPS (np. Ansible po WireGuard).
Starter (szkielet): `infra/baremetal-solana-rpc/`.
## Vast (GPU): jak to wpinamy
Model plane wg `doc/bots.md`:
- VPS zbiera dane (features, statsy, candles, eventy) i składa dataset.
- Trening transformera na Vast (min 5090).
- Artefakty modelu wracają na VPS (lub inference zostaje na Vast), ale:
- **Vast nie dostaje kluczy**,
- VPS podejmuje decyzję o wykonaniu i podpisuje transakcje (executor).

71
rpc/baremetal-iac.md Normal file
View File

@@ -0,0 +1,71 @@
# Bare metal (mevnode) jako IaC: runner na VPS
Cel: utrzymywać `mevnode-baremetal` (Solana RPC box) jako **IaC w Git**, wdrażane z VPS.
Dlaczego z VPS:
- masz stały “runner” (k3s box), który i tak żyje 24/7,
- łatwiej ograniczyć dostęp do bare metalu (WireGuard + allowlist),
- nie mieszasz kluczy i narzędzi na laptopie.
## Założenia
- Na VPS masz alias SSH `mevnode-baremetal` (w `~/.ssh/config`).
- Na bare metalu w `root/.ssh/authorized_keys` jest publiczny klucz z VPS.
- Repo `trade` jest dostępne na VPS (clone).
## Katalog IaC w repo
W tym repo jest starter Ansible:
- `infra/baremetal-solana-rpc/` — Agave (systemd) + opcjonalny Geyser + monitoring.
Sekrety (identity keypair, tokeny) **nie są w repo**.
## Setup na VPS (runner)
1) Zainstaluj Ansible (Ubuntu/Debian na VPS):
```bash
sudo apt-get update
sudo apt-get install -y ansible
```
2) Clone repo (jeśli nie masz):
```bash
git clone <YOUR_REPO_URL> trade
cd trade
```
3) Uzupełnij inventory/vars (lokalne, nie commitujemy):
```bash
cd infra/baremetal-solana-rpc/ansible
cp inventory/hosts.ini.example inventory/hosts.ini
cp group_vars/solana_rpc.yml.example group_vars/solana_rpc.yml
```
4) Dostosuj `group_vars/solana_rpc.yml` pod Wasz WireGuard IP, ścieżki danych i opcje Geyser.
5) Wdroż:
```bash
ansible-playbook -i inventory/hosts.ini playbook.yml
```
## Co to już robi (MVP)
- instaluje pakiety bazowe + `chrony`,
- przygotowuje usera `solana` + katalogi danych/logów,
- wrzuca systemd unit `solana-rpc` (Agave),
- (opcjonalnie) wrzuca config Yellowstone i podpina plugin,
- instaluje monitoring (node_exporter + probe RPC) opisany w `doc/rpc/baremetal-monitoring.md`.
## Co dalej (kolejne warstwy)
- WireGuard + firewall (żeby RPC/WS/gRPC nie wisiały publicznie),
- ograniczenie `RPC/WS` bind do WG IP,
- rotacja logów / limity journald,
- backup identity keypair + runbook odtwarzania.

136
rpc/baremetal-monitoring.md Normal file
View File

@@ -0,0 +1,136 @@
# Monitoring bare metalu (Solana RPC box)
Cel: mieć **twarde metryki** dla prywatnego RPC (i opcjonalnie Geysera), żeby:
- szybko wykrywać `slot lag`, spadki wydajności i problemy I/O,
- mieć “SLO” dla komponentów zależnych na VPS (DLOB / executor),
- nie zgadywać “czy to RAM/CPU/dysk/sieć”.
Wszystko poniżej zakłada, że RPC box jest **prywatny** (dostęp tylko po WireGuard).
## Co instalujemy (MVP)
### 1) Node exporter (hostowe metryki)
Pakiet: `prometheus-node-exporter`
Daje standardowe metryki hosta:
- CPU / iowait,
- RAM,
- filesystem usage,
- network,
- podstawowe statystyki procesów.
Bindujemy go na IP WireGuard (żeby nie wystawiać publicznie).
### 2) RPC probe → node_exporter textfile collector
To jest mały probe uruchamiany systemd timerem, który zapisuje plik `*.prom`
do textfile collector node_exportera.
Wystawia m.in.:
- `solana_rpc_up` (1/0),
- `solana_rpc_latency_seconds{method="getHealth|getSlot"}`,
- `solana_rpc_slot`,
- `solana_rpc_block_height`,
- `solana_rpc_slot_lag` (opcjonalnie, jeśli podasz endpoint referencyjny).
### 3) Yellowstone (Geyser) Prometheus endpoint (opcjonalnie)
Jeśli uruchamiasz plugin `yellowstone-grpc`, on sam wystawia `/metrics`
(adres/port z configu pluginu).
To jest osobny target do scrapowania w Prometheus.
## Gdzie jest IaC (Ansible)
IaC jest w `infra/baremetal-solana-rpc/`:
- playbook: `infra/baremetal-solana-rpc/ansible/playbook.yml`
- przykładowe zmienne: `infra/baremetal-solana-rpc/ansible/group_vars/solana_rpc.yml.example`
Monitoring jest domyślnie “włączony” w przykładzie. Najważniejsze zmienne:
- `node_exporter_listen` (np. `10.10.0.2:9100`)
- `node_exporter_textfile_collector_dir`
- `solana_rpc_probe_endpoint` (np. `http://10.10.0.2:8899`)
- `solana_rpc_probe_reference_endpoint` (opcjonalnie; slot lag vs referencja)
- `yellowstone_prometheus_listen` (np. `10.10.0.2:8999`)
## Jak wdrożyć (z VPS / runnera)
1) Uzupełnij inventory i vars (bez commitowania sekretów):
```bash
cd infra/baremetal-solana-rpc/ansible
cp inventory/hosts.ini.example inventory/hosts.ini
cp group_vars/solana_rpc.yml.example group_vars/solana_rpc.yml
```
2) Uruchom playbook:
```bash
ansible-playbook -i inventory/hosts.ini playbook.yml
```
## Jak sprawdzić, że działa
Z VPS (po WireGuard):
- node exporter: `curl -sS http://<rpc_wg_ip>:9100/metrics | head`
- RPC probe metryki: `curl -sS http://<rpc_wg_ip>:9100/metrics | rg "solana_rpc_" | head`
- yellowstone: `curl -sS http://<rpc_wg_ip>:8999/metrics | head` (jeśli włączone)
### Slot lag
Żeby dashboard miał metrykę `solana_rpc_slot_lag`, ustaw `solana_rpc_probe_reference_endpoint` na publiczny RPC (przykład: `https://api.mainnet-beta.solana.com`). W konfiguracji Ansible:
```yaml
solana_rpc_probe_reference_endpoint: "https://api.mainnet-beta.solana.com"
```
Po restarcie timer/probe:
- `systemctl restart solana-rpc-textfile-probe.timer`
- `systemctl start solana-rpc-textfile-probe.service`
W Prometheus/Grafanie:
- `solana_rpc_slot{job="mpabi-node-exporter",instance="<twoj-node-exporter-instance>"}`
- `solana_rpc_slot_reference{job="mpabi-node-exporter",instance="<twoj-node-exporter-instance>"}`
- `solana_rpc_slot_lag{job="mpabi-node-exporter",instance="<twoj-node-exporter-instance>"}`
### Alerty Prometheus
W `trade-deploy/kustomize/infra/monitoring-extras` dodane zostały alerty:
- `AgaveRPCDown``solana_rpc_up == 0` przez >30s
- `AgaveRPCSlotLagHigh` — lag > 50 slotów przez >2m
- `AgaveRPCSlotLagCritical` — lag > 500 slotów przez >2m
- `AgaveIOHigh` — wysoki throughput na `nvme` (read+write > 300MiB/s przez 5m)
- `AgaveIOWaitHigh``iowait > 20%` przez 5m
Po deployu ArgoCD (`monitoring-extras`) alerty są od razu aktywne.
Jeśli chcesz od razu zaciągnąć zmianę:
- `kubectl -n argocd get application monitoring-extras -o wide`
- `kubectl -n argocd annotate application monitoring-extras argocd.argoproj.io/refresh=hard --overwrite`
- `kubectl -n monitoring get prometheusrules.monitoring.coreos.com agave-rpc-alerts -o wide`
## Prometheus na VPS: co scrapować
Najprostszy wariant to statyczne targety po WG:
- `http://<rpc_wg_ip>:9100/metrics` (host + solana_rpc_*),
- `http://<rpc_wg_ip>:8999/metrics` (yellowstone, jeśli używasz).
Zasada: żadnych portów RPC/metrics na publicznym NIC.
## Minimalne alerty (polecane)
- `solana_rpc_up == 0` przez > 30s
- `solana_rpc_slot_lag > 50` przez > 12 min (jeśli liczysz lag)
- `node_filesystem_avail_bytes` < 1015% (ledger/accounts szybko zjadają dysk)
- wysokie `node_cpu_seconds_total{mode="iowait"}` (NVMe bottleneck)

121
rpc/bot-executor-api.md Normal file
View File

@@ -0,0 +1,121 @@
# Minimalne API dla bot-executora (k3s) + auth
Ten dokument opisuje **minimalny** zestaw endpointów i zasad bezpieczeństwa dla warstwy
**execution plane** (`bot-executor`) i **control plane** (API do sterowania botami) na VPS (k3s).
Cel: wysyłać transakcje na Drift **bez wystawiania publicznie** endpointu typu “podpisz i wyślij tx”.
Powiązane:
- Architektura botów: `doc/bots.md`
- DLOB / statsy na VPS: `doc/dlob-services.md`
- Topologia: `doc/rpc/README.md`
## Rozdział odpowiedzialności
### `bot-executor` (execution plane, private)
- Ma klucze prywatne (tylko tutaj).
- Podpisuje i wysyła transakcje na Drift przez prywatny Solana RPC.
- Czyta “desired state” z DB (`bot_config`) i zapisuje audyt (`bot_events`) + heartbeat (`bot_state`).
- **Nie** przyjmuje z zewnątrz “raw tx do podpisu”.
### Control plane (public/edge, auth)
- Ustawianie `bot_config` (mode/target/limity/kill switch).
- Odczyt `bot_state` i `bot_events`.
- Autoryzacja: tokeny/ACL/WireGuard (zależnie od klienta).
Control plane może być zrobiony na dwa sposoby:
1) **Hasura GraphQL** (z rolami i RLS) — szybkie, ale wymaga dopięcia uprawnień.
2) **`trade-api` endpointy** (HTTP) — prostsze do “opiniowania” auth (Bearer token scopes).
## Model danych (minimum)
Minimalne tabele (wg `doc/bots.md`):
- `bot_config`: desired state (mode, market, limity, kill_switch, strategia)
- `bot_state`: heartbeat + ostatni błąd/akcja
- `bot_events`: log audytowy (decision/order/panic/error)
## Auth (rekomendacja minimalna)
Warstwy:
1) **Sieć**: tylko przez WireGuard / allowlist IP (najprostsze i skuteczne).
2) **Aplikacja**: tokeny + scopes (np. `Authorization: Bearer ...`).
3) (Opcjonalnie) **mTLS/HMAC** service-to-service w klastrze, jeśli chcesz twardsze granice.
W tym repo masz już wzorzec tokenów w `api_tokens` + walidacja w `services/api/server.mjs`.
### Scopes (propozycja)
- `bots:read` — odczyt `bot_config/state/events`
- `bots:write` — zmiana `bot_config` (mode/params/kill switch)
- `exec:panic` — wymuszenie panic (jeśli zdecydujesz się na osobny endpoint; zwykle wystarczy `kill_switch=true`)
## Control plane API (HTTP) — propozycja endpointów
Te endpointy wystawiaj publicznie (za auth), ale **niech one tylko zmieniają DB**, a nie wysyłają transakcje.
### Konfiguracja bota
- `GET /v1/bots` (scope: `bots:read`)
- lista botów (id, name, market, mode, kill_switch, updated_at)
- `GET /v1/bots/:id` (scope: `bots:read`)
- pełny `bot_config`
- `POST /v1/bots` (scope: `bots:write`)
- tworzy nowy `bot_config`
- `PATCH /v1/bots/:id` (scope: `bots:write`)
- aktualizacja (np. limity, target exposure, params)
### Kill switch / mode (najczęstsze akcje)
- `POST /v1/bots/:id/mode` (scope: `bots:write`)
- body: `{ "mode": "off" | "observe" | "trade" }`
- `POST /v1/bots/:id/kill-switch` (scope: `bots:write`)
- body: `{ "enabled": true | false }`
- Executor traktuje `enabled=true` jako “panic” i wykonuje runbook (`cancel_all` + `close_position`) opisany w `doc/bots.md`.
### Status i audyt
- `GET /v1/bots/:id/state` (scope: `bots:read`)
- heartbeat, last_error, last_action_at
- `GET /v1/bots/:id/events?limit=200` (scope: `bots:read`)
- ostatnie eventy (decision/order/panic/error)
## `bot-executor` API (private) — minimalne endpointy
To API **nie musi być wystawione** poza klaster. Wystarczy Service `ClusterIP`.
- `GET /healthz` — liveness (bez auth)
- `GET /readyz` — readiness (bez auth; np. czy jest połączenie z RPC + DB)
- (Opcjonalnie) `POST /v1/reconcile` — ręczny reconcile (auth tylko wewnętrzny / admin)
Zamiast `POST /v1/panic` preferuj sterowanie przez DB (`kill_switch=true`), bo to daje audyt i działa nawet,
gdy control plane jest odcięty od samego executora.
## Deployment w k3s (propozycja)
- `Deployment/bot-executor`:
- env: RPC endpoints (po WG), Hasura URL, market list, itp.
- secret: keypair / seed, ewentualnie API tokeny
- zasoby: limity CPU/RAM (żeby executor nie “zjadał” nodea)
- `Service/bot-executor` (ClusterIP)
- brak Ingress (domyślnie)
- Monitoring:
- `Prometheus` scrape `/metrics` (jeśli dodasz)
## Co z “wysłaniem kontraktu” na Drift?
- `bot-executor` robi to przez Drift SDK → Solana RPC (`sendTransaction`).
- Control plane **nie** wysyła tx; tylko ustawia desired state.

79
rpc/geyser-dlob.md Normal file
View File

@@ -0,0 +1,79 @@
# Geyser (Yellowstone gRPC) + Drift DLOB
Ten dokument jest “praktycznym mostem” między:
- **RPC boxem** (bare metal) z `agave/solana-validator` i pluginem **Geyser/Yellowstone gRPC**,
- a **VPS** (k3s), gdzie działa **Drift DLOB** (publisher + redis + server + statsy).
Cel: realtime feed “prosto z noda” (gRPC), bez wystawiania RPC publicznie.
## Założenia sieciowe (must-have)
- Bare metal ↔ VPS po **WireGuard**.
- Porty RPC/WS/gRPC dostępne **tylko** po WG (albo bind do WG IP + firewall).
- Publicznie nie wystawiamy:
- Solana RPC/WS,
- Yellowstone gRPC,
- Redis.
## Porty (typowe)
To nie są twarde wymagania, ale typowy setup wygląda tak:
- Solana JSON-RPC HTTP: `8899`
- Solana pubsub WS: `8900`
- Yellowstone gRPC: `10000`
## Jak to mapuje się na env (VPS)
W `trade-staging` trzymaj endpointy jako secrety i wstrzykuj do podów:
- `ENDPOINT=http://<rpc_wg_ip>:8899`
- `WS_ENDPOINT=ws://<rpc_wg_ip>:8900`
- `GRPC_ENDPOINT=http://<rpc_wg_ip>:10000`
- `TOKEN=...` (jeśli włączasz auth w Yellowstone)
Uwaga:
- W naszym kodzie `dlob-publisher` w trybie gRPC używa gRPC głównie do `OrderSubscriber`.
DriftClient (accountSubscriber) nadal polega na WS/polling (gRPC dla driftClient jest w kodzie wyłączone),
więc **WS endpoint nadal musi działać**.
- Dla `OrderSubscriber` w trybie gRPC mamy lokalny auto-reconnect. Jeśli Yellowstone zamknie stream albo zwroci `14 UNAVAILABLE: Connection dropped`, publisher nie powinien juz wychodzic z `exit 1`; zamiast tego czyści stream i probuje wznowic subskrypcje. Backoff jest sterowany przez `GRPC_RECONNECT_DELAY_MS` i domyslnie wynosi `1000 ms`.
## DLOB: zalecana konfiguracja na start (2 markety)
Przykład ustawień dla `dlob-publisher`:
- `ENV=mainnet-beta`
- `PERP_MARKETS_TO_LOAD=0,75` (2 markety)
- `USE_ORDER_SUBSCRIBER=true`
- `USE_WEBSOCKET=true` (dla DriftClient / slotów)
- `USE_GRPC=true`
- `GRPC_CLIENT=yellowstone`
- `GRPC_ENDPOINT=...`
- `TOKEN=...` (jeśli wymagany)
- (opcjonalnie) `DISABLE_GPA_REFRESH=true` (żeby zmniejszyć polling)
Jeśli po drodze okaże się, że gRPC jest niestabilne, nadal możesz wrócić do trybu WS:
- wyłącz `USE_GRPC` i zostaw `USE_WEBSOCKET=true`.
Ale operacyjnie najpierw warto sprawdzic logi reconnectu, bo krotkie dropy streamu powinny byc teraz obslugiwane bez restartu poda.
## Minimalne testy “czy działa”
Z perspektywy VPS:
1) Sprawdź, czy gRPC port jest osiągalny po WG (np. TCP connect do `10000`).
2) W logach `dlob-publisher` powinno być widoczne, że `useGrpc: true` (albo analogiczna flaga).
3) Metryki DLOB powinny pokazywać rosnące liczniki updateów (publisher) oraz świeże sloty.
## Co to daje vs zwykły RPC/WS
- Niższa latencja i stabilniejszy stream zmian kont (szczególnie, gdy klientów WS jest dużo).
- Mniej “pchania” ciężkich subskrypcji przez publiczny RPC.
Co to nie rozwiązuje:
- “Pamięciożerności” DLOB jako takiej (stan orderbooka i user map rośnie z rynkami i aktywnością).
- Wymaga nadal rozsądnej konfiguracji rynku (na start: mała lista marketów).

89
rpc/software-placement.md Normal file
View File

@@ -0,0 +1,89 @@
# Strategia rozmieszczenia softu (bare metal / VPS / Vast)
Celem jest:
- **stabilny, prywatny feed danych** (Solana RPC → DLOB → statsy),
- **bezpieczne wykonanie transakcji** (klucze tylko na VPS),
- **skalowanie ML** (trening na Vast), bez kompromisu bezpieczeństwa.
Źródła kontekstu w repo:
- DLOB i przepływ danych: `doc/dlob-services.md`
- Boty i podział na planey: `doc/bots.md`
## Zasady (priorytety)
1) **RPC box jest “lean”** — żadnych baz danych, Grafany, workerów, botów.
2) **Klucze tylko w execution plane** — żadnych kluczy na Vast i w UI.
3) **Publicznie tylko read/control plane** — bez endpointu “podpisz i wyślij”.
4) **Ogranicz rynki** na start (np. `PERP_MARKETS_TO_LOAD=0,75`), żeby odchudzić cały pipeline.
## Co gdzie uruchamiamy
### Bare metal (Solana RPC box)
Uruchamiaj:
- `agave/solana-validator` jako prywatny RPC (non-voting).
- (Opcjonalnie) `geyser` / `yellowstone-grpc` plugin, jeśli chcesz feed “faster-than-RPC”.
- WireGuard + firewall + chrony.
- Monitoring: `node_exporter` + probe zdrowia RPC.
Nie uruchamiaj:
- DLOB, Redis, Hasura/Postgres, Grafana, botów.
Powód: RAM 192 GB jest cenny dla noda; trzymamy minimalną liczbę procesów i klientów.
### VPS (k3s / “app + trading box”)
Uruchamiaj:
- **Data plane**:
- `dlob-publisher-hot` i `dlob-publisher-all` (czytają z prywatnego RPC/WS lub gRPC),
- `dlob-redis`,
- `dlob-hot-redis-to-postgres-raw-writer`,
- `dlob-hot-postgres-to-postgres-derived-writer`,
- `dlob-all-redis-to-postgres-derived-writer`,
- Postgres + Hasura (GraphQL/WS dla “latest” tabel i sterowania botami).
- **Execution plane**:
- `bot-executor` (klucze, podpisywanie transakcji, risk, kill switch).
- **Control plane / UI**:
- `trade-frontend` (proxy/auth + UI),
- `trade-api` (narzędzia: tokeny, admin, pomocnicze endpointy).
- Monitoring:
- Prometheus/Grafana/Alertmanager.
Wystawianie na zewnątrz (rekomendacja):
- Publicznie: UI + GraphQL (Hasura) + ewentualnie read-only API.
- Control plane: endpointy do ustawiania `bot_config` i odczytu `bot_state/bot_events` (z auth).
- **Nie publicznie**: `bot-executor`, prywatny RPC, Redis.
### Vast (GPU / “model plane”)
Uruchamiaj:
- Trening transformera na danych wyeksportowanych z VPS (batch).
- Ewentualnie inference endpoint (jeśli chcesz oddzielić obciążenie od VPS).
Nie uruchamiaj / nie przechowuj:
- kluczy prywatnych,
- tokenów do środków,
- dostępu do prywatnego RPC po VPN (nie jest potrzebny do treningu).
## Kontrakt VPS ↔ Vast (bezpieczny)
- VPS wysyła: “feature snapshots” / dataset (bez sekretów).
- Vast zwraca: “decision” (np. target exposure/side/confidence).
- VPS decyduje o wykonaniu (risk engine) i podpisuje transakcję (executor).
## Minimalny start (2 markety)
1) DLOB:
- `PERP_MARKETS_TO_LOAD=0,75` (i analogicznie dla TOB monitoring, jeśli używasz).
2) Execution:
- `bot-executor` czyta config z DB, nie z requestów “na żywo”.
3) Public API:
- brak “sign & send”; tylko control-plane + read-only dane.

232
rpc/topol.html Normal file
View File

@@ -0,0 +1,232 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Professional Drift Trading Stack (Own Solana RPC + Own DLOB + Vast ML)</title>
<style>
:root { color-scheme: light dark; }
body {
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
line-height: 1.5;
margin: 0;
padding: 32px 20px;
max-width: 980px;
margin-inline: auto;
}
header { margin-bottom: 24px; }
h1 { font-size: 1.6rem; margin: 0 0 8px; }
.subtitle { opacity: 0.85; margin: 0; }
.card {
border: 1px solid rgba(127,127,127,0.35);
border-radius: 14px;
padding: 18px 18px;
margin: 14px 0;
background: rgba(127,127,127,0.05);
}
h2 { font-size: 1.2rem; margin: 0 0 10px; }
h3 { font-size: 1.05rem; margin: 14px 0 8px; }
ul { margin: 8px 0 0 18px; }
li { margin: 6px 0; }
code, pre { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.note {
border-left: 4px solid rgba(127,127,127,0.55);
padding: 10px 12px;
margin: 10px 0 0;
background: rgba(127,127,127,0.07);
border-radius: 10px;
}
.pill {
display: inline-block;
padding: 2px 10px;
border: 1px solid rgba(127,127,127,0.35);
border-radius: 999px;
font-size: 0.85rem;
opacity: 0.9;
}
</style>
</head>
<body>
<header>
<h1>Professional Drift Trading Stack</h1>
<p class="subtitle">
Own Solana RPC + Own Drift DLOB (Orderbook). Main rule:
<strong>keep the RPC box lean</strong>, put “trading services” on your second VPS.
<span class="pill">Target: min 10 markets</span>
<span class="pill">+ Vast (GPU) for ML</span>
</p>
</header>
<section class="card">
<h2>Overview</h2>
<p>
Yes — you can build a professional Drift trading stack with your own Solana RPC + your own DLOB,
but youll want a few supporting services around them. The main rule:
keep the RPC box lean, put “trading services” on your second VPS.
</p>
</section>
<section class="card">
<h2>On the Solana RPC server (dedicated) — keep it lean</h2>
<h3>Must-have</h3>
<ul>
<li>
<strong>Solana validator/RPC node</strong><br />
The base RPC your whole stack reads from / sends transactions through.
</li>
<li>
<strong>WireGuard</strong><br />
So RPC is reachable only privately (your second VPS + your admin).
</li>
<li>
<strong>Firewall (nftables/ufw)</strong><br />
Block RPC ports on public NIC; allow them only on WireGuard.
</li>
<li>
<strong>Time sync (chrony)</strong><br />
For stable networking, logs, and trading timestamps.
</li>
<li>
<strong>Monitoring exporters</strong>
<ul>
<li><strong>node_exporter</strong> (CPU/RAM/disk/iowait/network)</li>
<li><strong>solana-exporter</strong> (RPC/validator health via RPC)</li>
</ul>
</li>
<li>
<strong>Log + disk hygiene</strong>
<ul>
<li>logrotate/journald limits</li>
<li>NVMe health (smartmontools/nvme-cli)</li>
<li>alerts on disk filling / iowait</li>
</ul>
</li>
</ul>
<h3>Optional but “pro”</h3>
<ul>
<li>
<strong>Geyser streaming (Yellowstone gRPC plugin)</strong><br />
This gives ultra-low-latency streams of accounts/tx/slots compared to polling RPC.
Useful if you build your own real-time analytics pipeline.
<div class="note">
For Drift specifically, you can run without Geyser at the beginning,
but its the next step when you want “faster-than-RPC” feeds.
</div>
</li>
</ul>
</section>
<section class="card">
<h2>On the second VPS (your trading / app box) — where “pro trading” lives</h2>
<h3>Must-have</h3>
<ul>
<li>
<strong>Drift DLOB server (self-hosted)</strong><br />
This maintains the Drift decentralized orderbook view “fresh off your RPC” and exposes
REST + WS + gRPC/polling, plus health/metrics.
</li>
<li>
<strong>(Optional but common) Drift Gateway</strong><br />
A self-hosted API gateway to interact with Drift; handy for standardized API endpoints
around trading / market info.
</li>
<li>
<strong>Cache (Redis)</strong><br />
Cache top-of-book, funding, oracle snapshots, risk checks; protects your DLOB + RPC
from bursty bot load.
</li>
<li>
<strong>Metrics + dashboards</strong><br />
Prometheus + Grafana + Alertmanager
<div class="note">
Keep Grafana off the validator box; common ops guidance is to separate monitoring UI for safety.
</div>
</li>
<li>
<strong>Your trading services</strong>
<ul>
<li>strategy engine(s)</li>
<li>execution service (transaction builder/sender)</li>
<li>risk service (position limits, kill-switch, circuit breakers)</li>
</ul>
</li>
</ul>
<h3>Optional, depending on how “institutional” you want</h3>
<ul>
<li>
<strong>Database (Postgres/Timescale)</strong><br />
Persist fills, order events, PnL series, backtesting datasets.
</li>
<li>
<strong>Message bus (NATS/Kafka/Redis Streams)</strong><br />
Decouple ingestion (orderbook/events) from strategies/execution.
</li>
</ul>
</section>
<section class="card">
<h2>On the third box (Vast GPU) — model / research plane</h2>
<h3>What lives here</h3>
<ul>
<li>
<strong>Training (Transformer / ML)</strong><br />
Train on datasets exported from your VPS (orderbook stats, trades, features).
</li>
<li>
<strong>(Optional) Inference endpoint</strong><br />
Serve model decisions back to VPS. The VPS still owns execution.
</li>
</ul>
<div class="note">
Security rule: Vast should never hold private keys nor get access to your funds.
Treat it as a “signal generator”; execution and signing must remain on the VPS.
</div>
</section>
<section class="card">
<h2>Cost model (since you asked “cost per request”)</h2>
<p>
With your own RPC, there is no per-request billing. The “cost” is:
</p>
<ul>
<li>fixed monthly servers (your €149/m + the second VPS),</li>
<li>and capacity (CPU/RAM/NVMe/bandwidth) consumed by:
<ul>
<li>DLOB syncing from RPC,</li>
<li>number of WS subscriptions,</li>
<li>how many markets you track.</li>
</ul>
</li>
</ul>
<p class="note">
DLOB exists specifically to reduce RPC load by serving orderbook/trade views to clients
instead of every client rebuilding it from chain.
</p>
</section>
<section class="card">
<h2>Minimal “pro” starting set (recommended)</h2>
<ul>
<li><strong>RPC box:</strong> Solana RPC + WireGuard + firewall + node_exporter + solana-exporter</li>
<li><strong>App VPS:</strong> DLOB server + Redis + Prometheus/Grafana + your bot services</li>
</ul>
<p class="note">
For <strong>min 10 markets</strong>, expect the first scaling pressure to come from
continuous streaming + decoding + caching (DLOB + Redis + your strategy/execution),
and from your RPCs WS load. Next step after the minimal set is usually:
better streaming (Geyser) or more RAM/NVMe depending on bottleneck.
</p>
</section>
<footer style="opacity:.75; margin-top: 22px;">
<small>Saved as HTML — you can paste this into a file like <code>drift-stack.html</code>.</small>
</footer>
</body>
</html>