Files
Chan/live/deploy/dryrun.sh
T
jackandCursor 9562b8c598 空跑补一次带签名请求,否则密钥与白名单根本没被验到
dryrun 第 5 步声称"会真实验到密钥与白名单",但 start() 在空跑下于密钥检查
之前就 return,全程只发了 contracts() —— 那是公开端点,不验签。于是空跑会
"通过"却什么都没测到。这种假保证比不测更糟:等第一个真信号来时才暴露,而
信号那时正在过期,没有从容排查的余地。

现在空跑返回前发一次 account()(只读),失败即退出并给出码表(40018 白名单
/ 40037 key 不存在 / 40001,40009 secret,passphrase / 40099 权限)。顺带报
可用余额,并在不足 MAX_OPEN 笔并发所需保证金时告警。

两处 SystemExit 会绕过 run() 的收尾,退出前不关 aiohttp 会话,日志尾部一串
Unclosed client session 会把真正的报错顶出视野。都补上了 close()。

BITGET_PASSPHRASE 现在也接受 BITGET_API_PASSPHRASE:另两项都带 API_,只有
它不带,很容易顺手写错,而后果是"像是填了"但签名一直失败。我自己就踩了。

启动时打一行 Telegram 是否启用。配错 token 的表现原本是完全静默。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 18:17:53 +08:00

