diff --git a/.gitbook/assets/node-ecosystem-eligibility.png b/.gitbook/assets/node-ecosystem-eligibility.png new file mode 100644 index 0000000..b6cbde0 Binary files /dev/null and b/.gitbook/assets/node-ecosystem-eligibility.png differ diff --git a/.gitbook/assets/node-ecosystem-join.png b/.gitbook/assets/node-ecosystem-join.png new file mode 100644 index 0000000..976b11b Binary files /dev/null and b/.gitbook/assets/node-ecosystem-join.png differ diff --git a/.gitbook/assets/node-ecosystem-my-nodes-dashboard.png b/.gitbook/assets/node-ecosystem-my-nodes-dashboard.png new file mode 100644 index 0000000..27e5bda Binary files /dev/null and b/.gitbook/assets/node-ecosystem-my-nodes-dashboard.png differ diff --git a/.gitbook/assets/node-ecosystem-my-nodes-no-nft.png b/.gitbook/assets/node-ecosystem-my-nodes-no-nft.png new file mode 100644 index 0000000..93f5d4a Binary files /dev/null and b/.gitbook/assets/node-ecosystem-my-nodes-no-nft.png differ diff --git a/.gitbook/assets/node-ecosystem-my-nodes-warmup.png b/.gitbook/assets/node-ecosystem-my-nodes-warmup.png new file mode 100644 index 0000000..d6047b8 Binary files /dev/null and b/.gitbook/assets/node-ecosystem-my-nodes-warmup.png differ diff --git a/.gitbook/assets/node-ecosystem-nodes-table.png b/.gitbook/assets/node-ecosystem-nodes-table.png new file mode 100644 index 0000000..7949551 Binary files /dev/null and b/.gitbook/assets/node-ecosystem-nodes-table.png differ diff --git a/.gitbook/assets/node-ecosystem-overview-hero.png b/.gitbook/assets/node-ecosystem-overview-hero.png new file mode 100644 index 0000000..de432e3 Binary files /dev/null and b/.gitbook/assets/node-ecosystem-overview-hero.png differ diff --git a/.gitbook/assets/node-ecosystem-setup-1.png b/.gitbook/assets/node-ecosystem-setup-1.png new file mode 100644 index 0000000..94faf2e Binary files /dev/null and b/.gitbook/assets/node-ecosystem-setup-1.png differ diff --git a/.gitbook/assets/node-ecosystem-setup-2.png b/.gitbook/assets/node-ecosystem-setup-2.png new file mode 100644 index 0000000..d71b635 Binary files /dev/null and b/.gitbook/assets/node-ecosystem-setup-2.png differ diff --git a/.gitbook/assets/node-ecosystem-setup-3.png b/.gitbook/assets/node-ecosystem-setup-3.png new file mode 100644 index 0000000..f7eb6e4 Binary files /dev/null and b/.gitbook/assets/node-ecosystem-setup-3.png differ diff --git a/.gitbook/assets/node-ecosystem-setup-4.png b/.gitbook/assets/node-ecosystem-setup-4.png new file mode 100644 index 0000000..3ed6dee Binary files /dev/null and b/.gitbook/assets/node-ecosystem-setup-4.png differ diff --git a/.gitbook/assets/node-ecosystem-setup-5.png b/.gitbook/assets/node-ecosystem-setup-5.png new file mode 100644 index 0000000..f52aab9 Binary files /dev/null and b/.gitbook/assets/node-ecosystem-setup-5.png differ diff --git a/.gitbook/assets/node-ecosystem-setup-6.png b/.gitbook/assets/node-ecosystem-setup-6.png new file mode 100644 index 0000000..7df96a3 Binary files /dev/null and b/.gitbook/assets/node-ecosystem-setup-6.png differ diff --git a/.gitbook/assets/node-ecosystem-setup-7.png b/.gitbook/assets/node-ecosystem-setup-7.png new file mode 100644 index 0000000..7d3b40b Binary files /dev/null and b/.gitbook/assets/node-ecosystem-setup-7.png differ diff --git a/SUMMARY.md b/SUMMARY.md index e41b791..c9f0d67 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -74,6 +74,12 @@ * [COTI Starter Grant](private-messaging/skills/coti-starter-grant.md) * [Running a COTI Node](running-a-coti-node/README.md) * [COTI Node Ecosystem Litepaper](running-a-coti-node/coti-node-ecosystem-litepaper.md) +* [Node Ecosystem](node-ecosystem/README.md) + * [Features](node-ecosystem/features.md) + * [Installation](node-ecosystem/installation.md) + * [UI Guide](node-ecosystem/ui-guide.md) + * [Backend Services](node-ecosystem/backend-services.md) + * [Glossary](node-ecosystem/glossary.md) * [COTI Bridge](coti-bridge/README.md) * [Swap COTI V1 Funds to COTI V2](coti-bridge/swap-coti-v1-funds-to-coti-v2.md) * [Support and Community](support-and-community/README.md) diff --git a/node-ecosystem/README.md b/node-ecosystem/README.md new file mode 100644 index 0000000..3dae5fc --- /dev/null +++ b/node-ecosystem/README.md @@ -0,0 +1,78 @@ +# Node Ecosystem + +The **COTI Node Ecosystem** is the product surface that lets anyone run, monitor, and earn rewards from a COTI full node. It is composed of: + +* a web app that guides operators from zero to a live, reward-eligible node (see [Networks](#networks) below for the URLs), +* an automated installer that stands up a COTI full node on Ubuntu 24.04 LTS in a single command, +* a set of backend services that discover peers, mint node NFTs, monitor uptime, and distribute rewards each epoch. + +This section documents the product — what it does, how to install a node through it, how its UI is organized, and the terminology you will encounter along the way. + +## Networks + +The ecosystem runs on two networks. All guidance in this section applies to both unless noted; look up the right URL or value in the table below. + +| | **Testnet** | **Mainnet** | +|---|---|---| +| Web app | [dev.nodes.coti.io](https://dev.nodes.coti.io) | [nodes.coti.io](https://nodes.coti.io) | +| Status page (public, hot nodes) | [testnet.uptime.coti.io](https://testnet.uptime.coti.io) | [uptime.coti.io](https://uptime.coti.io) | +| Recommended node disk space | ≥ 100 GB | ≥ 700 GB | +| Installer host | `fullnode.testnet.coti.io` | `fullnode.mainnet.coti.io` | + +The **status page** is the public [Better Stack](https://betterstack.com/) dashboard where every hot node's monitor is visible. It is the fastest way to eyeball the current health of the whole fleet. + +{% hint style="info" %} +If you are looking for the protocol-level **Running a COTI Node** guide (hardware specs, manual Docker flow, ports, FAQ), see [**Running a COTI Node**](../running-a-coti-node/README.md). The current section focuses on the managed, UI-driven experience and the ecosystem that surrounds it. +{% endhint %} + +## What the COTI Node Ecosystem gives you + +* **One-command install** of a COTI full node on a certified OS (Ubuntu 24.04 LTS) with HTTPS and a proxy already configured. +* **Live visibility** into the node fleet — Who is online, which nodes are hot, how many earned rewards this epoch. +* **Per-operator dashboard** for your own node(s): thermal state, uptime, latency, rewards history, eligibility. +* **Automatic monitoring registration** in Better Stack once your node is recognized by the network. +* **Rewards distribution** every epoch to operators who meet the eligibility rules (holdings + uptime). + +## High-level architecture + +```mermaid +flowchart LR + Operator([Node operator]) + UI["COTI Nodes web app"] + FullNode["COTI full node
(operator server)"] + PDS["Peer Discovery"] + NFT["NFT service"] + BSI["Better Stack integration"] + NHM["Node Health Monitor"] + NRS["Node Rewards"] + BetterStack[(Better Stack)] + Chain[(COTI network)] + + Operator -->|guided setup| UI + UI -->|one-liner installer| FullNode + FullNode -->|admin_peers, eth_blockNumber| PDS + PDS -->|"hot event"| NFT + NFT -->|mint Soulbound NFT| Chain + NFT --> BSI + BSI -->|register monitor via FQDN| BetterStack + BetterStack -->|probe RPC over HTTPS| NHM + NHM -->|health check| FullNode + NRS -->|read uptime + holdings| BetterStack + NRS -->|distribute rewards per epoch| Chain + UI -->|read stats + per-node data| PDS + UI --> NFT + UI --> BSI + UI --> NRS +``` + +{% hint style="warning" %} +**A valid DNS (FQDN) is required to earn rewards.** The ecosystem measures your node's uptime by reaching its JSON-RPC endpoint through the domain name you configure. A node without a reachable DNS can still sync the chain, but it will **not** be credited with uptime and therefore will **not** receive rewards. See [installation.md](installation.md) for DNS prerequisites. +{% endhint %} + +## Where to go next + +* **[Features](features.md)** — everything the product does, end-to-end. +* **[Installation](installation.md)** — what the automated installer does on your server, and the DNS/server requirements. +* **[UI guide](ui-guide.md)** — a page-by-page tour of the web app, with focus on the spin-up flow and the warm-up period. +* **[Backend services](backend-services.md)** — the five services behind the ecosystem, described from an operator's perspective. +* **[Glossary](glossary.md)** — thermal states, NFT states, warm-up windows, eligibility, and other terms you will see in the UI. diff --git a/node-ecosystem/backend-services.md b/node-ecosystem/backend-services.md new file mode 100644 index 0000000..b98cfa1 --- /dev/null +++ b/node-ecosystem/backend-services.md @@ -0,0 +1,124 @@ +# Backend services + +The ecosystem is powered by five cooperating backend services. Operators do not interact with them directly — the web app (see [Networks](README.md#networks) for URLs) is the only interface. This page describes each service from the operator's perspective: **what it does for you** and **what its outputs look like in the UI**. + +```mermaid +flowchart LR + YourNode["Your full node
(RPC over FQDN)"] + PDS["Peer Discovery"] + NFT["NFT Service"] + BSI["Better Stack integration"] + NHM["Node Health Monitor"] + NRS["Node Rewards"] + Chain[(COTI network)] + BetterStack[(Better Stack)] + + YourNode -->|"admin_peers"| PDS + PDS -->|"node becomes hot"| NFT + NFT -->|"mint Soulbound NFT"| Chain + NFT -->|"hand off monitoring"| BSI + BSI -->|"register FQDN"| BetterStack + BetterStack -->|"probe RPC"| NHM + NHM -->|"health check"| YourNode + NRS -->|"record epoch rewards"| Chain + BetterStack --> NRS +``` + +## Peer Discovery Service + +**What it does for you** + +Peer Discovery is the service that first *sees* your node. It repeatedly calls `admin_peers` on a set of reference nodes and records which peers are currently connected. As soon as your node shows up in those responses, it is considered **online** in the ecosystem. + +Peer Discovery is also responsible for the **thermal state machine**: + +* While your node is newly online, it is **cold** with the NFT not yet minted — it is **warming up**. +* Once it has been continuously present for enough time (`HOT_THRESHOLD_HOURS` out of a rolling `HOT_WINDOW_HOURS` window), it transitions to **hot** and triggers NFT minting. +* If a hot node goes offline long enough (`COLD_THRESHOLD_HOURS` out of a `COLD_WINDOW_HOURS` window), it **cools down** back to cold and must warm up again. + +**Where it shows up in the UI** + +* The home-page **Live node heartbeats** counter. +* The **Nodes** table's **Status** column (active / syncing / offline). +* The **Warmup In Progress** card on `/my-nodes` during the warm-up period. +* The **Thermal** state badge (warming up / hot / cooling down / cold) on internal views. + +## NFT Service + +**What it does for you** + +The NFT service receives the "this node is hot" event from Peer Discovery and mints a **Soulbound Node NFT** to the operator's wallet. The NFT is the on-chain proof that the node exists, who owns it, and what its name and image are. + +Because the NFT is soulbound, it cannot be transferred — it is bound to the wallet that set up the node. If an operator regenerates keys, a new NFT is minted to the new wallet; the old one is not reused. + +**Where it shows up in the UI** + +* The node name and avatar shown everywhere the node appears (dashboard, nodes table, node-details modal). +* The **Edit Node** flow (`/edit-node`) where you rename your node — the name is stored on the NFT. +* The "No Node Detected" / "Warmup Complete" states on `/my-nodes`, which depend on whether the NFT exists for the connected wallet. + +## Better Stack Integration Service + +**What it does for you** + +Once your node has an NFT, the Better Stack integration service automatically registers your node's `https:///rpc` URL with [Better Stack](https://betterstack.com/) as a monitored endpoint. From that point on, Better Stack polls your node on a regular cadence and records the results. + +The operator does not configure or pay for Better Stack — the ecosystem manages the monitor centrally. + +**Where it shows up in the UI** + +* The **all-time uptime percentage** displayed for your node in the dashboard and nodes table. +* A public **status page** that aggregates every hot node's monitor state (up / down). The URL is listed in [Networks](README.md#networks). + +{% hint style="info" %} +Because monitoring happens over HTTPS against your FQDN, a node without a valid DNS cannot be monitored — see [installation.md](installation.md) and the [Glossary](glossary.md) FQDN entry. +{% endhint %} + +## Node Health Monitor + +**What it does for you** + +The Node Health Monitor is the health-check target that Better Stack calls. When Better Stack asks "is this node healthy?", the Node Health Monitor runs a **multi-signal health check** against the node's JSON-RPC through its FQDN and returns a single **healthy / failing** verdict. + +The check is designed so that simply answering RPC calls is **not** sufficient — the service confirms that the node is actually operating, not just reachable. Only healthy results accrue uptime; failures are recorded with a reason so operators can diagnose issues. + +**Where it shows up in the UI** + +* As the underlying cause of your **uptime percentage** each epoch. +* As the difference between "your node is reachable" and "your node is actually operating" — a reachable-but-unhealthy node does not count as up. + +## Node Rewards Service + +**What it does for you** + +At the end of each **103-hour epoch**, the rewards service: + +1. Snapshots each node operator's USDC and COTI holdings. +2. Reads each node's uptime for the epoch from the monitoring platform. +3. Applies the eligibility rules: **uptime is mandatory**, and the operator must meet **at least one** of the USDC-holdings threshold **or** the COTI-holdings threshold (with whitelist overrides for specific operators). +4. Allocates each eligible node its share of the epoch's reward pool in the on-chain **rewards smart contract**. +5. Records the per-epoch result: earned amount, snapshot values, uptime %, eligibility. + +Rewards are **not** pushed to the operator's wallet automatically. Once the contract is credited, the operator claims the accrued balance via the **Claim Now** button on the **My Node** dashboard, or by calling the rewards smart contract directly from any wallet they control. + +**Where it shows up in the UI** + +* The home-page **Reward-eligible nodes (last epoch)** and **COTI dropped (last epoch)** cards. +* The **Total COTI earned** card (cumulative). +* The **Total Rewards** column in the nodes table. +* The **Total Earned** and **Claim Now** controls in the My Node node-identity card. +* The **Rewards History** table on `/my-nodes`, including USDC, COTI, earned, uptime %, and Eligible / Ineligible per epoch. + +## How they work together + +For a newly-installed node, the lifecycle is: + +1. **Install finishes** → node comes up at `https:///rpc`. +2. **Peer Discovery** sees the node in `admin_peers` responses and starts tracking presence. +3. **Warm-up period** — the UI shows a progress bar until `HOT_THRESHOLD_HOURS` of presence is reached. +4. **Peer Discovery** declares the node **hot** → **NFT Service** mints the Soulbound NFT. +5. **Better Stack Integration** registers the node's FQDN with **Better Stack**. +6. **Better Stack** starts calling the **Node Health Monitor**, which runs the health check against the node's RPC through the FQDN. +7. At epoch boundaries, **Node Rewards** reads uptime + holdings and credits eligible nodes in the rewards smart contract; the operator claims from the **My Node** dashboard or directly from the contract. + +The operator only ever touches the web app and their own server — the five services coordinate everything in between. diff --git a/node-ecosystem/features.md b/node-ecosystem/features.md new file mode 100644 index 0000000..1b0fdbd --- /dev/null +++ b/node-ecosystem/features.md @@ -0,0 +1,75 @@ +# Features + +The COTI Node Ecosystem packages node operation into a small number of high-level features. Each one is surfaced in the web app (see [Networks](README.md#networks) for the testnet and mainnet URLs) and backed by one or more of the ecosystem services described in [backend-services.md](backend-services.md). + +## 1. Guided installation + +A step-by-step wizard at **`/setup`** takes an operator from a fresh Ubuntu server to a running, HTTPS-fronted COTI full node. + +* Generates (or accepts) a node private key locally — the key never leaves the browser. +* Validates the node's **FQDN** via a live DNS lookup before continuing. +* Produces a single-line installer command, tailored to the node's key and domain, that the operator runs as root on the target server. +* Watches the peer-discovery network and advances automatically once the node is seen by peers. + +See [installation.md](installation.md) for what the installer does on the server, and [ui-guide.md](ui-guide.md) for the wizard walkthrough. + +## 2. Live ecosystem view + +The home page of the web app exposes the current state of the node network: + +* **Live node heartbeats** — a running count of nodes currently observed by peer discovery. +* **Reward-eligible nodes (last epoch)** — how many nodes met the rules in the previous epoch. +* **COTI dropped (last epoch)** — total rewards distributed in the previous epoch. +* **Total COTI earned** — cumulative rewards paid to operators to date. +* **Nodes table** — every node the system knows about, with operator name, total rewards, online status, uptime, and latency. + +This view is read-only and does not require a wallet connection. + +## 3. Per-operator dashboard + +Once an operator connects a wallet that owns a COTI Node NFT, **`/my-nodes`** becomes the per-operator dashboard: + +* Current node status (active / syncing / offline) and thermal state (warming up / hot / cooling down / cold). +* **Warm-up progress bar** for nodes that have just been installed and are not yet hot. +* All-time totals: uptime, rewards, latency. +* Per-epoch rewards history with USDC/COTI snapshots, uptime, earned amount, and eligibility status. +* Edit node flow for renaming the node (the name is stored on the Soulbound NFT). + +## 4. Eligibility checks + +Anyone can preview whether their wallet meets the reward rules before installing a node. For a node to be eligible in a given epoch **both** conditions below must hold: + +* **Uptime (mandatory).** The node's per-epoch uptime must be ≥ the configured percentage. +* **Holdings (either threshold is enough).** The operator's wallet must meet **at least one** of the following: + * **USDC** holdings on COTI network ≥ the configured threshold, **or** + * **COTI** holdings ≥ the configured threshold (custodial and non-custodial wallets both count). + +The **`/eligibility`** page explains the rules in plain language; the home page exposes a quick "Check My Eligibility" button. + +## 5. Automatic uptime monitoring + +Once a node has been continuously seen by peer discovery for long enough to be considered **hot**, the ecosystem: + +1. Mints a Soulbound **Node NFT** to the operator's wallet. +2. Registers the node's RPC URL with **Better Stack** as a monitored endpoint. +3. Runs a multi-signal health check against the node's RPC **through its DNS** to confirm the node is actually operating — simply responding is not enough. +4. Aggregates the resulting uptime per epoch and exposes it in the per-operator dashboard. + +{% hint style="warning" %} +**Rewards require a valid DNS.** The ecosystem only measures uptime by calling the node's RPC through the FQDN the operator supplies during setup. A node without a reachable FQDN cannot be monitored and therefore cannot earn rewards — even if it is fully synced on the network. +{% endhint %} + +The operator does not interact with Better Stack directly — monitoring is fully automatic. A **public status page** aggregates every hot node's monitor and is available at the URL listed in [Networks](README.md#networks). + +## 6. Rewards distribution + +Rewards are distributed each **epoch** (103 hours). At the end of every epoch, the rewards service: + +1. Reads the node's per-epoch uptime from the monitoring platform. +2. Reads the operator's USDC and COTI holdings at the epoch snapshot. +3. Evaluates the eligibility rules (see [Feature 4](#4-eligibility-checks)). +4. Records each eligible node's reward allocation in the on-chain **rewards smart contract**. + +Rewards are **not** auto-deposited to the operator's wallet. Once the contract has been credited, the operator claims the accrued balance either from the **Claim Now** button in the **My Node** dashboard or by calling the rewards smart contract directly from any wallet they control. Unclaimed rewards remain available until claimed. + +The per-operator dashboard shows each past epoch with uptime, holdings, earned amount, and an "Eligible / Ineligible" badge. See the [Node Ecosystem Litepaper](../running-a-coti-node/coti-node-ecosystem-litepaper.md) for the economic model. diff --git a/node-ecosystem/glossary.md b/node-ecosystem/glossary.md new file mode 100644 index 0000000..dbdb86c --- /dev/null +++ b/node-ecosystem/glossary.md @@ -0,0 +1,152 @@ +# Glossary + +Terms you will encounter in the COTI Node Ecosystem web app, the installer, and this documentation. Definitions are authored for node operators; wording may differ from internal field names while preserving the same meaning. + +## Node states + +### Node status + +The operational state of the node process, derived from the node's JSON-RPC `eth_syncing` method and peer presence: + +* **Active** — the node is online and fully synced with the tip of the chain. +* **Syncing** — the node is online but still catching up on blocks. +* **Offline** — the node is not currently observed in the peer set. + +"Online" in the UI refers to any node that is **Active** or **Syncing**. + +### NFT state + +The on-chain thermal flag stored on the node's Soulbound NFT: + +* **Hot** — the NFT has been minted and is currently marked hot. +* **Cold** — either the NFT has not been minted yet (treated as cold by default), or the NFT has been marked cold after a prolonged outage. + +### Thermal status + +The combined state shown to operators, derived from node status + NFT state: + +| Node status | NFT state | Thermal status | +|---|---|---| +| Active / Syncing | Cold | **Warming up** | +| Active / Syncing | Hot | **Hot** | +| Offline | Hot | **Cooling down** | +| Offline | Cold | **Cold** | + +### Warming up + +A node is **warming up** when it is online and reachable but has not yet been continuously present long enough for the ecosystem to consider it stable. No NFT has been minted yet. The operator should keep the node online — the warm-up progress bar in `/my-nodes` tracks remaining time. + +### Cooling down + +A node is **cooling down** when it was previously hot (NFT minted) but has gone offline. If the node comes back online quickly enough, it remains hot. If it stays offline long enough, the NFT flips to cold and the node must warm up again. + +### Time to thermal update + +Time remaining until the node transitions thermal state — until it becomes **hot** if currently warming up, or until it becomes **cold** if currently cooling down. Not shown when the node is already in a stable state (hot-while-online or cold-while-offline). + +## Warm-up & cooldown windows + +The thermal state machine is driven by four configuration values maintained by the ecosystem. They are exposed so operators understand the timing of their node's transitions. + +### HOT\_WINDOW\_HOURS + +The length of the rolling window used to decide whether a node is stable enough to become hot. Defaults to **103 hours** (one epoch). + +### HOT\_THRESHOLD\_HOURS + +The minimum number of hours *within* `HOT_WINDOW_HOURS` that a node must be continuously present to qualify as hot and receive its Soulbound NFT. Defaults to **72 hours**. + +In plain language: *"To become hot, a node must be seen by peers for at least `HOT_THRESHOLD_HOURS` hours during the last `HOT_WINDOW_HOURS` hours."* + +### COLD\_WINDOW\_HOURS + +The length of the rolling window used to decide whether a node has become unstable enough to be demoted from hot back to cold. Defaults to **206 hours**. + +### COLD\_THRESHOLD\_HOURS + +The minimum number of hours *within* `COLD_WINDOW_HOURS` that a previously-hot node must be absent to be marked cold. When reached, the node must warm up again before it can return to hot. Defaults to **144 hours**. + +In plain language: *"A hot node that stays offline for more than `COLD_THRESHOLD_HOURS` hours in any rolling `COLD_WINDOW_HOURS` window cools back to cold and must redo the warm-up."* + +## Identity & ownership + +### Node private key + +The 64-hex secret that identifies a node on the network. It is generated locally in the browser (or supplied by the operator), written to the node's `nodekey` file by the installer, and **never transmitted to any COTI server**. + +### Node address (public key) + +The Ethereum-style address derived from the node private key. It is used as the node's identity on-chain and is the wallet that receives the Soulbound Node NFT. + +### Wallet address + +The wallet connected to the web app (for example via MetaMask). For the per-operator dashboard to show a node, the connected wallet must be the node address — that is, the wallet that owns the Soulbound NFT. + +### FQDN (Fully Qualified Domain Name) + +The public hostname the operator configures for their node (for example `node1.example.com`). An A record must point the FQDN to the server's public IP before installation. + +The FQDN is a **prerequisite for rewards**: the ecosystem probes the node's JSON-RPC endpoint through the FQDN to determine uptime, so a node without a reachable FQDN cannot accrue uptime and therefore cannot earn rewards. See [installation.md](installation.md). + +### RPC URL + +The public HTTPS endpoint the node exposes after installation, typically `https:///rpc`. This is the URL that Better Stack polls to invoke the Node Health Monitor's health check. + +### Soulbound Node NFT + +A non-transferable NFT minted to the operator's wallet once the node becomes hot. It stores the node's name and image and is the on-chain proof of node ownership. Because it is soulbound, it cannot be transferred between wallets. + +## Rewards + +### Epoch + +A fixed 103-hour reward period. At the end of each epoch, the rewards service evaluates eligibility and credits eligible nodes. + +### Eligibility + +The set of rules a node + operator must satisfy in an epoch to receive rewards: + +* **Uptime (mandatory).** Node uptime for the epoch is at least the configured percentage. +* **Holdings (either threshold is enough).** The operator wallet meets **at least one** of: + * **USDC** holdings on COTI network ≥ the configured threshold, or + * **COTI** holdings ≥ the configured threshold (custodial and non-custodial wallets both count). + +Whitelisted operators are exempt from the holdings rule and only need to meet the uptime rule. + +### Eligible + +A node that was found eligible for rewards in at least one epoch. The home-page stats card counts unique nodes that have ever been eligible; the `/my-nodes` per-epoch history marks each epoch with **Eligible** / **Ineligible**. + +### Whitelisted + +An operator flag that exempts the wallet from the holdings requirement. Uptime is still required. Whitelisting is managed centrally by COTI; most operators will not be whitelisted. + +### Blacklisted + +An operator flag that prevents a node from being accepted as a peer candidate. Blacklisted nodes do not appear in the ecosystem's dataset and cannot accrue rewards. Blacklisting is used for operational or abuse reasons and is not a state a normal operator encounters. + +### Uptime + +The percentage of an epoch during which the node was judged healthy by the monitoring stack. An RPC that merely answers is not enough — the health check confirms that the node is actually operating, and only healthy results accrue uptime. Displayed both per-epoch and all-time. + +### Rewards (total / last epoch) + +* **Total Rewards** — all-time COTI earned by a node across every epoch it was eligible for. +* **Last Epoch Rewards** — COTI earned in the most recently closed epoch. +* **Next Epoch Rewards** — the size of the pool that will be distributed in the upcoming epoch (configured centrally). + +Rewards accrue in the on-chain **rewards smart contract** rather than being deposited directly into the operator's wallet. Operators withdraw their balance via the **Claim Now** button in the **My Node** dashboard, or by calling the rewards smart contract directly. + +## Other terms you may see + +### Live node heartbeats + +The home-page visualization showing the count of nodes currently observed by peer discovery. The pulsing tiles are purely decorative; only the counter reflects real data. + +### Better Stack + +The external uptime-monitoring platform used by the ecosystem to probe every hot node. Operators do not sign up for or configure Better Stack directly — the ecosystem registers monitors automatically after NFT minting. + +### Status page + +The public Better Stack dashboard that aggregates every hot node's monitor state (up / down). It is the fastest way to see the current health of the whole fleet. URLs are listed in [Networks](README.md#networks). diff --git a/node-ecosystem/installation.md b/node-ecosystem/installation.md new file mode 100644 index 0000000..cf6d40e --- /dev/null +++ b/node-ecosystem/installation.md @@ -0,0 +1,131 @@ +# Installation + +This page explains what happens when you run the automated installer produced by the [**`/setup`** wizard](ui-guide.md). It is the destination for the **"Learn more about installation"** link in the installer step. See [Networks](README.md#networks) for the testnet and mainnet web-app URLs. + +{% hint style="info" %} +This page covers the **automated** installer (the single `curl | sudo bash` command). If you want the **manual** Docker-based procedure (hardware specs, ports, step-by-step Git clone and start scripts, FAQ), see [Running a COTI Node](../running-a-coti-node/README.md). +{% endhint %} + +## Certified operating system + +The installer is **certified on Ubuntu 24.04 LTS**. It is the only officially tested target. + +Other Debian-family distributions may work — the installer will warn and prompt for confirmation — but COTI does not guarantee compatibility and does not support installations on other systems. When in doubt, deploy a fresh Ubuntu 24.04 LTS server. + +## What you need before running the installer + +1. **A server running Ubuntu 24.04 LTS** with root access. +2. **Free disk space** on the install directory's partition, per network: + * **Testnet:** at least **100 GB**. + * **Mainnet:** at least **700 GB** (the mainnet chain history is significantly larger and grows over time). +3. **Ports 80 and 443** free on the server (used for HTTP challenge + HTTPS). +4. **Port 7400 (TCP + UDP)** free and not blocked by firewall or iptables (peer-to-peer + node discovery). +5. **A publicly-resolvable FQDN** (for example `node1.example.com`) with an **A record pointing to the server's public IP** — configured and propagated **before** you run the installer. +6. **A node private key** (64 hex characters) — the wizard can generate one for you, or you can bring your own. + +{% hint style="warning" %} +**The FQDN is a reward prerequisite, not just a convenience.** The installer requests a Let's Encrypt certificate for your FQDN, and the ecosystem later probes your node's JSON-RPC **through that FQDN** to measure uptime. If the FQDN is missing, misconfigured, or the certificate cannot be issued, **your node will not be credited with uptime and will not earn rewards** — even if the node is fully synced. See [glossary.md](glossary.md) for the FQDN entry. +{% endhint %} + +## The one-line command + +The wizard generates a command of this shape: + +```bash +curl -sL https://fullnode..coti.io | sudo bash -s -- "" "" +``` + +`` is either `mainnet` or `testnet`, `` is the 64-hex node key (with or without the `0x` prefix), and `` is the domain name that already points to your server. + +{% hint style="danger" %} +Piping `curl` into `sudo bash` executes a remote script as root. Only run commands you obtained from the official wizard, served over `https://fullnode.mainnet.coti.io` or `https://fullnode.testnet.coti.io`. Inspect the script first if you are unsure — the source is the [`coti-full-node`](https://github.com/coti-io/coti-full-node) repository's `install_coti-full-node.sh`. +{% endhint %} + +## What the installer does + +The installer is driven by [`install_coti-full-node.sh`](https://github.com/coti-io/coti-full-node/blob/main/install_coti-full-node.sh) in the `coti-full-node` repository. It executes the following phases on your server: + +### 1. OS and input validation + +* Detects `/etc/os-release` and warns if the distribution is not Ubuntu 24.04.x. +* Confirms the script is running as root. +* Validates that the private key is exactly 64 hex characters. +* Validates the FQDN as a well-formed hostname (≤ 253 chars). + +### 2. Environment pre-checks + +* Confirms the current directory is writable and has enough free disk space for the selected network (see [What you need](#what-you-need-before-running-the-installer)). +* Confirms ports 80, 443 (for Nginx) and 7400 (for the node) are free. +* Confirms no active `ufw` or `iptables` rules block those ports. + +### 3. Host dependencies + +Installs the packages required to run the node: + +* Docker and Docker Compose (skipped if Docker is already present). +* `certbot` for the Let's Encrypt certificate. +* `curl`, `git`, `jq`, `dnsutils`. + +### 4. Repository checkout + +Clones the [`coti-full-node`](https://github.com/coti-io/coti-full-node) repository into the current directory on the tagged branch (for example `coti-mainnet`), and refuses to proceed if a clone already exists. + +### 5. Node configuration + +* Writes a `.env` file with the server's detected public IP and the chosen FQDN. +* Writes the private key into a `nodekey` file for the node process. + +### 6. HTTPS and reverse proxy + +Unless `--no-nginx` is passed: + +* Starts a temporary Nginx on port 80 to serve the ACME challenge. +* Requests a Let's Encrypt certificate for the FQDN via `certbot`. +* Tears the temporary Nginx down. +* Writes the full Nginx config (`/rpc`, `/ws`, `/metrics` upstreams) and starts the production proxy. + +This is the step that makes your node reachable at `https:///rpc` — which is what the monitoring system uses to check your uptime. + +### 7. Node launch + +Runs `./start_coti-full-node.sh`, which brings up the COTI full node container under Docker Compose and begins syncing the chain. + +## After the command finishes + +On success the script prints: + +``` + SUCCESS! Your COTI full node is initializing. + FQDN: https:// + Use 'docker logs -f coti--full-node' to view logs. +``` + +At this point: + +* The node starts syncing blocks from peers. +* The wizard in the browser polls the peer-discovery service every ~60 seconds and advances as soon as your node appears in the peer set. +* You enter the **warm-up period** — once your node has been continuously observed for `HOT_THRESHOLD_HOURS` inside a `HOT_WINDOW_HOURS` window, a Soulbound **Node NFT** is minted to your operator wallet and your node becomes **hot**. See the [Glossary](glossary.md) for the exact definitions. + +## Optional flags + +The installer accepts two flags that the wizard does not surface: + +| Flag | Purpose | +|------|---------| +| `--no-nginx` | Skip the Nginx + Let's Encrypt setup. The node still runs on `:8545` / `:8546` but is **not** publicly reachable over HTTPS. Not suitable for reward-eligible nodes. | +| `--staging` | Use the Let's Encrypt **staging** environment (useful for dry runs; the resulting certificate is not trusted by browsers). | + +To use these, invoke the script with the extra argument appended: + +```bash +curl -sL https://fullnode.mainnet.coti.io | sudo bash -s -- "0x..." "node1.example.com" --staging +``` + +## Troubleshooting + +* **Certbot failed** — Confirm your A-record has propagated (`dig `) and that ports 80/443 are reachable from the public internet. Then re-run the installer. +* **Port already in use** — Stop whatever is occupying the port (common culprits: Apache on 80, an existing Nginx, another COTI install). The installer refuses to continue if 80, 443, or 7400 are busy. +* **`coti-full-node` directory already exists** — The installer requires a clean directory. Remove or archive the previous clone before re-running. +* **Node does not appear in the wizard** — Confirm the node container is running (`docker ps`), the chain is syncing (`docker logs -f coti--full-node`), and the FQDN resolves to your server's public IP. + +For manual node management (restart, stop, logs, cleanup), see [Running a COTI Node → Restarting Your Node](../running-a-coti-node/README.md#restarting-your-node). diff --git a/node-ecosystem/ui-guide.md b/node-ecosystem/ui-guide.md new file mode 100644 index 0000000..3785232 --- /dev/null +++ b/node-ecosystem/ui-guide.md @@ -0,0 +1,189 @@ +# UI guide + +A page-by-page walkthrough of the COTI Nodes web app (see [Networks](README.md#networks) for the testnet and mainnet URLs). Read [features.md](features.md) first for the product-level overview; this page describes what each screen shows and how to use it. + +## Site map + +The top-level navigation exposes three tabs: **Overview**, **My Node**, and **Eligibility**. The spin-up and edit flows are reachable from links inside those pages rather than from the top nav. + +| Route | Tab / Surface | Purpose | +|---|---|---| +| `/` | Overview | Public dashboard: live heartbeats, ecosystem stats, nodes table | +| `/join` | (from "Spin up a Node") | Choose between local install and hosted provider | +| `/setup` | (from Join) | 7-step guided installation wizard | +| `/my-nodes` | My Node | Per-operator dashboard (wallet-gated) | +| `/edit-node` | (from My Node) | Rename your node (stored on the NFT) | +| `/eligibility` | Eligibility | Explainer of reward eligibility rules | +| `/terms` | (footer) | Terms of service | + +## Overview (`/`) + +The landing page has several sections. + +
Overview hero with Spin up a Node CTA, Live Node Heartbeats panel, and the three ecosystem stats cards

