From ade8579bae11395a9dfb1a72eb8de730ff3b3243 Mon Sep 17 00:00:00 2001 From: u1 Date: Thu, 12 Mar 2026 23:26:17 +0100 Subject: [PATCH] docs(solana-rpc): expand agave and geyser runbook --- ...ep-002-plan-solana-rpc-mainnet-private.txt | 122 ++++---- doc/step-002-solana-rpc-install.txt | 117 ++++---- ...a-storage-existing-solacct-solledg-xfs.txt | 51 ++++ doc/step-002a-storage-nvme0n1-xfs.txt | 64 +++++ doc/step-002b-agave-validator-systemd.txt | 79 ++++++ doc/step-002c-genesis-download-mainnet.txt | 34 +++ doc/step-002d-snapshot-download-mainnet.txt | 49 ++++ doc/step-002e-agave-validator-run-cli.txt | 71 +++++ ...ep-002f-agave-build-from-source-latest.txt | 70 +++++ ...pabi-runbook-agave-rpc-geyser-postgres.txt | 264 ++++++++++++++++++ doc/step-003-geyser-plugin-postgres.txt | 122 ++++++++ 11 files changed, 923 insertions(+), 120 deletions(-) create mode 100644 doc/step-002a-storage-existing-solacct-solledg-xfs.txt create mode 100644 doc/step-002a-storage-nvme0n1-xfs.txt create mode 100644 doc/step-002b-agave-validator-systemd.txt create mode 100644 doc/step-002c-genesis-download-mainnet.txt create mode 100644 doc/step-002d-snapshot-download-mainnet.txt create mode 100644 doc/step-002e-agave-validator-run-cli.txt create mode 100644 doc/step-002f-agave-build-from-source-latest.txt create mode 100644 doc/step-002g-mpabi-runbook-agave-rpc-geyser-postgres.txt create mode 100644 doc/step-003-geyser-plugin-postgres.txt diff --git a/doc/step-002-plan-solana-rpc-mainnet-private.txt b/doc/step-002-plan-solana-rpc-mainnet-private.txt index 9195b27..ba11d50 100644 --- a/doc/step-002-plan-solana-rpc-mainnet-private.txt +++ b/doc/step-002-plan-solana-rpc-mainnet-private.txt @@ -1,10 +1,11 @@ -Step 002: Plan wdrozenia Solana RPC (Agave mainnet, non-voting, private RPC + Yellowstone gRPC + monitoring + NOC tmux) +Step 002: Plan wdrozenia Solana RPC (Agave mainnet, non-voting, private RPC + Geyser->Postgres + monitoring + NOC tmux) Zalozenia (default): - WG iface: wg0, WG subnet: 10.66.66.0/24, WG IP baremetala: 10.66.66.1 - Public iface: eth0, public IP: 149.50.116.219 -- RPC: 8899 (HTTP), WS: 8900 -- Yellowstone gRPC: 10000 (tylko po WG) +- RPC: 8899 (HTTP), WS: 8900 (WS = RPC_PORT+1) +- Postgres (lokalnie): 5432 (DB: geyser, user: geyser) +- (Optional) Yellowstone gRPC: 10000 (tylko po WG) - Prometheus: 9090, Grafana: 3000, node_exporter: 9100 (tylko po WG) - Dynamic port range (cluster): 8000-8020/udp (public eth0) - User: solana @@ -28,6 +29,7 @@ Zalozenia (default): sysstat iotop \ ethtool nstat \ chrony curl jq git ca-certificates \ + ripgrep \ smartmontools nvme-cli \ build-essential pkg-config libssl-dev \ clang llvm-dev libclang-dev \ @@ -46,6 +48,15 @@ Zalozenia (default): # sudo chown solana:solana /var/lib/solana/identity.json # sudo chmod 600 /var/lib/solana/identity.json +2A) Storage (rekomendowane) + # Variant A: jesli /dev/nvme0n1 jest wolny i chcesz go podzielic 50/50: + # doc/step-002a-storage-nvme0n1-xfs.txt + # + # Variant B (mpabi): masz juz 2x NVMe z XFS: + # - SOLACCT na accounts (nvme0n1p1) + # - SOLLEDG na ledger (nvme1n1p1) + # doc/step-002a-storage-existing-solacct-solledg-xfs.txt + 3) Firewall/WG binding (private-only) # UFW: deny everything inbound by default sudo ufw default deny incoming @@ -102,39 +113,16 @@ EOF sudo -u solana -H bash -lc 'sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"' # Copy binaries to /opt/solana/bin (avoid symlink permission gotchas) - sudo bash -lc ' - set -e - SRC="/var/lib/solana/.local/share/solana/install/active_release/bin" - DST="/opt/solana/bin" - for f in "$SRC"/*; do - [ -f "$f" ] || continue - install -m 0755 "$f" "$DST/$(basename "$f")" - done - ' + sudo cp -a /var/lib/solana/.local/share/solana/install/active_release/bin/. /opt/solana/bin/ + sudo find /opt/solana/bin -maxdepth 1 -type f -exec chmod 0755 {} \; /opt/solana/bin/solana --version || true /opt/solana/bin/solana-keygen --version # Build agave-validator (pin tag + toolchain) - AGAVE_VERSION_TAG="v2.3.13" - AGAVE_RUST_TOOLCHAIN="1.86.0" - AGAVE_SRC_DIR="/var/lib/solana/src/agave" - - sudo -u solana -H bash -lc "curl -sSfL https://sh.rustup.rs | sh -s -- -y --default-toolchain '${AGAVE_RUST_TOOLCHAIN}'" - sudo -u solana -H bash -lc " - set -euo pipefail - export PATH=/var/lib/solana/.cargo/bin:\$PATH - rustup toolchain install '${AGAVE_RUST_TOOLCHAIN}' - mkdir -p '$(dirname \"$AGAVE_SRC_DIR\")' - rm -rf '${AGAVE_SRC_DIR}' - git clone --depth 1 --branch '${AGAVE_VERSION_TAG}' https://github.com/anza-xyz/agave.git '${AGAVE_SRC_DIR}' - cd '${AGAVE_SRC_DIR}' - cargo +${AGAVE_RUST_TOOLCHAIN} build --release -p agave-validator - " - - sudo install -o root -g root -m 0755 \ - "${AGAVE_SRC_DIR}/target/release/agave-validator" \ - /opt/solana/bin/agave-validator + # Uwaga: dla nowszych stable release'ow binarka moze nie byc publikowana, + # wiec build ze zrodel jest wymagany. + # doc/step-002f-agave-build-from-source-latest.txt # Identity (create once) if [ ! -f /var/lib/solana/identity.json ]; then @@ -148,15 +136,20 @@ EOF --data '{"jsonrpc":"2.0","id":1,"method":"getGenesisHash"}' \ https://api.mainnet-beta.solana.com | jq -r .result)" echo "$GENESIS_HASH" + # Oczekiwane (mainnet): 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d # systemd unit (bind RPC to WG/localhost only) - # NOTE: agave-validator expects sockets on the same IP in many setups. - # We keep bind 0.0.0.0 but rely on UFW to ensure private-only access to RPC/WS. - sudo tee /etc/systemd/system/agave-validator.service >/dev/null </dev/null <<'EOF' [Unit] Description=Agave validator (mainnet, RPC-only, non-voting) -After=network-online.target -Wants=network-online.target +After=network-online.target wg-quick@wg0.service +Wants=network-online.target wg-quick@wg0.service [Service] Type=simple @@ -168,22 +161,21 @@ LimitNOFILE=1048576 Restart=always RestartSec=5 TimeoutStopSec=120 -ExecStart=/opt/solana/bin/agave-validator \\ - --identity /var/lib/solana/identity.json \\ - --no-voting \\ - --ledger /var/lib/solana/ledger \\ - --accounts /var/lib/solana/accounts \\ - --log /var/log/solana/validator.log \\ - --bind-address 0.0.0.0 \\ - --rpc-bind-address 0.0.0.0 \\ - --rpc-port 8899 \\ - --rpc-pubsub-bind-address 0.0.0.0 \\ - --rpc-pubsub-port 8900 \\ - --dynamic-port-range 8000-8020 \\ - --entrypoint entrypoint.mainnet-beta.solana.com:8001 \\ - --expected-genesis-hash ${GENESIS_HASH} \\ - --full-rpc-api \\ - --limit-ledger-size +ExecStart=/opt/solana/bin/agave-validator \ + --identity /var/lib/solana/identity.json \ + --no-voting \ + --private-rpc \ + --ledger /var/lib/solana/ledger \ + --accounts /var/lib/solana/accounts \ + --log /var/log/solana/validator.log \ + --bind-address 0.0.0.0 \ + --rpc-bind-address 10.66.66.1 \ + --rpc-port 8899 \ + --dynamic-port-range 8000-8020 \ + --entrypoint entrypoint.mainnet-beta.solana.com:8001 \ + --expected-genesis-hash 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d \ + --full-rpc-api \ + --limit-ledger-size 50000000 NoNewPrivileges=true PrivateTmp=true ProtectSystem=full @@ -199,15 +191,24 @@ EOF systemctl is-active agave-validator journalctl -u agave-validator -n 80 --no-pager -5) Yellowstone gRPC (plugin) (placeholder) - # TODO (next step): install/build yellowstone geyser plugin matching Agave 3.0.15, - # put plugin .so under /opt/solana/plugins/, write /etc/solana/yellowstone-geyser.json, - # and add to ExecStart: - # --geyser-plugin-config /etc/solana/yellowstone-geyser.json + # Jesli padnie na genesis (brak genesis.tar.bz2): + # doc/step-002c-genesis-download-mainnet.txt # - # Verification (after enable): - # journalctl -u agave-validator | rg -i 'geyser|yellowstone|plugin' - # ss -lntp | rg ':10000\\b' + # Jesli padnie na snapshot (mainnet wymaga snapshot): + # doc/step-002d-snapshot-download-mainnet.txt + # + # Jesli chcesz najpierw odpalic validator z CLI (test), zanim przepniesz na systemd: + # doc/step-002e-agave-validator-run-cli.txt + +5) Geyser plugin -> Postgres + # Krok po kroku: + # doc/step-003-geyser-plugin-postgres.txt + # + # W skrocie: + # - budujesz plugin .so i wrzucasz do /opt/solana/plugins/ + # - tworzysz /etc/solana/geyser-postgres.json + # - dopisujesz do ExecStart: + # --geyser-plugin-config /etc/solana/geyser-postgres.json 6) Drift DLOB (2 markets) (on VPS, not baremetal) (placeholder) # VPS env: @@ -258,4 +259,3 @@ EOF curl -sS -H 'content-type: application/json' \ --data '{"jsonrpc":"2.0","id":1,"method":"getSlot"}' \ http://10.66.66.1:8899 | jq . - diff --git a/doc/step-002-solana-rpc-install.txt b/doc/step-002-solana-rpc-install.txt index d3c820e..ad207c9 100644 --- a/doc/step-002-solana-rpc-install.txt +++ b/doc/step-002-solana-rpc-install.txt @@ -5,25 +5,29 @@ Stan startowy: - SSH po publicznym eth0 jest odciete (UFW deny na eth0:22), SSH dziala tylko po wg0. - RPC ma byc prywatny: porty 8899/8900 tylko po wg0, ale node ma miec publiczne porty klastra (UDP dynamic range) zeby syncowal. -UWAGA o bind: -- `agave-validator` praktycznie wymaga, zeby wszystkie sockety byly na tym samym IP. -- Dlatego w tym kroku bindujemy usluge na 0.0.0.0 i zabezpieczamy dostep firewall-em: - - eth0: blokujemy TCP 8899/8900 - - wg0: pozwalamy TCP 8899/8900 - - eth0: pozwalamy UDP dynamic port range (np. 8000-8020) dla klastra +UWAGA o prywatnosci: +- RPC/WS bindujemy na wg0 (10.66.66.1), zeby NIE wystawic RPC na publicznym eth0 nawet gdy UFW jest wylaczone. +- Dodatkowo i tak robimy UFW "deny" na eth0:8899/8900 (defense-in-depth). Parametry (dostosuj, przyklad mainnet): - PUBLIC_IFACE=eth0 - WG_IFACE=wg0 - WG_IP=10.66.66.1 - ENDPOINT_RPC_PORT=8899 -- ENDPOINT_WS_PORT=8900 +- ENDPOINT_WS_PORT=8900 (WS = RPC_PORT+1) - DYNAMIC_PORT_RANGE="8000:8020" +0) Storage (rekomendowane) +Jesli masz osobny NVMe na dane (ledger/accounts), zrob najpierw: + doc/step-002a-storage-nvme0n1-xfs.txt +albo (mpabi, 2x NVMe z juz istniejacym XFS): + doc/step-002a-storage-existing-solacct-solledg-xfs.txt + 1) Bazowe pakiety sudo apt-get update sudo apt-get install -y \ chrony curl jq git \ + ripgrep \ smartmontools nvme-cli \ build-essential pkg-config libssl-dev \ clang llvm-dev libclang-dev \ @@ -38,6 +42,10 @@ Parametry (dostosuj, przyklad mainnet): sudo install -d -o solana -g solana -m 0750 \ /var/lib/solana /var/lib/solana/ledger /var/lib/solana/accounts /var/log/solana + # Jesli ledger/accounts sa mountpointami (Step 002A), upewnij sie, ze root FS jest writable dla usera solana: + sudo chown solana:solana /var/lib/solana/ledger /var/lib/solana/accounts + sudo chmod 750 /var/lib/solana/ledger /var/lib/solana/accounts + 3) Sysctl + ulimit (baseline pod Agave) sudo tee /etc/sysctl.d/90-agave.conf >/dev/null <<'EOF' fs.file-max = 2000000 @@ -83,44 +91,19 @@ EOF 5) Narzedzia Solana/Anza (dla `solana`): solana-keygen itd. sudo -u solana -H bash -lc 'sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"' - ACTIVE_RELEASE_BIN_DIR="/var/lib/solana/.local/share/solana/install/active_release/bin" - test -d "$ACTIVE_RELEASE_BIN_DIR" || { echo "Missing: $ACTIVE_RELEASE_BIN_DIR" >&2; exit 1; } - for bin in "$ACTIVE_RELEASE_BIN_DIR"/*; do - sudo ln -sfn "$bin" "/opt/solana/bin/$(basename "$bin")" - done - test -x /opt/solana/bin/solana-keygen + # Weryfikacja, ze installer utworzyl active_release/bin (bez exit, zeby nie ubijac pane/tmux): + sudo -u solana -H bash -lc 'ls -ld ~/.local/share/solana/install/active_release/bin && ls -1 ~/.local/share/solana/install/active_release/bin | head' + + # Kopiuj binarki do /opt/solana/bin (zamiast symlinkow - mniej problemow z uprawnieniami) + sudo cp -a /var/lib/solana/.local/share/solana/install/active_release/bin/. /opt/solana/bin/ + sudo find /opt/solana/bin -maxdepth 1 -type f -exec chmod 0755 {} \; + + /opt/solana/bin/solana-keygen --version 6) Build `agave-validator` ze zrodel i instalacja do /opt/solana/bin - AGAVE_VERSION_TAG="v2.3.13" - AGAVE_RUST_TOOLCHAIN="1.86.0" - AGAVE_SRC_DIR="/var/lib/solana/src/agave" - - sudo -u solana -H bash -lc \ - "curl -sSfL https://sh.rustup.rs | sh -s -- -y --default-toolchain '${AGAVE_RUST_TOOLCHAIN}'" - - sudo -u solana -H bash -lc " - set -euo pipefail - export PATH=/var/lib/solana/.cargo/bin:\$PATH - rustup toolchain install '${AGAVE_RUST_TOOLCHAIN}' - - mkdir -p '$(dirname "$AGAVE_SRC_DIR")' - if [ ! -d '${AGAVE_SRC_DIR}/.git' ]; then - git clone --depth 1 --branch '${AGAVE_VERSION_TAG}' https://github.com/anza-xyz/agave.git '${AGAVE_SRC_DIR}' - else - cd '${AGAVE_SRC_DIR}' - git fetch --tags --prune - git checkout '${AGAVE_VERSION_TAG}' - fi - - cd '${AGAVE_SRC_DIR}' - cargo +${AGAVE_RUST_TOOLCHAIN} build --release -p agave-validator - " - - sudo install -o root -g root -m 0755 \ - "${AGAVE_SRC_DIR}/target/release/agave-validator" \ - /opt/solana/bin/agave-validator - - test -x /opt/solana/bin/agave-validator + # Najnowszy stable release dla mainnet wybieraj z GitHub Releases (tag v3.0.x). + # Krok po kroku (w tym automatyczny wybor tagu): + doc/step-002f-agave-build-from-source-latest.txt 7) Identity (tylko raz) + backup poza hostem if [ ! -f /var/lib/solana/identity.json ]; then @@ -146,14 +129,21 @@ Testnet: https://api.testnet.solana.com | jq -r .result)" echo "$GENESIS_HASH" -9) Systemd unit: /etc/systemd/system/solana-rpc.service -Minimalny unit (RPC node, non-voting). Bind na 0.0.0.0 + firewall robi prywatnosc RPC. +9) Systemd unit: /etc/systemd/system/agave-validator.service +Minimalny unit (RPC node, non-voting). RPC/WS bind na wg0 (10.66.66.1). +Jesli widzisz w logach: + "error: The subcommand '\\' wasn't recognized" +to zrob: + doc/step-002b-agave-validator-systemd.txt - sudo tee /etc/systemd/system/solana-rpc.service >/dev/null <<'EOF' +Jesli chcesz najpierw odpalic recznie z CLI (test) przed systemd: + doc/step-002e-agave-validator-run-cli.txt + + sudo tee /etc/systemd/system/agave-validator.service >/dev/null <<'EOF' [Unit] -Description=Solana RPC node (Agave) -After=network-online.target -Wants=network-online.target +Description=Agave validator (mainnet, RPC-only, non-voting) +After=network-online.target wg-quick@wg0.service +Wants=network-online.target wg-quick@wg0.service [Service] Type=simple @@ -168,16 +158,18 @@ TimeoutStopSec=120 ExecStart=/opt/solana/bin/agave-validator \ --identity /var/lib/solana/identity.json \ --no-voting \ + --private-rpc \ --ledger /var/lib/solana/ledger \ --accounts /var/lib/solana/accounts \ + --log /var/log/solana/validator.log \ --bind-address 0.0.0.0 \ - --rpc-bind-address 0.0.0.0 \ + --rpc-bind-address 10.66.66.1 \ --rpc-port 8899 \ --dynamic-port-range 8000-8020 \ --entrypoint entrypoint.mainnet-beta.solana.com:8001 \ + --expected-genesis-hash 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d \ --full-rpc-api \ - --limit-ledger-size \ - --log /var/log/solana/validator.log + --limit-ledger-size 50000000 NoNewPrivileges=true PrivateTmp=true ProtectSystem=full @@ -188,20 +180,20 @@ WantedBy=multi-user.target EOF sudo systemctl daemon-reload - sudo systemctl enable --now solana-rpc + sudo systemctl enable --now agave-validator Jesli chcesz dodac genesis hash: - dopisz w ExecStart linie: --expected-genesis-hash 10) Weryfikacja - systemctl is-active solana-rpc - journalctl -u solana-rpc -n 200 --no-pager + systemctl is-active agave-validator + journalctl -u agave-validator -n 200 --no-pager - # z samego hosta: + # z samego hosta (getHealth moze zwracac blad dopoki node nie dogoni klastra): curl -sS -H 'content-type: application/json' \ - --data '{"jsonrpc":"2.0","id":1,"method":"getHealth"}' \ - http://127.0.0.1:8899 | jq . + --data '{"jsonrpc":"2.0","id":1,"method":"getVersion"}' \ + http://10.66.66.1:8899 | jq . # z laptopa/VPS po WG: curl -sS -H 'content-type: application/json' \ @@ -211,5 +203,12 @@ Jesli chcesz dodac genesis hash: Jesli cos nie dziala: - `sudo wg show` (czy WG jest OK) - `sudo ufw status verbose` (czy RPC nie jest blokowane po wg0) -- `journalctl -u solana-rpc -n 200 --no-pager` (logi Agave) +- `journalctl -u agave-validator -n 200 --no-pager` (logi Agave) +Typowe fixy: +- "error: The subcommand '\\' wasn't recognized": + doc/step-002b-agave-validator-systemd.txt +- "failed to open genesis" / brak `genesis.tar.bz2`: + doc/step-002c-genesis-download-mainnet.txt +- "did you forget to provide a snapshot" (mainnet bez snapshot nie ruszy): + doc/step-002d-snapshot-download-mainnet.txt diff --git a/doc/step-002a-storage-existing-solacct-solledg-xfs.txt b/doc/step-002a-storage-existing-solacct-solledg-xfs.txt new file mode 100644 index 0000000..2be7955 --- /dev/null +++ b/doc/step-002a-storage-existing-solacct-solledg-xfs.txt @@ -0,0 +1,51 @@ +Step 002A (variant): Storage na 2x NVMe (XFS juz istnieje) -> SOLACCT=accounts, SOLLEDG=ledger + +Context (wg hosta mpabi): +- /dev/nvme0n1p1: XFS LABEL=SOLACCT (nowy dysk na accounts) +- /dev/nvme1n1p1: XFS LABEL=SOLLEDG (stary dysk ~63% used na ledger) + +Cel: +- NIE formatowac (bez kasowania danych), tylko zamontowac i spiac w /etc/fstab: + - /var/lib/solana/accounts -> SOLACCT + - /var/lib/solana/ledger -> SOLLEDG + +0) Check (zanim dotkniesz fstab) + lsblk -f + sudo blkid /dev/nvme0n1p1 /dev/nvme1n1p1 + + # Upewnij sie, ze NIC nie jest zamontowane w /var/lib/solana/*: + findmnt /var/lib/solana/accounts || true + findmnt /var/lib/solana/ledger || true + +1) Mountpointy + sudo getent group solana >/dev/null || sudo groupadd --system solana + sudo id -u solana >/dev/null 2>&1 || sudo useradd --system --gid solana \ + --home-dir /var/lib/solana --create-home --shell /bin/bash solana + + sudo install -d -o solana -g solana -m 0750 /var/lib/solana/accounts /var/lib/solana/ledger + +2) /etc/fstab (po UUID) + UUID_ACCTS="$(sudo blkid -s UUID -o value /dev/nvme0n1p1)" + UUID_LEDGER="$(sudo blkid -s UUID -o value /dev/nvme1n1p1)" + + echo "UUID=$UUID_ACCTS /var/lib/solana/accounts xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null + echo "UUID=$UUID_LEDGER /var/lib/solana/ledger xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null + + sudo mount -a + sudo systemctl daemon-reload + +3) Permissions (po mount) - krytyczne + sudo chown solana:solana /var/lib/solana/accounts /var/lib/solana/ledger + sudo chmod 750 /var/lib/solana/accounts /var/lib/solana/ledger + +4) Weryfikacja + df -hT /var/lib/solana/accounts /var/lib/solana/ledger + findmnt /var/lib/solana/accounts + findmnt /var/lib/solana/ledger + stat -c '%U:%G %a %n' /var/lib/solana/accounts /var/lib/solana/ledger + +5) Uwaga (bezpieczenstwo / dane) +- Jesli na SOLLEDG masz stare dane ledgera z innej instalacji, to validator moze startowac na "starym stanie". + Wtedy najlepiej wyczyscic ledger przed pobraniem snapshotow: + doc/step-002d-snapshot-download-mainnet.txt (sekcja czyszczenia) + diff --git a/doc/step-002a-storage-nvme0n1-xfs.txt b/doc/step-002a-storage-nvme0n1-xfs.txt new file mode 100644 index 0000000..262ca9a --- /dev/null +++ b/doc/step-002a-storage-nvme0n1-xfs.txt @@ -0,0 +1,64 @@ +Step 002A: Storage pod Solana data (nvme0n1 -> XFS -> /var/lib/solana/{ledger,accounts}) + +Cel: +- system zostaje na md1 (/) +- dane Solany (ledger/accounts) ida na osobny NVMe: /dev/nvme0n1 + +UWAGA: kroki nizej KASUJA dane na /dev/nvme0n1. + +0) Check (czy nvme0n1 jest do wyczyszczenia) + lsblk /dev/nvme0n1 + sudo wipefs -n /dev/nvme0n1 + sudo lsblk -f /dev/nvme0n1 + +1) Partycje (50/50) + sudo apt-get update + sudo apt-get install -y parted + + sudo parted -s /dev/nvme0n1 mklabel gpt + sudo parted -s /dev/nvme0n1 mkpart primary 0% 50% + sudo parted -s /dev/nvme0n1 mkpart primary 50% 100% + sudo partprobe /dev/nvme0n1 + sudo udevadm settle + + lsblk /dev/nvme0n1 + ls -l /dev/nvme0n1p1 /dev/nvme0n1p2 + +2) Format XFS +Uwaga: mkfs.xfs na Ubuntu ma limit label <= 12 znakow. + + sudo mkfs.xfs -f -L sol_ledger /dev/nvme0n1p1 + sudo mkfs.xfs -f -L sol_accts /dev/nvme0n1p2 + sudo blkid /dev/nvme0n1p1 /dev/nvme0n1p2 + +3) Mountpointy + fstab (po UUID) + sudo install -d -o solana -g solana -m 0750 /var/lib/solana/ledger /var/lib/solana/accounts + + UUID_LEDGER="$(sudo blkid -s UUID -o value /dev/nvme0n1p1)" + UUID_ACCTS="$(sudo blkid -s UUID -o value /dev/nvme0n1p2)" + + echo "UUID=$UUID_LEDGER /var/lib/solana/ledger xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null + echo "UUID=$UUID_ACCTS /var/lib/solana/accounts xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null + + sudo mount -a + + # systemd pokazuje hint po edycji fstab - to jest OK, ale zrob reload: + sudo systemctl daemon-reload + +4) WAŻNE: ustaw ownera na zamontowanych filesystemach +Po mount, root filesystemu jest domyslnie root:root 755, wiec validator uruchamiany jako solana nie zapisze ledger/accounts. + + sudo chown solana:solana /var/lib/solana/ledger /var/lib/solana/accounts + sudo chmod 750 /var/lib/solana/ledger /var/lib/solana/accounts + +5) Weryfikacja + df -hT /var/lib/solana/ledger /var/lib/solana/accounts + findmnt /var/lib/solana/ledger + findmnt /var/lib/solana/accounts + + stat -c '%U:%G %a %n' /var/lib/solana/ledger /var/lib/solana/accounts + +Dla tego hosta (z wdrozenia): +- /dev/nvme0n1p1 (LABEL=sol_ledger) UUID=56a2c342-3162-43f2-9649-e0dd25db870d +- /dev/nvme0n1p2 (LABEL=sol_accts) UUID=ae5d6625-0910-489a-bbe3-6fd156439e03 + diff --git a/doc/step-002b-agave-validator-systemd.txt b/doc/step-002b-agave-validator-systemd.txt new file mode 100644 index 0000000..9557d5d --- /dev/null +++ b/doc/step-002b-agave-validator-systemd.txt @@ -0,0 +1,79 @@ +Step 002B: agave-validator pod systemd (RPC-only, non-voting) + fix na problemy z ExecStart + +Ten krok naprawia 2 typowe bledy po wklejeniu unit-a: +1) "error: The subcommand '\\' wasn't recognized" +2) RPC nie startuje, bo ExecStart zostal "polamany" (brakuje --rpc-port albo --log ma sciezke do katalogu) + +Przyczyna: +- W unit file kontynuacja linii w ExecStart to JEDEN backslash na koncu linii: `\` +- NIE uzywaj `\\` (dwa backslashe) bo wtedy do programu trafia literalny argument `\` i validator pada. +- Dodatkowo: unikaj bardzo dlugich linii, bo clipboard/paste potrafi je rozciac (i systemd wtedy ignoruje reszte). + +0) Stop/wycisz restart loop + sudo systemctl disable --now agave-validator + sudo systemctl reset-failed agave-validator + +1) Wrzuc poprawny unit (wielolinijkowy ExecStart z poprawna kontynuacja `\`) + sudo tee /etc/systemd/system/agave-validator.service >/dev/null <<'EOF' +[Unit] +Description=Agave validator (mainnet, RPC-only, non-voting) +After=network-online.target wg-quick@wg0.service +Wants=network-online.target wg-quick@wg0.service + +[Service] +Type=simple +User=solana +Group=solana +WorkingDirectory=/var/lib/solana +Environment=RUST_LOG=info +LimitNOFILE=1048576 +Restart=always +RestartSec=5 +TimeoutStopSec=120 +ExecStart=/opt/solana/bin/agave-validator \ + --identity /var/lib/solana/identity.json \ + --no-voting \ + --private-rpc \ + --ledger /var/lib/solana/ledger \ + --accounts /var/lib/solana/accounts \ + --log /var/log/solana/validator.log \ + --bind-address 0.0.0.0 \ + --rpc-bind-address 10.66.66.1 \ + --rpc-port 8899 \ + --dynamic-port-range 8000-8025 \ + --entrypoint entrypoint.mainnet-beta.solana.com:8001 \ + --entrypoint entrypoint2.mainnet-beta.solana.com:8001 \ + --entrypoint entrypoint3.mainnet-beta.solana.com:8001 \ + --expected-genesis-hash 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d \ + --full-rpc-api \ + --limit-ledger-size 50000000 \ + --geyser-plugin-config /etc/solana/yellowstone-geyser.json +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=full +ReadWritePaths=/var/lib/solana/ledger /var/lib/solana/accounts /var/log/solana /var/lib/solana + +[Install] +WantedBy=multi-user.target +EOF + +2) Reload + start + sudo systemctl daemon-reload + sudo systemctl enable --now agave-validator + +3) Weryfikacja (na hoście) + # Sprawdz, czy systemd widzi kompletne argv[] (ma byc --rpc-port 8899 i poprawna sciezka --log): + systemctl show agave-validator -p ExecStart --no-pager + + sudo systemctl status agave-validator --no-pager -l + + # Czy porty sluchaja (RPC/WS na wg0): + sudo ss -lntp | egrep ':8899\\b|:8900\\b' || true + + # getHealth moze zwracac blad dopoki node nie dogoni klastra, wiec sprawdz getVersion: + curl -sS -H 'content-type: application/json' \ + --data '{"jsonrpc":"2.0","id":1,"method":"getVersion"}' \ + http://10.66.66.1:8899 | jq . + + # Logi: + sudo journalctl -u agave-validator -n 120 --no-pager diff --git a/doc/step-002c-genesis-download-mainnet.txt b/doc/step-002c-genesis-download-mainnet.txt new file mode 100644 index 0000000..1ec0752 --- /dev/null +++ b/doc/step-002c-genesis-download-mainnet.txt @@ -0,0 +1,34 @@ +Step 002C: Download genesis (mainnet) do /var/lib/solana/ledger (fix na "failed to open genesis") + +Objaw w logach: + Failed to load genesis_config ... missing genesis.bin + Extracting "/var/lib/solana/ledger/genesis.tar.bz2"... + Failed to start validator: failed to open genesis ... No such file or directory + +Fix: +- Zaciagnij genesis archive na dysk i zrestartuj serwis. + +1) Zatrzymaj validator (zeby nie robil restart loop) + sudo systemctl stop agave-validator + +2) Pobierz genesis.tar.bz2 do ledger (jako user `solana`) + sudo -u solana -H bash -lc ' + cd /var/lib/solana/ledger + rm -f genesis.tar.bz2 genesis.bin + curl -sSfL https://api.mainnet-beta.solana.com/genesis.tar.bz2 -o genesis.tar.bz2 + ls -lh genesis.tar.bz2 + ' + +Oczekiwane: + - plik genesis.tar.bz2 istnieje (ok. kilkadziesiat KB) + +3) Start + logi + sudo systemctl start agave-validator + systemctl status agave-validator --no-pager -l + sudo journalctl -u agave-validator -n 80 --no-pager + +4) RPC check (local/WG) + curl -sS -H 'content-type: application/json' \ + --data '{"jsonrpc":"2.0","id":1,"method":"getVersion"}' \ + http://10.66.66.1:8899 | jq . + diff --git a/doc/step-002d-snapshot-download-mainnet.txt b/doc/step-002d-snapshot-download-mainnet.txt new file mode 100644 index 0000000..c8e00e7 --- /dev/null +++ b/doc/step-002d-snapshot-download-mainnet.txt @@ -0,0 +1,49 @@ +Step 002D: Download snapshot (mainnet) do /var/lib/solana/ledger (wymagane na mainnet) + +Objaw (bez snapshot): + Failed to start validator: ... did you forget to provide a snapshot + +UWAGA: +- Snapshot full jest DUZY (setki GB). Ten krok moze trwac dlugo. +- Pobieramy full + incremental z oficjalnego endpointu (api.mainnet-beta.solana.com). + +0) Stop validator + sudo systemctl stop agave-validator + +1) (Opcjonalnie, polecane) wyczysc stare dane ledger (zostaw genesis.*) + sudo -u solana -H bash -lc ' + cd /var/lib/solana/ledger + rm -rf rocksdb snapshots accounts_index accounts_hash_cache admin.rpc ledger.lock + ls -la | head + ' + +2) Pobierz FULL + INCREMENTAL snapshot do ledger (jako user `solana`) + sudo -u solana -H bash -lc ' + set -euo pipefail + cd /var/lib/solana/ledger + + FULL_REL="$(curl -sI https://api.mainnet-beta.solana.com/snapshot.tar.bz2 | awk "/^location:/{print \\$2}" | tr -d "\\r")" + INC_REL="$(curl -sI https://api.mainnet-beta.solana.com/incremental-snapshot.tar.bz2 | awk "/^location:/{print \\$2}" | tr -d "\\r")" + + echo "FULL_REL=$FULL_REL" + echo "INC_REL=$INC_REL" + + FULL_URL="https://api.mainnet-beta.solana.com${FULL_REL}" + INC_URL="https://api.mainnet-beta.solana.com${INC_REL}" + + FULL_FILE="$(basename "$FULL_REL")" + INC_FILE="$(basename "$INC_REL")" + + echo "Downloading FULL: $FULL_FILE" + curl -fSL "$FULL_URL" -o "$FULL_FILE" + ls -lh "$FULL_FILE" + + echo "Downloading INC: $INC_FILE" + curl -fSL "$INC_URL" -o "$INC_FILE" + ls -lh "$INC_FILE" + ' + +3) Start validator + logi + sudo systemctl start agave-validator + sudo journalctl -u agave-validator -n 80 --no-pager + diff --git a/doc/step-002e-agave-validator-run-cli.txt b/doc/step-002e-agave-validator-run-cli.txt new file mode 100644 index 0000000..711ec10 --- /dev/null +++ b/doc/step-002e-agave-validator-run-cli.txt @@ -0,0 +1,71 @@ +Step 002E: Start agave-validator z linii polecen (test przed systemd) + +Cel: +- Odpalic `agave-validator` recznie (w tmux), potwierdzic ze RPC dziala. +- Dopiero potem przepiac na systemd (Step 002B). + +Preconditions: +- Masz genesis + snapshoty: + - doc/step-002c-genesis-download-mainnet.txt + - doc/step-002d-snapshot-download-mainnet.txt +- WireGuard dziala (RPC ma byc prywatne po wg0). + +0) Upewnij sie, ze systemd nie trzyma procesu na portach +```bash +sudo systemctl stop agave-validator || true +sudo systemctl disable agave-validator || true +``` + +1) Odpal w tmux (zeby proces nie zginal po rozlaczeniu SSH) +```bash +tmux new -s agave-rpc +``` + +2) Start (dzialajaca komenda z wdrozenia) +```bash +sudo bash -lc ' +set -euo pipefail +ulimit -n 1048576 +exec sudo -u solana -H /opt/solana/bin/agave-validator \ + --identity /var/lib/solana/identity.json \ + --no-voting \ + --private-rpc \ + --ledger /var/lib/solana/ledger \ + --accounts /var/lib/solana/accounts \ + --log - \ + --bind-address 0.0.0.0 \ + --rpc-bind-address 10.66.66.1 \ + --rpc-port 8899 \ + --dynamic-port-range 8000-8020 \ + --entrypoint entrypoint.mainnet-beta.solana.com:8001 \ + --entrypoint entrypoint2.mainnet-beta.solana.com:8001 \ + --entrypoint entrypoint3.mainnet-beta.solana.com:8001 \ + --expected-genesis-hash 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d \ + --full-rpc-api \ + --limit-ledger-size 50000000 +' +``` + +3) Weryfikacja (w drugim oknie / innym terminalu) +```bash +ss -lnt | egrep ':8899\\b|:8900\\b' || true +``` + +```bash +curl -sS -H 'content-type: application/json' \ + --data '{"jsonrpc":"2.0","id":1,"method":"getVersion"}' \ + http://10.66.66.1:8899 | jq . +``` + +4) Detach z tmux +- `Ctrl+b d` + +5) Stop (gdy chcesz zatrzymac recznie) +- `tmux attach -t agave-rpc` +- `Ctrl+c` (zatrzyma validator) +- `exit` + +Next: +- Jak komenda dziala stabilnie, wrzuc unit i odpal przez systemd: + doc/step-002b-agave-validator-systemd.txt + diff --git a/doc/step-002f-agave-build-from-source-latest.txt b/doc/step-002f-agave-build-from-source-latest.txt new file mode 100644 index 0000000..4172266 --- /dev/null +++ b/doc/step-002f-agave-build-from-source-latest.txt @@ -0,0 +1,70 @@ +Step 002F: Build Agave (agave-validator) z najnowszych zrodel (pin do releasu) i instalacja do /opt/solana/bin + +Cel: +- Zbudowac `agave-validator` ze zrodel z pinu do konkretnego releasu (stable dla mainnet). +- Nie robic "floating HEAD" (zeby nie wjechal update bez kontroli). + +Konwencja: +- "najnowsza wersja" = najnowszy stabilny release dla mainnet z GitHub Releases repo `anza-xyz/agave`. + (Zweryfikuj przed startem: tag typu v3.0.x.) + +0) Packages (build deps) + sudo apt-get update + sudo apt-get install -y \ + build-essential pkg-config libssl-dev \ + clang llvm-dev libclang-dev \ + cmake protobuf-compiler libudev-dev zlib1g-dev \ + curl jq git ca-certificates + +1) Uzytkownik + katalogi + sudo getent group solana >/dev/null || sudo groupadd --system solana + sudo id -u solana >/dev/null 2>&1 || sudo useradd --system --gid solana \ + --home-dir /var/lib/solana --create-home --shell /bin/bash solana + + sudo install -d -o root -g root -m 0755 /opt/solana/bin + sudo install -d -o solana -g solana -m 0750 /var/lib/solana/src + +2) Wybierz tag releasu (stable dla mainnet) + # Opcja A (manual): sprawdz Releases i wpisz tag, np.: + AGAVE_VERSION_TAG="v3.0.13" + + # Opcja B (CLI): pobierz liste tagow i wybierz najwyzszy semver (bez rc/beta) + # (Uwaga: to korzysta z network; jesli nie masz neta - uzyj opcji A.) + AGAVE_VERSION_TAG="$( + git ls-remote --refs --tags https://github.com/anza-xyz/agave.git 'v*' \ + | awk -F/ '{print $NF}' \ + | rg -v '(rc|beta|alpha)' \ + | sort -V \ + | tail -n1 + )" + echo "AGAVE_VERSION_TAG=$AGAVE_VERSION_TAG" + +3) Rust toolchain + # Rekomendacja: uzyj rustup (Agave ma pinned toolchain w repo). + sudo -u solana -H bash -lc 'command -v rustup >/dev/null 2>&1 || (curl -sSfL https://sh.rustup.rs | sh -s -- -y)' + +4) Clone + build (pin do tagu) + AGAVE_SRC_DIR="/var/lib/solana/src/agave-${AGAVE_VERSION_TAG}" + + sudo -u solana -H bash -lc " + set -euo pipefail + export PATH=/var/lib/solana/.cargo/bin:\$PATH + rm -rf \"${AGAVE_SRC_DIR}\" + git clone --depth 1 --branch \"${AGAVE_VERSION_TAG}\" https://github.com/anza-xyz/agave.git \"${AGAVE_SRC_DIR}\" + cd \"${AGAVE_SRC_DIR}\" + + # Agave ma wrapper `./cargo`, ktory bierze pinned toolchain z repo. + ./cargo build --release -p agave-validator + " + +5) Install do /opt/solana/bin + sudo install -o root -g root -m 0755 \ + "${AGAVE_SRC_DIR}/target/release/agave-validator" \ + /opt/solana/bin/agave-validator + + /opt/solana/bin/agave-validator --version + +6) Uwagi (operacyjne) +- Jesli budujesz pluginy (Geyser), trzymaj je na tym samym pinned releasie i najlepiej w tej samej "epoce" API. +- Po update do nowego releasu: buduj validator + pluginy ponownie i restartuj systemd. + diff --git a/doc/step-002g-mpabi-runbook-agave-rpc-geyser-postgres.txt b/doc/step-002g-mpabi-runbook-agave-rpc-geyser-postgres.txt new file mode 100644 index 0000000..a2fb03d --- /dev/null +++ b/doc/step-002g-mpabi-runbook-agave-rpc-geyser-postgres.txt @@ -0,0 +1,264 @@ +Runbook (mpabi): Agave RPC (mainnet, private) + Geyser plugin -> Postgres + +Cel: +- Na mpabi odpalic prywatny Agave RPC (non-voting) po WireGuard (wg0). +- Zbudowac Agave ze zrodel (pinned release). +- (Po starcie) dodac Geyser plugin zapisujacy do PostgreSQL. + +Skrot (kolejnosc): +1) Preconditions: WG + UFW (SSH tylko po wg0). +2) Storage: SOLACCT->/var/lib/solana/accounts, SOLLEDG->/var/lib/solana/ledger (+ decyzja: wipe czy kontynuacja). +3) Pakiety + sysctl/limits. +4) /opt/solana/bin: Anza tools (solana-keygen itd.). +5) Build Agave ze zrodel (pin tag) + install do /opt/solana/bin/agave-validator. +6) Identity (0600). +7) Genesis + snapshot (mainnet). +8) Systemd: agave-validator (User=solana) + RPC smoke test po WG. +9) Geyser plugin -> Postgres + dopiecie do systemd + weryfikacja. + +Konwencja: +- Komendy uruchamiasz jako user: `user` (z sudo). +- Validator dziala jako uzytkownik systemowy: `solana`. +- Biny instalujemy do /opt/solana/bin (root-owned, stabilne sciezki). +- Dane runtime: + - ledger: /var/lib/solana/ledger (SOLLEDG = /dev/nvme1n1p1) + - accounts: /var/lib/solana/accounts (SOLACCT = /dev/nvme0n1p1) + +Parametry hosta (mpabi): +- Public iface: enp6s0, public IP: 149.50.116.219 +- WireGuard iface: wg0, WG IP: 10.66.66.1 +- RPC: 8899, WS: 8900 +- Cluster inbound UDP: 8000-8020 (na public) + +===================== +0) Preconditions +===================== +1) WireGuard up: + ip -4 a show wg0 + wg show + +2) SSH powinno byc tylko po wg0 (defense-in-depth): + sudo ufw status verbose + +3) Upewnij sie, ze masz sudo do operacji operatorskich (systemctl/journalctl/ufw). + +===================== +1) Storage: mount SOLACCT/SOLLEDG +===================== +UWAGA: ten wariant NIE formatuje dyskow (bez kasowania), tylko montuje istniejace XFS. + +UUIDs (wg lsblk -f): +- SOLACCT: 055bf4e7-00f0-45a0-a995-2413b14428c4 (/dev/nvme0n1p1) +- SOLLEDG: 6ac7a8c6-efc7-4803-a3dc-a66ea2ef0125 (/dev/nvme1n1p1) + +1) (Opcjonalnie) obejrzyj co zajmuje SOLLEDG (zanim podepniesz pod /var/lib/solana/ledger): + sudo mkdir -p /mnt/solledg + sudo mount /dev/nvme1n1p1 /mnt/solledg + sudo du -sh /mnt/solledg/* 2>/dev/null | sort -h | tail + sudo umount /mnt/solledg + +2) Utworz usera solana + mountpointy: + sudo getent group solana >/dev/null || sudo groupadd --system solana + sudo id -u solana >/dev/null 2>&1 || sudo useradd --system --gid solana \ + --home-dir /var/lib/solana --create-home --shell /bin/bash solana + + sudo install -d -o solana -g solana -m 0750 /var/lib/solana/accounts /var/lib/solana/ledger + +3) Dodaj wpisy do /etc/fstab (sprawdz czy nie ma juz duplikatow): + grep -nE '(/var/lib/solana/(accounts|ledger))' /etc/fstab || true + + UUID_ACCTS="055bf4e7-00f0-45a0-a995-2413b14428c4" + UUID_LEDGER="6ac7a8c6-efc7-4803-a3dc-a66ea2ef0125" + + echo "UUID=$UUID_ACCTS /var/lib/solana/accounts xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null + echo "UUID=$UUID_LEDGER /var/lib/solana/ledger xfs noatime,nodiratime 0 2" | sudo tee -a /etc/fstab >/dev/null + + sudo mount -a + sudo systemctl daemon-reload + +4) Permissions (krytyczne): + sudo chown solana:solana /var/lib/solana/accounts /var/lib/solana/ledger + sudo chmod 750 /var/lib/solana/accounts /var/lib/solana/ledger + +5) Verify: + df -hT /var/lib/solana/accounts /var/lib/solana/ledger + findmnt /var/lib/solana/accounts + findmnt /var/lib/solana/ledger + stat -c '%U:%G %a %n' /var/lib/solana/accounts /var/lib/solana/ledger + +DECYZJA: co robimy z SOLLEDG (63% used)? +- Opcja A: zostawiamy (jesli to stary ledger Solany i chcesz kontynuowac). +- Opcja B: czyscimy i robimy sync od nowa (destrukcyjne, rekomendowane dla powtarzalnosci): + sudo systemctl stop agave-validator 2>/dev/null || true + sudo -u solana -H bash -lc ' + cd /var/lib/solana/ledger + rm -rf rocksdb snapshots accounts_index accounts_hash_cache admin.rpc ledger.lock + ' + +===================== +2) Pakiety + sysctl/limits +===================== +1) Pakiety: + sudo apt-get update + sudo apt-get install -y \ + chrony curl jq git ca-certificates ripgrep \ + smartmontools nvme-cli \ + build-essential pkg-config libssl-dev \ + clang llvm-dev libclang-dev \ + cmake protobuf-compiler libudev-dev zlib1g-dev + +2) Sysctl: + sudo tee /etc/sysctl.d/90-agave.conf >/dev/null <<'EOF' +fs.file-max = 2000000 +vm.max_map_count = 1000000 +net.core.somaxconn = 65535 +net.core.netdev_max_backlog = 250000 +net.core.rmem_max = 134217728 +net.core.wmem_max = 134217728 +EOF + sudo sysctl --system + +3) ulimit: + sudo tee /etc/security/limits.d/90-solana.conf >/dev/null <<'EOF' +* soft nofile 1000000 +* hard nofile 1000000 +EOF + +===================== +3) Firewall (UFW) dla prywatnego RPC +===================== +Docelowo: +- SSH 22/tcp: tylko wg0 +- RPC 8899/tcp, WS 8900/tcp: tylko wg0 (dodatkowo bind na 10.66.66.1) +- WireGuard: 51820/udp (public) +- Cluster sync: 8000-8020/udp (public) + +Komendy (jesli jeszcze nie ustawione): + sudo ufw default deny incoming + sudo ufw default allow outgoing + sudo ufw allow 51820/udp + + sudo ufw allow in on wg0 to any port 22 proto tcp + sudo ufw deny in on enp6s0 to any port 22 proto tcp + + sudo ufw allow in on wg0 to any port 8899 proto tcp + sudo ufw allow in on wg0 to any port 8900 proto tcp + sudo ufw deny in on enp6s0 to any port 8899 proto tcp + sudo ufw deny in on enp6s0 to any port 8900 proto tcp + + sudo ufw allow in on enp6s0 to any port 8000:8020 proto udp + + sudo ufw enable + sudo ufw status verbose + +===================== +4) Instalacja narzedzi Solana/Anza do /opt/solana/bin +===================== +1) Installer (jako solana): + sudo install -d -o root -g root -m 0755 /opt/solana/bin + sudo -u solana -H bash -lc 'sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"' + +2) Skopiuj biny do /opt/solana/bin: + sudo cp -a /var/lib/solana/.local/share/solana/install/active_release/bin/. /opt/solana/bin/ + sudo find /opt/solana/bin -maxdepth 1 -type f -exec chmod 0755 {} \; + +3) Verify: + /opt/solana/bin/solana --version || true + /opt/solana/bin/solana-keygen --version + +===================== +5) Build + install agave-validator (pinned latest stable) +===================== +Patrz: +- trade-iac/doc/step-002f-agave-build-from-source-latest.txt + +Skrót: +1) Wybierz TAG (np. v3.0.x) i zbuduj jako solana do /var/lib/solana/src/ +2) Zainstaluj binarke do /opt/solana/bin/agave-validator +3) Verify: + /opt/solana/bin/agave-validator --version + +===================== +6) Identity +===================== +1) Utworz raz: + if [ ! -f /var/lib/solana/identity.json ]; then + sudo -u solana -H /opt/solana/bin/solana-keygen new --no-passphrase -o /var/lib/solana/identity.json + sudo chown solana:solana /var/lib/solana/identity.json + sudo chmod 0600 /var/lib/solana/identity.json + fi + +2) Zapisz pubkey do notatek: + sudo -u solana -H /opt/solana/bin/solana-keygen pubkey /var/lib/solana/identity.json + +===================== +7) Genesis + snapshot (mainnet) +===================== +1) Genesis: + patrz: trade-iac/doc/step-002c-genesis-download-mainnet.txt + +2) Snapshot (wymagany na mainnet): + patrz: trade-iac/doc/step-002d-snapshot-download-mainnet.txt + +===================== +8) Systemd: agave-validator (RPC-only) +===================== +Unit template: +- trade-iac/doc/step-002b-agave-validator-systemd.txt + +Wazne: +- `User=solana` +- `--rpc-bind-address 10.66.66.1` +- `--private-rpc` +- nie uzywaj `\\` w ExecStart (tylko pojedynczy `\` na koncu linii) + +Start/verify: + sudo systemctl daemon-reload + sudo systemctl enable --now agave-validator + systemctl is-active agave-validator + sudo journalctl -u agave-validator -n 120 --no-pager + +RPC smoke test (po WG): + curl -sS -H 'content-type: application/json' \ + --data '{"jsonrpc":"2.0","id":1,"method":"getVersion"}' \ + http://10.66.66.1:8899 | jq . + +Manual run (exports + komenda w plikach na mpabi): + # Zawiera "solana export" (PATH + SOLANA_RPC_URL) i helper `agave_run()`: + # - /etc/solana/agave-env.sh + # - /etc/solana/agave-validator.args + sudo -u solana -H bash -lc 'source /etc/solana/agave-env.sh; agave_run' + +===================== +9) Geyser plugin -> PostgreSQL +===================== +Krok po kroku: +- trade-iac/doc/step-003-geyser-plugin-postgres.txt + +Skrót: +1) Postgres: + sudo apt-get install -y postgresql + sudo systemctl enable --now postgresql + +2) DB/user: + sudo -u postgres psql -v ON_ERROR_STOP=1 <<'SQL' + DO $$ + BEGIN + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'geyser') THEN + CREATE ROLE geyser LOGIN PASSWORD 'CHANGE_ME'; + END IF; + END $$; + CREATE DATABASE geyser OWNER geyser; + SQL + +3) Build plugin (.so) i instaluj do /opt/solana/plugins/ +4) Skopiuj example JSON config do /etc/solana/geyser-postgres.json, ustaw DSN, selektory. +5) Dopisz do unit ExecStart: + --geyser-plugin-config /etc/solana/geyser-postgres.json + i zrestartuj: + sudo systemctl daemon-reload + sudo systemctl restart agave-validator + +Verify: + sudo journalctl -u agave-validator -n 200 --no-pager | rg -i 'geyser|plugin|postgres' || true + sudo -u postgres psql -d geyser -c '\\dt' | head diff --git a/doc/step-003-geyser-plugin-postgres.txt b/doc/step-003-geyser-plugin-postgres.txt new file mode 100644 index 0000000..238b833 --- /dev/null +++ b/doc/step-003-geyser-plugin-postgres.txt @@ -0,0 +1,122 @@ +Step 003: Geyser plugin -> PostgreSQL (Agave) na prywatnym RPC node + +Cel: +- Wlaczyc Geyser plugin zapisujacy eventy do Postgresa. +- Na poczatek: dzialajace end-to-end (plugin laduje sie w validatorze + dane wpadaja do DB). + +Wazne ryzyka: +- Pisanie wszystkiego do Postgresa na mainnet generuje OGROMNY write load. + Jezeli DB bedzie na tym samym hoście co validator, latwo o IO contention i spadek performance sync. +- Rekomendacja: startuj od selektorow (filtrow), np. tylko programy ktore bot potrzebuje. + +0) Preconditions +- Agave dziala pod systemd: + - doc/step-002b-agave-validator-systemd.txt +- Masz pinned Agave release (tag) i go nie zmieniasz "w locie": + - doc/step-002f-agave-build-from-source-latest.txt + +1) Postgres (lokalnie, minimalny setup) + sudo apt-get update + sudo apt-get install -y postgresql postgresql-contrib + sudo systemctl enable --now postgresql + + # DB + user (dostosuj haslo; nie commituj do repo) + sudo -u postgres psql -v ON_ERROR_STOP=1 <<'SQL' + DO $$ + BEGIN + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'geyser') THEN + CREATE ROLE geyser LOGIN PASSWORD 'CHANGE_ME'; + END IF; + END $$; + + CREATE DATABASE geyser OWNER geyser; + SQL + +2) Build plugin ze zrodel (Anza Agave plugin Postgres) + # Repo: + # https://github.com/anza-xyz/agave-geyser-plugin-postgres + # + # Uwaga: plugin i validator musza byc kompatybilne wersjami interfejsu. + # Najbezpieczniej: build pluginu po update Agave i test "plugin loaded". + # + # Opcjonalnie: pin plugin do tagu/commit (np. pod ten sam release co Agave). + # PLUGIN_REF="main" # albo tag/commit + + sudo install -d -o root -g root -m 0755 /opt/solana/plugins + sudo install -d -o solana -g solana -m 0750 /var/lib/solana/src + + PLUGIN_SRC_DIR="/var/lib/solana/src/agave-geyser-plugin-postgres" + + sudo -u solana -H bash -lc " + set -euo pipefail + export PATH=/var/lib/solana/.cargo/bin:\$PATH + rm -rf \"${PLUGIN_SRC_DIR}\" + git clone https://github.com/anza-xyz/agave-geyser-plugin-postgres.git \"${PLUGIN_SRC_DIR}\" + cd \"${PLUGIN_SRC_DIR}\" + if [ \"${PLUGIN_REF:-main}\" != \"main\" ]; then git checkout \"${PLUGIN_REF}\"; fi + cargo build --release + " + + # Typowa nazwa .so (sprawdz `ls target/release/*.so`): + sudo cp -a "${PLUGIN_SRC_DIR}"/target/release/*.so /opt/solana/plugins/ + sudo chmod 0755 /opt/solana/plugins/*.so + +3) Schema w Postgres + # Plugin repo ma SQL do stworzenia schematu. Najpierw znajdz plik: + sudo -u solana -H bash -lc ' + cd /var/lib/solana/src/agave-geyser-plugin-postgres + find . -maxdepth 3 -type f -iname \"*schema*.sql\" -o -type f -iname \"create*.sql\" | sort + ' + + # Potem wykonaj jako postgres na DB geyser (podmien sciezke na znaleziony plik): + # sudo -u postgres psql -d geyser -f /var/lib/solana/src/agave-geyser-plugin-postgres/scripts/create_schema.sql + +4) Konfig pluginu (JSON) + # Najbezpieczniej: skopiuj example config z repo pluginu i zmien tylko: + # - sciezke do .so + # - connection string + # - selektory (na poczatek mozesz dac \"*\" tylko na smoke test, potem zawęz) + # + # Znajdz przyklad w repo: + sudo -u solana -H bash -lc ' + cd /var/lib/solana/src/agave-geyser-plugin-postgres + find . -maxdepth 4 -type f -iname \"*.json\" | sort + rg -n \"connection_str|libpath|accounts_selector|transaction_selector|selector\" -S . || true + ' + + sudo install -d -o root -g root -m 0755 /etc/solana + + # Start od skopiowania example (podmien sciezke jesli repo ma inna nazwe pliku): + # sudo cp -a /var/lib/solana/src/agave-geyser-plugin-postgres/config.json /etc/solana/geyser-postgres.json + + # Uprawnienia: config zawiera haslo, ale validator (User=solana) musi go czytac. + if [ -f /etc/solana/geyser-postgres.json ]; then + sudo chown root:solana /etc/solana/geyser-postgres.json + sudo chmod 0640 /etc/solana/geyser-postgres.json + fi + +5) Wlaczenie pluginu w agave-validator (systemd) + # Sprawdz, jak na Twojej wersji nazywa sie flaga: + /opt/solana/bin/agave-validator --help | rg -n \"geyser|plugin\" || true + + # Docelowo (w unit file) dopisz: + # --geyser-plugin-config /etc/solana/geyser-postgres.json + # + # Nastepnie: + sudo systemctl daemon-reload + sudo systemctl restart agave-validator + +6) Weryfikacja + sudo journalctl -u agave-validator -n 200 --no-pager | rg -i \"geyser|plugin|postgres\" || true + + # Czy w DB pojawiaja sie tabele (zalezy od schema.sql): + sudo -u postgres psql -d geyser -c \"\\dt\" | head + + # Czy rosną inserty (przyklad - dostosuj nazwy tabel): + # sudo -u postgres psql -d geyser -c 'select count(*) from account;' + +7) Performance (minimum sanity) +- Jezeli validator zacznie znacząco odstawać, zacznij od: + - zawężenia selektorow (unikaj \"*\" po smoke tescie) + - zmniejszenia batch/threads + - przeniesienia DB na osobny host (lub przynajmniej na osobny NVMe)