2bbdb00a4d
包含节点账本、每日清算,以及 Ubuntu 交互式部署脚本。 Co-authored-by: Cursor <cursoragent@cursor.com>
111 lines
4.8 KiB
Markdown
111 lines
4.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` | 可单独执行的清算命令 |
|
||
| `deploy/ubuntu22.sh` | Ubuntu 22.04 交互式部署 |
|
||
|
||
## 数据表
|
||
|
||
业务表:
|
||
|
||
- `users`:钱包地址、注册时间。
|
||
- `compute_nodes`:节点 SN、购买金额、12 个月授权、`online` / `offline`、最后心跳。可选 `callback_url` 用来推送任务。
|
||
- `node_yields`:每日算力产出和积分。同一节点同一天只有一条。
|
||
- `withdrawal_logs`:提现金额、资产符号、链上哈希、状态。
|
||
|
||
计算用的表:
|
||
|
||
- `uptime_intervals`:一段连续在线时间。
|
||
- `compute_tasks`:下发的模拟任务和回传结果。
|
||
- `scheduler_locks`:多台服务实例同时跑定时任务时互斥。
|
||
|
||
## 产出公式
|
||
|
||
授权金额按授权起止日期的天数线性释放,再乘当天表现系数。单节点累计积分不超过购买金额。
|
||
|
||
- 在线率 = 当天授权窗口内的在线秒数 / 当天授权有效秒数
|
||
- 任务响应率 = 校验通过且执行成功的任务数 / 当天下发任务数
|
||
- 当天没有下发任务时,表现系数 = 在线率
|
||
- 有任务时,表现系数 = `0.7 × 在线率 + 0.3 × 响应率`
|
||
- 算力产出 = 购买金额 × 表现系数
|
||
- 当日积分 = 算力产出 / 授权天数
|
||
|
||
开放的在线区间如果最后心跳已超过 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 不匹配都不算成功。
|
||
|
||
## 接口
|
||
|
||
前缀都是 `/api/v1`。金额在 JSON 里是字符串。
|
||
|
||
| 方法 | 路径 | 作用 |
|
||
|---|---|---|
|
||
| POST | `/users` | 注册钱包 |
|
||
| POST | `/nodes` | 登记节点 |
|
||
| GET | `/nodes/{sn}` | 查看节点 |
|
||
| POST | `/node/heartbeat` | 心跳,请求体 `{"sn":"..."}` |
|
||
| 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` | 新节点授权月数 |
|
||
| `DISABLE_SCHEDULER` | `false` | 设为 `true` 时不启动定时任务 |
|
||
|
||
修改 `.env` 后执行 `systemctl restart hypernode`。
|