0740016ad8
Co-authored-by: Cursor <cursoragent@cursor.com>
165 lines
9.8 KiB
Markdown
165 lines
9.8 KiB
Markdown
# HyperNode-AI 说明
|
||
|
||
HyperNode-AI 是算力节点的控制面。节点程序部署在各处,本服务负责登记节点、接收心跳、下发模拟任务、按天计算积分,并记录提现。
|
||
|
||
时间全部使用 UTC。每日清算的触发时刻是北京时间 00:05,入账的是上一个已经结束的 UTC 日。
|
||
|
||
本地开发直接启动时监听 8000。服务器按 [部署.md](部署.md) 安装后监听 33333。
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
python -m app
|
||
```
|
||
|
||
## 目录
|
||
|
||
| 路径 | 内容 |
|
||
|---|---|
|
||
| `app/models.py` | 数据表 |
|
||
| `app/api.py` | HTTP 接口 |
|
||
| `app/services/heartbeat.py` | 心跳与离线判断 |
|
||
| `app/services/tasks.py` | 任务下发与 nonce 校验 |
|
||
| `app/services/yield_engine.py` | 产出公式与按日入账 |
|
||
| `app/jobs/daily_yield.py` | 凌晨清算入口 |
|
||
| `app/scheduler.py` | 进程内定时任务 |
|
||
| `app/settle.py` | 可单独执行的清算命令 |
|
||
| `frontend/` | Vue 3 控制台源码。改完后在该目录执行 `npm run build` |
|
||
| `web/` | 控制台构建结果,服务启动后打开 `/` |
|
||
| `deploy/manage.sh` | Ubuntu 22.04 交互式部署,支持 `curl \| bash` |
|
||
|
||
## 数据表
|
||
|
||
业务表:
|
||
|
||
- `users`:钱包地址、可选用户名和密码、角色 `user` / `admin`、注册时间。
|
||
- `compute_nodes`:节点 SN、购买金额、12 个月授权、`online` / `offline`、最后心跳。可选 `callback_url` 用来推送任务。
|
||
- `node_yields`:每日算力产出和积分。同一节点同一天只有一条。
|
||
- `withdrawal_logs`:提现金额、资产符号、链上哈希、状态。
|
||
|
||
计算用的表:
|
||
|
||
- `uptime_intervals`:一段连续在线时间。
|
||
- `compute_tasks`:下发的模拟任务和回传结果。
|
||
- `scheduler_locks`:多台服务实例同时跑定时任务时互斥。
|
||
|
||
## 产出公式
|
||
|
||
节点按激活顺序编号。第 1 台显示为 `1001`,第 2 台为 `1002`,即 `display_node_id = 1000 + 激活序号`。首页和控制台的全网节点数同样加上 1000:3 台在线显示为 1003。机器序列号仍用于心跳和客户端,不对外当作节点编号。
|
||
|
||
编号 `1001` 到 `1020` 是创世特权节点,回本固定为 30 天,每日基础释放 = `1500 / 30` = 50。上报显卡只会记录型号,不会改掉这 30 天。从 `1021` 起按显卡世代回本。
|
||
|
||
同一个公网 IP 只能绑定一台普通节点。再挂第二台时会拒绝,并提示去申请机房白名单。白名单可以是单 IP,也可以是网段,例如 `203.0.113.0/24`;请求 IP 落在网段里,或节点本身被标成白名单,就可以挂多台。客户端用心跳上报硬件指纹,由显卡 UUID、主板序列号和网卡地址合成,数据库里唯一。指纹重复会按虚拟机克隆拒绝。机房申请至少 5 台,且证明材料不能包含 10 系、20 系或核显;管理员通过后,该网段自动写入白名单。已经进网段的机器如果上报 10 系及更低显卡,不能混入这批授权。订单审核开通时不占用管理员自己的 IP,节点客户端第一次心跳才绑定地址。
|
||
|
||
心跳上报显卡后,世代会被锁定,并决定 1500 USDT 质押的回本天数。当日积分 = 购买金额 / 回本天数 × 当日表现系数。表现系数就是平台收益加权系数。积分优先冲减待返还质押,直到质押返还完毕。
|
||
|
||
- 创世节点 `1001`–`1020`:30 天,每日基础释放 = `1500 / 30`
|
||
- 40 系及以上,例如 RTX 4090、4080、4070:210 天,每日基础释放 = `1500 / 210`
|
||
- 30 系,例如 RTX 3090、3080、3070、3060 Ti、3060:365 天,每日基础释放 = `1500 / 365`
|
||
- 10 系及更低、20 系,以及核显:540 天,每日基础释放 = `1500 / 540`
|
||
- 在线率 = 当天授权窗口内的在线秒数 / 当天授权有效秒数
|
||
- 任务响应率 = 校验通过且执行成功的任务数 / 当天下发任务数
|
||
- 当天没有下发任务时,表现系数 = 在线率
|
||
- 有任务时,表现系数 = `0.7 × 在线率 + 0.3 × 响应率`
|
||
- 第 21 台及之后,未上报显卡前按 540 天计算。一旦识别到型号就锁定,之后不再改档
|
||
|
||
硬件权重仍会记录:RTX 3060 及以上为 `1.0`,RTX 20 系和 GTX 1060–1660 为 `0.5`,更旧或更低的独显为 `0.05`,没有独显为 `0.02`。回本速度看世代,不看这个权重。10 系的回本天数长于 12 个月授权时,授权结束时间会延到回本周期结束。
|
||
|
||
开放的在线区间如果最后心跳已超过 15 分钟,只计算到最后一次心跳。
|
||
|
||
权重可用环境变量 `ONLINE_WEIGHT`、`TASK_WEIGHT` 修改,默认 `0.7` 和 `0.3`。
|
||
|
||
## 运行中的三件事
|
||
|
||
服务进程里有三个定时任务:
|
||
|
||
1. 每 5 分钟检查心跳。超过 15 分钟没有心跳,或授权到期,节点改为 `offline`,在线区间结束在最后一次心跳。
|
||
2. 每 5 分钟向在线、授权仍有效、且没有未完成任务的节点随机下发任务,每轮最多 20 台。任务带 `task_id` 和一次性 `nonce`。节点若配置了 `callback_url`,会额外 POST 一次;否则节点用拉取接口领取。
|
||
3. 北京时间 00:05 结算上一个已结束的 UTC 日,写入 `node_yields`。同一天已有记录则跳过。
|
||
|
||
回传必须带上任务里的 `nonce`。超时、重复回传、nonce 不匹配都不算成功。
|
||
|
||
## 登录
|
||
|
||
普通用户可以注册钱包、用户名和密码。之后用钱包地址,或用户名加密码登录。管理员只能用账号密码。
|
||
|
||
新部署会在安装结束时打印管理员账号 `admin` 和随机密码,并写入 `/opt/hypernode/.env` 的 `ADMIN_PASSWORD`。已经部署过的机器如果 `.env` 里没有这两项,服务第一次启动会在日志里写一次初始密码:
|
||
|
||
```bash
|
||
journalctl -u hypernode.service | grep 初始密码
|
||
```
|
||
|
||
页面路由:
|
||
|
||
- `/login` 登录和注册
|
||
- `/dashboard` 用户提交 1500 USDT 支付凭证、查看待审核订单、复制已开通节点的 Token 并下载客户端
|
||
- `/admin` 管理员审核授权订单,通过后自动开通 12 个月节点;同时看总用户、总节点、总产出和提现
|
||
|
||
节点心跳、拉任务、回传任务不需要登录。查看全网数据、清算、确认提现需要管理员令牌。
|
||
|
||
## 接口
|
||
|
||
前缀都是 `/api/v1`。金额在 JSON 里是字符串。浏览器登录后带 `Authorization: Bearer <token>`。
|
||
|
||
| 方法 | 路径 | 作用 |
|
||
|---|---|---|
|
||
| POST | `/auth/register` | 注册钱包,可带用户名和密码,返回令牌 |
|
||
| POST | `/auth/login` | 钱包地址,或用户名加密码 |
|
||
| GET | `/me/dashboard` | 当前用户的节点、订单、积分和提现 |
|
||
| POST | `/me/orders` | 提交 1500 USDT 支付凭证 TxID,订单进入待审核 |
|
||
| GET | `/me/nodes/{sn}/client` | 下载挂机客户端。节点未开通时返回 403 |
|
||
| GET | `/admin/orders` | 管理员:授权订单,待审核排在前面 |
|
||
| POST | `/admin/orders/{id}/approve` | 管理员:通过订单,创建节点并签发 Token |
|
||
| POST | `/admin/orders/{id}/reject` | 管理员:拒绝订单,不创建节点 |
|
||
| POST | `/me/nodes` | 直接登记节点,不签发挂机 Token |
|
||
| POST | `/me/withdrawals` | 当前用户申请提现 |
|
||
| GET | `/admin/summary` | 管理员:用户数、节点数、总产出 |
|
||
| GET | `/admin/users` | 管理员:全网用户 |
|
||
| GET | `/admin/nodes` | 管理员:节点状态与今日在线率 |
|
||
| GET | `/admin/withdrawals` | 管理员:提现审核列表 |
|
||
| POST | `/admin/withdrawals/{id}/confirm` | 管理员:写入链上哈希并完成 |
|
||
| POST | `/admin/withdrawals/{id}/reject` | 管理员:拒绝并释放占用的积分 |
|
||
| POST | `/users` | 只登记钱包,不设置密码 |
|
||
| POST | `/nodes` | 登记节点,必须是该钱包本人或管理员 |
|
||
| GET | `/nodes/{sn}` | 查看节点 |
|
||
| POST | `/node/heartbeat` | 心跳。已开通节点必须带 `token`,客户端同时上报显卡、显存、CPU 和内存 |
|
||
| GET | `/node/{sn}/tasks` | 拉取未完成任务 |
|
||
| POST | `/node/task/report` | 回传 `sn`、`task_id`、`success`、`nonce` |
|
||
| GET | `/nodes/{sn}/contribution?yield_date=YYYY-MM-DD` | 预览某日产出,不入账 |
|
||
| POST | `/yield/settle?yield_date=YYYY-MM-DD` | 手动清算,不传日期则清算昨天 |
|
||
| GET | `/nodes/{sn}/yields` | 节点流水 |
|
||
| GET | `/users/{wallet}/balance` | 可用积分 |
|
||
| POST | `/withdrawals` | 申请提现 |
|
||
| POST | `/withdrawals/{id}/confirm` | 写入 `tx_hash` 并完成 |
|
||
| POST | `/withdrawals/{id}/reject` | 拒绝并释放占用的积分 |
|
||
|
||
可用积分 = 已入账积分 − 待处理提现 − 已完成提现。
|
||
|
||
健康检查是 `/health`,不在 `/api/v1` 下面。
|
||
|
||
## 配置
|
||
|
||
生产环境的配置在 `/opt/hypernode/.env`。也可以在启动前用同名环境变量覆盖。
|
||
|
||
| 变量 | 默认值 | 含义 |
|
||
|---|---|---|
|
||
| `DATABASE_URL` | 部署后指向 `/var/lib/hypernode/hypernode.db` | 数据库。可改为 PostgreSQL 连接串 |
|
||
| `HEARTBEAT_TIMEOUT_MINUTES` | `15` | 心跳超时 |
|
||
| `OFFLINE_CHECK_MINUTES` | `5` | 离线巡检间隔 |
|
||
| `TASK_DISPATCH_MINUTES` | `5` | 任务下发间隔 |
|
||
| `DISPATCH_BATCH_SIZE` | `20` | 每轮最多下发数量 |
|
||
| `TASK_DEADLINE_MINUTES` | `10` | 任务回传时限 |
|
||
| `ONLINE_WEIGHT` / `TASK_WEIGHT` | `0.7` / `0.3` | 有任务时的表现系数权重 |
|
||
| `YIELD_TIMEZONE` | `Asia/Shanghai` | 清算触发时区 |
|
||
| `YIELD_HOUR` / `YIELD_MINUTE` | `0` / `5` | 清算时刻 |
|
||
| `LICENSE_MONTHS` | `12` | 新节点授权月数 |
|
||
| `LICENSE_PRICE` | `1500` | 购买节点授权的金额 |
|
||
| `LICENSE_ASSET` | `USDT` | 购买节点授权的资产符号 |
|
||
| `DISABLE_SCHEDULER` | `false` | 设为 `true` 时不启动定时任务 |
|
||
| `JWT_SECRET` | 空则自动生成并写入数据库 | 登录令牌签名 |
|
||
| `JWT_EXPIRE_MINUTES` | `1440` | 令牌有效分钟数 |
|
||
| `ADMIN_USERNAME` | `admin` | 初始管理员用户名 |
|
||
| `ADMIN_PASSWORD` | 空则首次启动随机生成并写入日志 | 初始管理员密码 |
|
||
| `ADMIN_WALLET` | `admin-root` | 初始管理员钱包地址 |
|
||
|
||
修改 `.env` 后执行 `systemctl restart hypernode`。
|