Files
HyperNode-AI/说明.md
T
2026-10-10 22:20:45 +08:00

112 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` | 可单独执行的清算命令 |
| `web/` | 控制台页面,服务启动后打开 `/` |
| `deploy/manage.sh` | Ubuntu 22.04 交互式部署,支持 `curl \| bash` |
## 数据表
业务表:
- `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`。