107 lines
5.2 KiB
Bash
Executable File
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.
#!/usr/bin/env bash
# 空跑验全链:真连交易所读规则/持仓,**不下任何真单**。
#
# 上真单之前必须过这一步。它验的是那些"上线才会暴露、且暴露方式是花钱"的
# 环节:密钥能不能用、IP 白名单对不对、时钟同不同步、搬运通不通、
# 数量与价位取整合不合交易所规则。
set -euo pipefail
APP=/opt/chan
CONF=/etc/chan-live/live.env
STATE=/var/lib/chan-live
USER_NAME=chan
SECS="${SECS:-90}"
die() { echo "⛔ $*" >&2; exit 1; }
ok() { echo " ✓ $*"; }
[[ $EUID -eq 0 ]] || die "要 rootsudo $0"
[[ -f "$CONF" ]] || die "缺 $CONF,先跑 install.sh"
set -a; . "$CONF"; set +a
echo "── 1. 配置自检 ──"
for v in BITGET_API_KEY BITGET_API_SECRET BITGET_PASSPHRASE SHIP_FROM; do
[[ -n "${!v:-}" ]] || die "$CONF$v 还是空的"
done
ok "密钥三项与 SHIP_FROM 都已填"
[[ "$LIVE_HOME" != /opt/chan* ]] || die "LIVE_HOME 不能指到仓库里(会被 git 清掉)"
ok "LIVE_HOME=$LIVE_HOME 在仓库外"
echo "── 2. 时钟 ──"
# staleness 闸靠两机时钟一致才有意义。这里只能验本机;跨机偏差由
# ship_signals 在收到信号时报「时间倒流」
if command -v chronyc >/dev/null; then
chronyc tracking | grep -E "Reference ID|System time|Leap status" | sed 's/^/ /'
src="$(chronyc tracking | awk '/Reference ID/{print $NF}')"
[[ "$src" != "()" && -n "$src" ]] || die "chrony 还没同步上,等一会再跑"
ok "chrony 已同步"
else
die "没装 chrony。staleness 闸不可信,先 apt install chrony"
fi
echo "── 3. 出口 IP 是否在白名单内 ──"
myip="$(curl -s --max-time 10 https://api.ipify.org || true)"
[[ -n "$myip" ]] && echo " 本机出口 IP$myip" || echo " ⚠ 取不到出口 IP"
echo " 对照 Bitget 后台该 key 的 IP 白名单,不一致下面会报 40018 之类"
echo "── 4. 能否 ssh 到采集机 ──"
# 不能用 ssh <host> 'echo ok' 来试:采集机那侧的 authorized_keys 用了强制命令
# (把这把 key 锁成只能跑 tail,拿不到 shell),任何请求都会变成 tail -F,
# 而它**永不返回**——ConnectTimeout 只管建连不管命令时长,测试会永久挂住。
# 所以照 ship_signals 的真实用法读流:tail -c +0 会先把整个文件吐出来,
# 数一下就等于对端总线的条数,之后它挂着等新内容,由 timeout 收掉。
rb="${SHIP_REMOTE_BUS:-\$HOME/chan-live/state/signals_live.jsonl}"
err="$(mktemp)"; outf="$(mktemp)"
# timeout 要套在 sudo **里面**:套外面时 SIGTERM 只到 sudo,未必传给 ssh
# 于是该被收掉的 tail 会继续挂着
sudo -u "$USER_NAME" timeout 12 ssh -T -o BatchMode=yes -o ConnectTimeout=10 \
"$SHIP_FROM" "tail -c +0 -F $rb" >"$outf" 2>"$err" || true
n="$(wc -l < "$outf")"
if grep -qi "Host key verification failed" "$err"; then
fp="(在采集机上跑 ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub 拿)"
rm -f "$err" "$outf"
die "主机指纹没确认过。这不是 key 的问题,装 key 也修不了。
$USER_NAME 的 known_hosts 是空的,而 BatchMode=yes 不允许交互确认。
**不要**用 StrictHostKeyChecking=no 糊过去,那等于放弃中间人防护。
正确做法:在采集机上读出权威指纹 $fp
再在这台上写入并核对:
sudo -u $USER_NAME ssh-keyscan -t ed25519 <采集机IP> \\
| sudo -u $USER_NAME tee -a $STATE/home/.ssh/known_hosts
sudo -u $USER_NAME ssh-keygen -lf $STATE/home/.ssh/known_hosts"
elif grep -qiE "Permission denied|publickey" "$err"; then
rm -f "$err" "$outf"
die "认证被拒。指纹是通的,是 key 没装到采集机上:
sudo -u $USER_NAME ssh-keygen -t ed25519 -N '' -f $STATE/home/.ssh/id_ed25519
再把 $STATE/home/.ssh/id_ed25519.pub 加到采集机的 authorized_keys"
elif [[ -s "$err" ]] && ! grep -q "^" "$outf" 2>/dev/null; then
msg="$(head -3 "$err")"; rm -f "$err" "$outf"
die "ssh $SHIP_FROM 不通:$msg"
else
ok "ssh $SHIP_FROM 通"
echo " 对端总线现有 $n 条信号"
[[ "$n" -gt 0 ]] || echo " ⚠ 对端总线是空的。信号 6.8 个/天,刚重启过就是空的很正常;但要确认采集机接了总线"
rm -f "$err" "$outf"
fi
echo "── 5. 执行器空跑 ${SECS}s(真连交易所,不下单)──"
# --dry-run 下只读不写:下单一律只打印。合约规则那个端点是**公开**的、不验签,
# 所以空跑里专门补了一次带签名的 account() —— 否则这一步会"通过"却根本没测到
# 密钥与 IP 白名单,等第一个真信号来时才暴露,而那时信号正在过期
# 让 chan 自己 source 配置($CONF 是 640 root:chan,它读得到)。
# 不用 `env "$(grep ...)"` 那种拼法:值里有空格就会被切开
set +e
sudo -u "$USER_NAME" bash -c \
"set -a; . '$CONF'; set +a; exec timeout $SECS \
'$APP/.venv/bin/python' '$APP/live/live_exec.py' --dry-run"
rc=$?
set -e
# timeout 到点是 124,属于预期
[[ $rc -eq 124 || $rc -eq 0 ]] || die "空跑退出码 $rc,看上面报错"
ok "空跑没有报错退出"
echo
echo "空跑过了。真跑:"
echo " sudo systemctl enable --now chan-live-ship chan-live-exec"
echo " $APP/live/deploy/status.sh"