docs(snapshot): sync workspace documentation
This commit is contained in:
168
rpc/README.md
Normal file
168
rpc/README.md
Normal 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
71
rpc/baremetal-iac.md
Normal 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
136
rpc/baremetal-monitoring.md
Normal 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 > 1–2 min (jeśli liczysz lag)
|
||||
- `node_filesystem_avail_bytes` < 10–15% (ledger/accounts szybko zjadają dysk)
|
||||
- wysokie `node_cpu_seconds_total{mode="iowait"}` (NVMe bottleneck)
|
||||
121
rpc/bot-executor-api.md
Normal file
121
rpc/bot-executor-api.md
Normal 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ł” node’a)
|
||||
|
||||
- `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
79
rpc/geyser-dlob.md
Normal 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
89
rpc/software-placement.md
Normal 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 plane’y: `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
232
rpc/topol.html
Normal 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 you’ll 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 it’s 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 RPC’s 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>
|
||||
Reference in New Issue
Block a user