From a28cbdf9120c38e45ef207d99727c3dcaed83de8 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Mon, 7 Sep 2026 11:33:57 +0200 Subject: [PATCH 1/2] docs(readme): use a markdown link so mint can parse the README Co-Authored-By: Claude Fable 5.1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d03d7239b..3d8d34050 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ live in [`docs.json`](./docs.json). ## Source & accuracy Content is rebuilt from first principles based on the Livepeer v2 docs at -. Network values (inflation, unbonding period, active-set size, +[docs.livepeer.org](https://docs.livepeer.org). Network values (inflation, unbonding period, active-set size, contract addresses) are governance-controlled and change over time — the Reference pages carry a "last verified" date from on-chain reads, and you can always re-verify against the [Livepeer Explorer](https://explorer.livepeer.org) and on-chain state. Run `npm run check` to From fe2016cc1982489ae5c042d54e8c9e45c5170caf Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Mon, 7 Sep 2026 11:33:58 +0200 Subject: [PATCH 2/2] docs(orchestrator): harden wallet setup with delegated reward calling Activation now recommends a hardware wallet or Safe, a throwaway node wallet with -ethOrchAddr, and a LIP-118 reward caller. Adds the related flags to the CLI reference. Co-Authored-By: Claude Fable 5.1 --- network/guides/orchestrator-activate.mdx | 124 +++++++++++++++++++---- network/guides/orchestrator-monitor.mdx | 7 +- network/reference/cli-flags.mdx | 9 +- 3 files changed, 116 insertions(+), 24 deletions(-) diff --git a/network/guides/orchestrator-activate.mdx b/network/guides/orchestrator-activate.mdx index 06e543243..015dcbd7c 100644 --- a/network/guides/orchestrator-activate.mdx +++ b/network/guides/orchestrator-activate.mdx @@ -14,9 +14,10 @@ fund the wallet, stake LPT, activate on-chain, and confirm reward calling. ## 1. Point at a reliable Arbitrum RPC -`-ethUrl` connects the node to Arbitrum One. Free tiers from **Alchemy** (300M compute units/mo) or -**Infura** (100K req/day) work for most operators. Public endpoints like `arb1.arbitrum.io/rpc` are -for testing only — a dropped connection during round initialization can forfeit that round's reward. +`-ethUrl` connects the node to Arbitrum One. The community-run [LiveInfra SPE](https://liveinfraspe.com/) +endpoint is free for verified orchestrators. Free tiers from **Alchemy** (300M compute units/mo) or +**Infura** (100K req/day) also work for most operators. Public endpoints like `arb1.arbitrum.io/rpc` +are for testing only — a dropped connection during round initialization can forfeit that round's reward. Verify the endpoint is actually Arbitrum One: @@ -27,18 +28,21 @@ curl -s -X POST -H "Content-Type: application/json" \ # Expect "result":"0xa4b1" (42161). "0x1" means you're on Ethereum L1 — switch endpoints. ``` -## 2. Identify and back up the wallet +## 2. Choose your orchestrator wallet -On first start, `go-livepeer` creates an account and prints the address in the logs. Record it — this -address receives ETH fees and holds your staked LPT. +The orchestrator wallet holds your staked LPT and receives fees. **It never needs to run on the +node** — you only use it to update orchestrator settings, move funds, and vote. Use a hardware wallet +or a [Safe](https://safe.global) multisig. + +Alternatively, `go-livepeer` creates an account on first start and prints the address in the logs: ```bash docker compose logs 2>&1 | grep -i "account\|address" ``` - The private key lives at `~/.lpData/arbitrum-one-mainnet/keystore`. **Back it up offline now.** - Losing the keystore means permanent loss of the account and all bonded LPT. + If you use this keystore, its private key lives at `~/.lpData/arbitrum-one-mainnet/keystore`. + **Back it up offline now.** Losing it means permanent loss of the account and all bonded LPT. ## 3. Fund the wallet with ETH on Arbitrum @@ -52,14 +56,21 @@ withdrawing from an exchange that supports Arbitrum, or bridging from L1 at LPT bonded to your address is what puts you in the active set (top orchestrators by total stake). Check the current threshold on the [Explorer](https://explorer.livepeer.org/orchestrators) before -deciding how much to acquire. Then open the CLI and bond: +deciding how much to acquire. The orchestrator itself only needs a 1 LPT self-bond. **Stake the rest by +delegating from a hardware wallet** rather than bonding it all from a keystore. Self-bond on the +[Explorer](https://explorer.livepeer.org), or in the CLI if the keystore is on the node: ```bash docker exec -it livepeer-orchestrator livepeer_cli ``` -Select the bond/stake option and enter an amount. Two transactions are submitted — `approve`, then -`bond`. Wait for both to confirm. + + Transactions in `livepeer_cli` require the node to be started with `-enableCliTxRoutes`. Add it for + these steps only and remove it afterwards. Keep `-cliAddr` on `127.0.0.1:7935` and never expose + port 7935 to the internet. + + +Either way, two transactions are submitted — `approve`, then `bond`. Wait for both to confirm. ## 5. Activate on-chain @@ -71,6 +82,11 @@ In `livepeer_cli`, select **"Invoke multi-step 'become an orchestrator'"** and s | Fee Cut | `95` | % of ETH fees you keep (95% → delegators get 5%) | | Service address | `YOUR_PUBLIC_IP:8935` | Must match `-serviceAddr` exactly | +Without a keystore on the node, make the same two calls from your wallet: `transcoder` on the +[`BondingManager`](/network/reference/contracts) and `setServiceURI` on the +[`ServiceRegistry`](/network/reference/contracts), or on the +[`AIServiceRegistry`](/network/reference/contracts) if you serve AI. + **The Explorer displays Fee Cut inverted, as "Fee Share."** Set Fee Cut `95` here and your profile will show **Fee Share 5%** — the portion passed to delegators. That's the same setting, not a @@ -85,16 +101,72 @@ In `livepeer_cli`, select **"Invoke multi-step 'become an orchestrator'"** and s See [Economics](/network/explanation/economics) for how these two settings affect both your earnings and your appeal to delegators. -## 6. Confirm reward calling +## 6. Run the node on a throwaway wallet + +The machine doing the work is your exposed surface. **Never run it with the orchestrator key.** Start +the node with a fresh `-dataDir` so it generates a new account, send that address a little ETH for +gas, and point it at your orchestrator: + +| Flag | Value | Purpose | +| --- | --- | --- | +| `-ethAcctAddr` | throwaway address | Signs for the node, redeems tickets, and can be the reward caller (step 7) | +| `-ethOrchAddr` | your orchestrator address | Fees and rewards accrue here | + + + If you activated from a keystore on this machine, finish step 7, then move it to cold storage and + delete it from the node. A compromised machine then yields a near-empty wallet, not your stake. + -`go-livepeer` calls `reward()` automatically each round by default. Make sure it isn't disabled: +## 7. Set up a reward caller + +Delegate reward calling to a separate, low-privilege wallet. It can only call `reward()` — not move +funds, unbond, change settings, or vote — so the orchestrator wallet stays in cold storage +([LIP-118](https://github.com/livepeer/LIPs/blob/master/LIPs/LIP-118.md)). + +**Choose the caller:** + + + + The throwaway wallet from step 6. The node reads the on-chain mapping and calls reward for + `-ethOrchAddr` itself — no extra flags. + + + The wallet of a [livepeer-reward-caller](https://github.com/rickstaa/livepeer-reward-caller) + you run yourself — a single static binary with its own keystore. Start the node with + `-reward=false`. + + + The community [livepeer.bot caller](https://forum.livepeer.org/t/livepeer-bot-put-your-orchestrator-keys-in-cold-storage-a-shared-lip-118-reward-caller-live-on-arbitrum-one/3330), + which calls reward for every orchestrator that authorizes its address. Nothing to run. Start the + node with `-reward=false`. + + + +**Authorize it** from your orchestrator wallet — with [`cast`](https://getfoundry.sh/cast/overview) +against the [`BondingManager`](/network/reference/contracts), or with **"Set reward caller"** in +`livepeer_cli` if the keystore is on the node: + +```bash +cast send 0x35Bcf3c30594191d53231E4FF333E8A770453e40 \ + "setRewardCaller(address)" \ + --rpc-url \ + --keystore +``` + +Set it to `0x0000000000000000000000000000000000000000` to revoke. Arbiscan does not show this method +on the proxy page yet, but it is live on-chain. + +## 8. Confirm reward calling + +After the next round starts (~22h), your orchestrator's page on the +[Explorer](https://explorer.livepeer.org/orchestrators) shows the reward call. With a standalone or +shared caller, its wallet on Arbiscan shows it too. With go-livepeer, the node logs do: ```bash docker compose logs 2>&1 | grep -i reward ``` -The startup command should **not** include `-reward=false`. A missed round forfeits that round's LPT -permanently — there is no catch-up. +A missed round forfeits that round's LPT permanently — there is no catch-up. **Exception for very low stake:** if reward-call gas costs more than the LPT you'd earn, disabling @@ -102,19 +174,29 @@ permanently — there is no catch-up. calls use ~350k–450k gas (cents at typical Arbitrum prices). -## 7. Verify + + A caller that quietly stops looks exactly like one that is working. Send + `/subscribe ` to [@OrchestratorWatcherBot](https://t.me/OrchestratorWatcherBot) + on Telegram for alerts on missed reward calls, and see + [Monitor your orchestrator](/network/guides/orchestrator-monitor). + + +## 9. Verify On [explorer.livepeer.org/orchestrators](https://explorer.livepeer.org/orchestrators), search your -address and confirm **Status**, **Service URI**, **Stake**, **Reward Cut**, and **Fee Cut**. Then -confirm external reachability: +address and confirm **Status**, **Stake**, **Reward Cut**, and **Fee Cut**. The Explorer does not show +the service URI — read it from the [`ServiceRegistry`](/network/reference/contracts), then confirm +external reachability: ```bash +cast call 0xC92d3A360b8f9e083bA64DE15d95Cf8180897431 \ + "getServiceURI(address)(string)" --rpc-url curl -k https://YOUR_PUBLIC_IP:8935/status ``` -If the Service URI is wrong or unreachable, update it in `livepeer_cli` (this costs gas). A bad or -unreachable service address is the most common reason an active node still receives no jobs — see the -[FAQ](/network/reference/faq). +If the service URI is wrong or unreachable, update it in `livepeer_cli` or via `setServiceURI` on the +contract (this costs gas). A bad or unreachable service address is the most common reason an active +node still receives no jobs — see the [FAQ](/network/reference/faq). ## Next diff --git a/network/guides/orchestrator-monitor.mdx b/network/guides/orchestrator-monitor.mdx index febeb53da..8bb812640 100644 --- a/network/guides/orchestrator-monitor.mdx +++ b/network/guides/orchestrator-monitor.mdx @@ -28,6 +28,11 @@ livepeer \ The metrics are served at **`http://localhost:7935/metrics`** — the same port as the go-livepeer CLI; `-monitor` just activates the `/metrics` path on it. + + Port 7935 is the node's private CLI port. Keep `-cliAddr` on loopback and scrape it locally or over + a private network — never expose it to the internet. + + | Flag | What it does | | --- | --- | | `-monitor` | Enables `/metrics`. Required for any Prometheus scraping. | @@ -102,7 +107,7 @@ The metrics you'll actually act on: The single highest-value alert: **a missed `reward()` call.** Miss a round and that round's LPT is gone permanently — there's no catch-up. Alert on it, and keep enough ETH on Arbitrum for gas. See - [Activate on Arbitrum](/network/guides/orchestrator-activate#6-confirm-reward-calling). + [Activate on Arbitrum](/network/guides/orchestrator-activate#8-confirm-reward-calling). ## 4. Monitor the AI runner (if you serve AI) diff --git a/network/reference/cli-flags.mdx b/network/reference/cli-flags.mdx index 079b4e6b7..f9fe69ae8 100644 --- a/network/reference/cli-flags.mdx +++ b/network/reference/cli-flags.mdx @@ -13,7 +13,8 @@ for how to choose values. | --- | --- | --- | | `-network` | `arbitrum-one-mainnet` | Network to join (default `offchain` does not participate) | | `-ethUrl` | RPC URL | Arbitrum One endpoint for on-chain reads/writes | -| `-ethAcctAddr` | ETH address | Orchestrator identity; holds stake, receives fees. Omit to create a new account | +| `-ethAcctAddr` | ETH address | Account the node signs with. Omit to create a new account. With `-ethOrchAddr` this can be a throwaway holding only gas | +| `-ethOrchAddr` | ETH address | Registered orchestrator this node works and calls reward for. Fees and rewards accrue here. See [Activate on Arbitrum](/network/guides/orchestrator-activate#6-run-the-node-on-a-throwaway-wallet) | | `-serviceAddr` | `ip:port` | Public address gateways use to reach the node | | `-dataDir` | path | Where keystore and node data are stored (default `~/.lpData`) | @@ -58,6 +59,8 @@ for how to choose values. | Flag | Value | Purpose | | --- | --- | --- | | `-reward` | bool | Call `reward()` automatically each round (default `true`) | +| `-cliAddr` | `ip:port` | Where the CLI/metrics server listens (default `127.0.0.1:7935`). Never bind it to a public interface | +| `-enableCliTxRoutes` | bool | Enable transaction, signing, and gas-control routes on the CLI port (default `false`). Turn on only for one-time setup, then remove | | `-v` | level | Log verbosity (`6` is useful while setting up) | @@ -70,7 +73,9 @@ for how to choose values. `livepeer_cli` is an interactive tool that connects to a running node for one-off on-chain actions — activating as an orchestrator, staking/bonding LPT, updating price, updating the service URI, and -viewing node status. It does **not** need to stay running; only the `livepeer` daemon does. +viewing node status. It does **not** need to stay running; only the `livepeer` daemon does. Read-only +status works out of the box. Any action that sends a transaction requires the node to run with +`-enableCliTxRoutes`. ```bash # Against a Docker node: