cloud-sre
Lighthouse の InvalidToken が、実際には Erigon の Forbidden だった
Gnosis の Erigon と Lighthouse の Engine API 接続を直した記録。JWT ミスに見えたが、実際に詰まっていたのは authrpc vhost だった。
Gnosis の archive node で、execution layer は Erigon、consensus layer は Lighthouse という構成だった。Erigon 側には次の warning が出続けていた。
flag --externalcl was provided, but no CL requests to engine-api in 22h...
Lighthouse コンテナは起動していたが、ログはこの繰り返しだった。
Failed jwt authorization error: InvalidToken
Execution engine call failed error: Auth(InvalidToken)
HTTP status client error (403 Forbidden) for url (http://gnosis:8551/)
最初は JWT secret の不一致に見える。実際には違った。最後に必要だったのは、Erigon の Engine API に Docker service name を vhost として許可することだった。
--authrpc.vhosts=gnosis,localhost,127.0.0.1
用語の説明
| 用語 | 意味 |
|---|---|
| Execution layer | ブロックを実行し、実行層データを保存する client。この構成では Erigon。 |
| Consensus layer | PoS の beacon chain を追い、fork choice を進める client。この構成では Lighthouse。 |
| Engine API | consensus client と execution client の間で使う認証付き API。よく使う port は 8551。 |
| JWT secret | consensus client が Engine API に接続するための共有 secret file。 |
| authrpc vhost | Erigon が認証 RPC で許可する Host の一覧。JWT が正しくても Host が拒否されることがある。 |
| Checkpoint sync | Lighthouse が最近の finalized checkpoint から起動する同期方式。genesis から追うよりかなり速い。 |
ログが示していたこと
Erigon は外部 consensus layer を使う形で起動していた。
--externalcl
--authrpc.addr=0.0.0.0
--authrpc.port=8551
--authrpc.jwtsecret=/jwt/jwt.hex
この方向自体は合っている。Erigon README では、Gnosis では Erigon と一緒に consensus layer client が必要だと説明されている。また、consensus client が localhost 以外から接続する場合は --authrpc.addr 0.0.0.0 と --authrpc.vhosts <CL host> を設定するよう書かれている [1]。
Lighthouse 側の endpoint は Docker service name を使っていた。
--execution-endpoint http://gnosis:8551
--execution-jwt /jwt/jwt.hex
この request には二つの要素があった。JWT と HTTP Host だ。このケースでは Host が gnosis:8551 になっていた。
まず JWT を疑った
一番ありそうなのは secret file の不一致なので、まず同じ file が見えているか確認した。
sha256sum /data/jwt/jwt.hex
docker exec gnosis sha256sum /jwt/jwt.hex
docker exec gnosis-lighthouse sha256sum /jwt/jwt.hex
host の file、Erigon container の mount、Lighthouse container の mount は一致していた。
さらに同じ secret から一時 JWT を作り、Erigon の engine_exchangeCapabilities を直接呼んだ。この request は HTTP 200 を返した。ここで範囲がかなり狭まった。Erigon は token を検証できるし、Engine API も到達できる。Lighthouse の InvalidToken は、実際には 403 を包んでいた。
Lighthouse の更新で別の問題も見えた
動いていた Lighthouse image が古かったので、floating tag ではなく明示的な version に固定した。
sigp/lighthouse:v8.2.0
v8.2.0 はその時点の current release で、Lighthouse project も high-priority としていた [2]。
この更新で、古い Lighthouse database を開けない問題が出た。
Unable to open database: LoadConfig(ConfigError(InvalidVersionByte(Some(0))))
execution data は Erigon の datadir 側にあり、そこは触っていない。古い Lighthouse datadir は別名で退避し、Gnosis の checkpoint sync を使って Lighthouse を起動し直した。
--checkpoint-sync-url https://checkpoint.gnosischain.com
Gnosis docs はこの checkpoint sync server を案内している。Lighthouse docs でも、checkpoint sync は genesis から同期するより速く、同じ beacon node 機能を提供すると説明されている [3][4]。
もう一つ、古い flag を外す必要があった。新しい Lighthouse では次の組み合わせは使えない。
--checkpoint-sync-url ...
--allow-insecure-genesis-sync
checkpoint sync を使うなら、genesis sync 用の古い flag は不要だった。
接続を直した変更
Lighthouse v8.2.0 が起動しても、まだ次の error が残った。
InvalidToken("HTTP status client error (403 Forbidden) for url (http://gnosis:8551/)")
見る点は 403 Forbidden だった。
Lighthouse の endpoint は http://gnosis:8551。これは Docker network 内の service name だ。Erigon は 0.0.0.0:8551 で listen していたが、authrpc vhost に gnosis が入っていなかった。そこで Erigon の起動引数をこう変えた。
--authrpc.addr=0.0.0.0
--authrpc.port=8551
--authrpc.vhosts=gnosis,localhost,127.0.0.1
--authrpc.jwtsecret=/jwt/jwt.hex
その後、同じ /data/erigon と同じ JWT file を使ったまま、Erigon container だけを再起動した。
最終的な形
Erigon 側:
erigon
--chain=gnosis
--datadir=/data
--externalcl
--authrpc.addr=0.0.0.0
--authrpc.port=8551
--authrpc.vhosts=gnosis,localhost,127.0.0.1
--authrpc.jwtsecret=/jwt/jwt.hex
--prune.mode=archive
Lighthouse 側:
lighthouse bn
--network gnosis
--datadir /data
--execution-endpoint http://gnosis:8551
--execution-jwt /jwt/jwt.hex
--checkpoint-sync-url https://checkpoint.gnosischain.com
確認したこと
Erigon を再起動した後、Erigon のログに次の行が出た。
[GetClientVersionV1] Received request fromClientCode: LH, Lighthouse-v8.2.0...
Lighthouse 側も JWT error ではなく、通常の Engine API flow に変わった。
Execution engine online
Issuing forkchoiceUpdated
Synced ... exec_hash: ... (unverified)
Head is optimistic
直近ログで InvalidToken を数えると 0 だった。
docker logs --since 2m gnosis-lighthouse 2>&1 | grep -c 'InvalidToken'
# 0
この時点の Head is optimistic は問題の切り分けとしては許容できる状態だった。Lighthouse は consensus head に追いついているが、execution layer が対応する payload をまだ検証しきっていない、という意味だ。Erigon 側では Execution stage が進んでいたので、残りは Engine API 認証ではなく execution catch-up だった。
今回の教訓は小さい。Lighthouse が InvalidToken と言っている時も、内側の HTTP status まで見る。Erigon から 403 が返っているなら、JWT file そのものではなく authrpc host allowlist が詰まっていることがある。
参考
[1] Erigon README: Beacon Chain / Consensus Layer
[2] Lighthouse v8.2.0 release notes