Overview hero, Live Node Heartbeats, and ecosystem stats.

+ +### Hero + live heartbeats + +A **"Spin up a Node"** CTA sits alongside the **Live Node Heartbeats** panel. The panel shows: + +* The current count of nodes observed by the peer-discovery service. +* How many seconds have passed since the last refresh. +* A purely decorative pulse visualization. + +### Ecosystem stats + +Three cards summarize the most recent closed epoch and all-time totals: + +* **Reward-eligible nodes (last epoch)** — how many nodes met the rules last epoch. +* **COTI dropped (last epoch)** — total rewards distributed last epoch. +* **Total COTI earned** — cumulative rewards paid across all epochs. + +Clicking the clock icons on the first two cards opens an **Epoch Status** modal with the current epoch number and time remaining. + +### Nodes table + +
Nodes table listing node operator, total rewards, status, uptime, and latency

Every node the ecosystem knows about, sortable and searchable.

+ +Columns: + +* **Node operator** — NFT avatar, node name, and the truncated node address. Nodes without a minted NFT show "NFT Not Found". +* **Total rewards** — cumulative COTI earned. +* **Status** — Active / Syncing / Offline (see [Glossary → Node status](glossary.md#node-status)). +* **Uptime** — all-time percentage and a proportional bar. +* **Latency** — most-recent RPC latency with a color-coded rank (Fast / Good / Slow). + +The search box filters on node name, node address, and status. Clicking a row opens a **Node Details** modal with the node's NFT metadata, rewards breakdown, and a link to the operator's recent activity. + +## Join COTI Nodes (`/join`) + +
Join page with two options: Local Node (Vibe Coding) and Hosted Node Provider (Coming Soon)

Entry point for new operators.

+ +Two cards: + +* **Local node (Vibe Coding)** — routes to `/setup`, the guided installer. This is the primary, fully-supported path. +* **Hosted node provider** — currently labeled **Coming Soon**. Reserved for a future marketplace of third-party providers and not usable yet. + +## Spin up a Node (`/setup`) + +The installation wizard is a 7-step flow. The top of the page shows a **SetupBar** with step labels; the main panel swaps content per step. The primary **Next** button advances; **Back** goes to the previous step. + +### Step 1 — Watch the setup video + +
Setup step 1 with a short walkthrough video and bullet summary

Step 1: short video walkthrough.

+ +A short video plus a bulleted summary: what the command does, what happens after, and that there is no configuration required. + +### Step 2 — Accept the terms + +
Setup step 2 presenting the Terms of Use with a checkbox

Step 2: terms of use for node operators.

+ +The Terms of Use must be checked before the wizard advances. A **Download Full Terms of Use (PDF)** link exposes the complete document. Trying to continue without checking the box surfaces an inline error. + +### Step 3 — Generate node keys + +
Setup step 3 showing a generated public/private key pair with a Download Key Backup button and a confirmation checkbox

Step 3: locally-generated node keys with an option to bring your own.

+ +Two paths: + +* **Generate node keys locally** — the wizard generates a fresh private key in the browser, derives the node address, and offers a **Download Key Backup** button. You must tick **"I've saved my keys in a secure location"** to proceed. +* **Bring your own key** — paste an existing 64-hex private key. The wizard derives the address and confirms it. If that address already owns a node NFT, a modal offers to clear the field so you don't accidentally re-run setup for an existing node. + +If the just-generated address differs from the currently connected wallet, a yellow notice explains that you will need to connect the new wallet later to see the node's warm-up state, NFT, and rewards. + +{% hint style="warning" %} +The private key is the identity of your node and the wallet that will receive the Soulbound NFT and rewards. It is generated locally and never transmitted. Back it up before continuing. +{% endhint %} + +### Step 4 — Setup FQDN + +
Setup step 4 with the Node FQDN input, an A/CNAME instruction, and an I have completed my FQDN settings checkbox

Step 4: the FQDN that will front your node's RPC.

+ +Enter the public hostname that will point to your node (for example `node1.example.com`). The checkbox **"I have completed my FQDN settings"** triggers a live DNS lookup via `dns.google.com/resolve`: + +* Success — the box is checked and you can proceed. +* Failure — an inline error explains that the domain did not resolve; fix the A/CNAME record at your DNS provider and retry. + +{% hint style="warning" %} +**This FQDN is the address the ecosystem will use to reach your node's JSON-RPC for uptime monitoring.** It must be live, its A record must point to your server, and ports 80/443 must be reachable from the public internet. Without a valid FQDN your node cannot earn rewards — see [installation.md](installation.md). +{% endhint %} + +### Step 5 — Run the command + +
Setup step 5 showing a terminal card with the generated curl | sudo bash one-liner and a Learn more about installation link

Step 5: the installer command tailored to your key and FQDN.

+ +The wizard displays the one-liner tailored to the key and FQDN from the previous steps: + +```bash +curl -sL https://fullnode..coti.io | sudo bash -s -- "" "" +``` + +Copy and run it as root on your server. A **"Learn more about installation"** link opens [installation.md](installation.md) (this documentation). Tick **"I've run this command"** to advance. + +### Step 6 — Waiting for node connection + +
Setup step 6 with a spinner and the message Listening for node heartbeat

Step 6: the wizard polls peer discovery every ~60 seconds and advances automatically once your node is seen.

+ +The wizard polls the peer-discovery service every ~60 seconds and waits for your node address to show up in the peer set. Three states: + +* **Searching** — spinner + "Listening for node heartbeat". You can safely close the tab and return later. +* **Detected** — green check + "Heartbeat Detected!". The wizard auto-advances in a few seconds. +* **Timeout** — after the initial grace period, a retry countdown appears and the wizard retries automatically. + +{% hint style="info" %} +This step only confirms that peers can *see* your node. It does not mean your node is hot or that an NFT has been minted. That is the **warm-up period** (see [Glossary → Warming up](glossary.md#warming-up)), tracked on the **My Node** tab. +{% endhint %} + +### Step 7 — Your node is live + +
Setup step 7 with a success card showing Status Online, Uptime tracking Started, and a Go to Dashboard button

Step 7: node is on the network and uptime tracking has started.

+ +A success card with a **Go to Dashboard** button that routes to **My Node**. It also confirms that uptime tracking has started — the node has been registered with the monitoring stack via its FQDN. + +If the connected wallet differs from the node address, the wizard shows a warning explaining that the dashboard only lists nodes owned by the connected wallet — connect the node wallet (or import its private key into MetaMask) to see the node on the dashboard. + +## My Node (`/my-nodes`) + +The per-operator dashboard. It requires a connected wallet; the wallet must own a Soulbound Node NFT to show full content. + +### Warmup (in progress / complete) + +
My Node screen showing the Warmup Complete card with the progress bar at 100%

The warm-up card near the end of the warm-up period, with the progress bar full. The NFT is about to be minted.

+ +While the node is warming up, the page shows a **Warmup In Progress** card with an elapsed / required progress bar (for example `18h 30m / 72h (26%)`) and copy explaining that the operator should keep the node online to complete the warm-up. + +When the threshold is reached (progress reaches 100%, as in the screenshot above), the card flips to **Warmup Complete**. The Soulbound NFT is minted shortly thereafter and the full dashboard replaces the warm-up card automatically. + +### No node detected + +
My Node screen showing No Node Detected for a wallet without a node NFT

Empty state for wallets that do not own a node NFT.

+ +If the connected wallet has not started setup and does not own a node NFT, the page shows a "No Node Detected" card with a link back to the overview. Operators who just finished `/setup` but see this screen are likely connected with the wrong wallet — the NFT is minted to the **node address**, not the wallet used to navigate the site. + +### Full dashboard + +
My Node full dashboard with node identity, live status, eligibility panel, all-time stats, and past epochs table

Full operator dashboard once the NFT has been minted.

+ +Once the NFT exists, the dashboard shows: + +* **Node identity card** — NFT image, node name, `LIVE` badge, node ID (address), **Edit** button → `/edit-node`, and the headline **Total Earned** in COTI with a **Claim Now** button that withdraws the accrued balance from the rewards smart contract into the connected wallet. Operators who prefer to claim from outside the UI can also call the rewards contract directly. +* **At-a-glance stats** — **All-Time Uptime** with a performance badge (for example *Excellent*), **Eligibility Streak (Days)**, and **COTI Claimed**. +* **Eligibility panel** — your current USDC holdings, COTI holdings, and node uptime for the current epoch, each compared to its threshold with a progress bar. **Uptime is always required**; for the holdings requirement, meeting **either** the USDC threshold **or** the COTI threshold is enough. A row that fails shows a warning and the shortfall. +* **Past Epochs table** — paginated per-epoch history with columns: + * **Epoch** — epoch number. + * **USDC** — USDC balance at the epoch snapshot. + * **COTI** — COTI balance at the epoch snapshot. + * **Earned** — COTI credited for the epoch (zero if ineligible). + * **Uptime** — uptime percentage for the epoch. + * **Status** — **Eligible** / **Ineligible**. + +## Edit Node (`/edit-node`) + +A focused flow that renames the node. Because the name is stored on the Soulbound NFT, saving triggers a wallet signature / on-chain transaction. Changes propagate to the public nodes table the next time the UI refreshes NFT metadata. + +## Eligibility (`/eligibility`) + +
Eligibility tab showing the three reward requirements: USDC Holdings, COTI Holdings, and Operate a Node uptime

The three reward requirements, with current thresholds.

+ +A static explainer that lists the reward requirements — **USDC Holdings**, **COTI Holdings**, and **Operate a Node** (minimum uptime) — with each threshold. A **Check My Eligibility** button opens a modal that compares the connected wallet's current values against the rules. + +The rule combining those requirements is: **uptime is always required**, and the wallet qualifies on holdings by meeting **either** the USDC threshold **or** the COTI threshold (see [Features → Eligibility checks](features.md#4-eligibility-checks)). diff --git a/running-a-coti-node/README.md b/running-a-coti-node/README.md index 03b162c..748d57f 100644 --- a/running-a-coti-node/README.md +++ b/running-a-coti-node/README.md @@ -283,3 +283,8 @@ Congratulations on setting up your COTI Node! By running a node, you’re contri The following related sections may provide helpful information: * [coti-node-ecosystem-litepaper.md](coti-node-ecosystem-litepaper.md "mention") +* [**Node Ecosystem**](../node-ecosystem/README.md) — the managed product experience at [dev.nodes.coti.io](https://dev.nodes.coti.io), including the guided [installer](../node-ecosystem/installation.md), a [UI walkthrough](../node-ecosystem/ui-guide.md) of the spin-up flow, and a [glossary](../node-ecosystem/glossary.md) of thermal states and warm-up windows. + +{% hint style="warning" %} +**Running a node without a valid FQDN means no rewards.** The ecosystem measures uptime by calling your node's JSON-RPC endpoint through your domain name. A node that is fully synced but not publicly reachable over a valid FQDN will not accrue uptime and will not be eligible for rewards. See [Node Ecosystem → Installation](../node-ecosystem/installation.md). +{% endhint %}