ASSET-only — zero-gravity/scripts/init.sh. Script-only, so no ./update.sh and no gitlink change.
Symptom
aristotle @ rpc-de-32 crash-loops. show-status reports it as syncing, which is wrong — the CL never starts:
priv_validator_state.json found in /root/.0g. Continuing!
Already initialized, continuing!
panic: error calling provider ProvideBlsSigner (node-core/components/signer.go:46):
key file does not exist at path: /root/.0g/config/priv_validator_key.json
The EL is a casualty, not the cause — it sits at peercount=0 with zero engine traffic because nothing is driving it.
Root cause: cross-volume inference, plus a write order that latches the failure
$DATA_DIR and $CONFIG_DIR are separate docker volumes (<node>_zerog → /root/.0g/data, <node>_config → /root/.0g/config). The guard tested only:
— inferring the state of the config volume from a file on the data volume. And the copies wrote that guard file before the keys:
cp .../priv_validator_state.json $DATA_DIR# 2 <- guard file
cp .../node_key.json $CONFIG_DIR# 3
cp .../priv_validator_key.json $CONFIG_DIR# 4 <- the file that panics when absent
So an init interrupted between (2) and (4) leaves the guard file present and the keys missing. Every subsequent start takes the Already initialized branch, copies nothing, and panics.
Unrecoverable by restarting — the node wedges permanently. aristotle reached that state via the repeated build failures earlier today (see #61, #63).
This is latent for every 0g node. galileo escaped only because its init happened to complete uninterrupted.
Fix
Guard on everything 0gchaind needs to boot — both config keys and the data state file — instead of one proxy file on the wrong volume.
Write the keys first and the guard file last, so an interrupted init re-runs on the next start rather than latching.
Tested locally against the real binary
Not reasoned about — reproduced. aristotle-v1.0.6's actual 0gchaind (version → e8e1071) runs on the controller, so the matrix ran the real 0gchaind init with a sandboxed HOME_DIR:
scenario
before
after
fresh volumes
keys created
keys created — no regression
wedged (state, no keys)
keys MISSING, Already initialized
keys created, identity incomplete → initializing
partial (state + node_key only)
keys MISSING
keys created
healthy (all present)
no re-init
no re-init
The wedged row reproduces aristotle's production panic exactly, and the fix clears it.
Non-destructiveness was tested explicitly rather than assumed: in the healthy case a SENTINEL written into priv_validator_key.jsonsurvives the run, so the fix can never clobber an already-initialized node. sh -n clean; the geth branch is untouched.
Caveat worth stating
On an affected node this regenerates node_key.json and priv_validator_key.json. On a validator that would matter — these are RPC nodes that never sign, so a fresh identity is harmless, and chain data on the _zerog volume is untouched.
After merge
aristotle needs a force-recreate on de-32 to re-run init and populate the keys. galileo is unaffected and currently syncing normally (height ~7.1k of 49.07M).
Related: #61 (download fails loudly), #63 (extraction fails loudly). This one is the same theme a step later — a guard that silently skipped the work it was guarding.
**ASSET-only** — `zero-gravity/scripts/init.sh`. Script-only, so no `./update.sh` and no gitlink change.
## Symptom
aristotle @ rpc-de-32 crash-loops. `show-status` reports it as `syncing`, which is wrong — the CL never starts:
```
priv_validator_state.json found in /root/.0g. Continuing!
Already initialized, continuing!
panic: error calling provider ProvideBlsSigner (node-core/components/signer.go:46):
key file does not exist at path: /root/.0g/config/priv_validator_key.json
```
The EL is a casualty, not the cause — it sits at `peercount=0` with zero engine traffic because nothing is driving it.
## Root cause: cross-volume inference, plus a write order that latches the failure
`$DATA_DIR` and `$CONFIG_DIR` are **separate docker volumes** (`<node>_zerog` → `/root/.0g/data`, `<node>_config` → `/root/.0g/config`). The guard tested only:
```sh
if [ ! -f "$DATA_DIR/priv_validator_state.json" ]; then
```
— inferring the state of the **config** volume from a file on the **data** volume. And the copies wrote that guard file *before* the keys:
```sh
cp .../priv_validator_state.json $DATA_DIR # 2 <- guard file
cp .../node_key.json $CONFIG_DIR # 3
cp .../priv_validator_key.json $CONFIG_DIR # 4 <- the file that panics when absent
```
So an init interrupted between (2) and (4) leaves the guard file present and the keys missing. Every subsequent start takes the `Already initialized` branch, **copies nothing**, and panics.
**Unrecoverable by restarting — the node wedges permanently.** aristotle reached that state via the repeated build failures earlier today (see #61, #63).
This is latent for **every** 0g node. galileo escaped only because its init happened to complete uninterrupted.
## Fix
1. **Guard on everything `0gchaind` needs to boot** — both config keys *and* the data state file — instead of one proxy file on the wrong volume.
2. **Write the keys first and the guard file last**, so an interrupted init re-runs on the next start rather than latching.
## Tested locally against the real binary
Not reasoned about — reproduced. `aristotle-v1.0.6`'s actual `0gchaind` (`version` → `e8e1071`) runs on the controller, so the matrix ran the real `0gchaind init` with a sandboxed `HOME_DIR`:
| scenario | before | after |
|---|---|---|
| fresh volumes | keys created | keys created — **no regression** |
| **wedged** (state, no keys) | **keys MISSING**, `Already initialized` | **keys created**, `identity incomplete → initializing` |
| partial (state + node_key only) | keys MISSING | keys created |
| healthy (all present) | no re-init | no re-init |
The **wedged** row reproduces aristotle's production panic exactly, and the fix clears it.
Non-destructiveness was tested explicitly rather than assumed: in the healthy case a `SENTINEL` written into `priv_validator_key.json` **survives** the run, so the fix can never clobber an already-initialized node. `sh -n` clean; the `geth` branch is untouched.
## Caveat worth stating
On an affected node this regenerates `node_key.json` and `priv_validator_key.json`. On a **validator** that would matter — these are RPC nodes that never sign, so a fresh identity is harmless, and chain data on the `_zerog` volume is untouched.
## After merge
aristotle needs a `force-recreate` on de-32 to re-run init and populate the keys. galileo is unaffected and currently syncing normally (height ~7.1k of 49.07M).
Related: **#61** (download fails loudly), **#63** (extraction fails loudly). This one is the same theme a step later — a guard that silently skipped the work it was guarding.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
aristotle @ rpc-de-32 crash-looped after its build was fixed:
priv_validator_state.json found in /root/.0g. Continuing!
Already initialized, continuing!
panic: ProvideBlsSigner (node-core/components/signer.go:46):
key file does not exist at path: /root/.0g/config/priv_validator_key.json
$DATA_DIR and $CONFIG_DIR are SEPARATE docker volumes (<node>_zerog and
<node>_config), but the guard tested only $DATA_DIR/priv_validator_state.json —
inferring the state of the config volume from a file on the data volume. Worse, the
copy order wrote that guard file BEFORE the two key files, so an init interrupted
between them left the data volume with the guard and the config volume without the
keys. Every later start then took the 'Already initialized' branch, copied nothing,
and panicked. Unrecoverable by restarting: the node wedges permanently. aristotle
got there via the repeated build failures earlier today.
Fix, two parts:
- guard on everything 0gchaind needs to boot (both config keys AND the data state
file), not one proxy file on the wrong volume;
- write the keys FIRST and the guard file LAST, so an interrupted init re-runs on
the next start instead of latching into the wedged state.
Tested locally against the real 0gchaind binary (aristotle v1.0.6), sandboxed HOME:
scenario before after
fresh volumes keys created keys created (no regression)
wedged (state, no keys) keys MISSING keys created (unwedges)
partial (state+node_key) keys MISSING keys created
healthy (all present) no re-init no re-init, and a SENTINEL written
into priv_validator_key.json survives
-> never clobbers an initialized node
The 'wedged' row reproduces aristotle's production failure exactly.
Note this regenerates node identity on an affected node (node_key.json,
priv_validator_key.json). These are RPC nodes that never sign, so a fresh identity is
harmless; chain data on the _zerog volume is untouched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
claude
manually merged commit 92cdb31d17 into main2026-08-12 19:37:52 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
ASSET-only —
zero-gravity/scripts/init.sh. Script-only, so no./update.shand no gitlink change.Symptom
aristotle @ rpc-de-32 crash-loops.
show-statusreports it assyncing, which is wrong — the CL never starts:The EL is a casualty, not the cause — it sits at
peercount=0with zero engine traffic because nothing is driving it.Root cause: cross-volume inference, plus a write order that latches the failure
$DATA_DIRand$CONFIG_DIRare separate docker volumes (<node>_zerog→/root/.0g/data,<node>_config→/root/.0g/config). The guard tested only:— inferring the state of the config volume from a file on the data volume. And the copies wrote that guard file before the keys:
So an init interrupted between (2) and (4) leaves the guard file present and the keys missing. Every subsequent start takes the
Already initializedbranch, copies nothing, and panics.Unrecoverable by restarting — the node wedges permanently. aristotle reached that state via the repeated build failures earlier today (see #61, #63).
This is latent for every 0g node. galileo escaped only because its init happened to complete uninterrupted.
Fix
0gchaindneeds to boot — both config keys and the data state file — instead of one proxy file on the wrong volume.Tested locally against the real binary
Not reasoned about — reproduced.
aristotle-v1.0.6's actual0gchaind(version→e8e1071) runs on the controller, so the matrix ran the real0gchaind initwith a sandboxedHOME_DIR:Already initializedidentity incomplete → initializingThe wedged row reproduces aristotle's production panic exactly, and the fix clears it.
Non-destructiveness was tested explicitly rather than assumed: in the healthy case a
SENTINELwritten intopriv_validator_key.jsonsurvives the run, so the fix can never clobber an already-initialized node.sh -nclean; thegethbranch is untouched.Caveat worth stating
On an affected node this regenerates
node_key.jsonandpriv_validator_key.json. On a validator that would matter — these are RPC nodes that never sign, so a fresh identity is harmless, and chain data on the_zerogvolume is untouched.After merge
aristotle needs a
force-recreateon de-32 to re-run init and populate the keys. galileo is unaffected and currently syncing normally (height ~7.1k of 49.07M).Related: #61 (download fails loudly), #63 (extraction fails loudly). This one is the same theme a step later — a guard that silently skipped the work it was guarding.
🤖 Generated with Claude Code
aristotle @ rpc-de-32 crash-looped after its build was fixed: priv_validator_state.json found in /root/.0g. Continuing! Already initialized, continuing! panic: ProvideBlsSigner (node-core/components/signer.go:46): key file does not exist at path: /root/.0g/config/priv_validator_key.json $DATA_DIR and $CONFIG_DIR are SEPARATE docker volumes (<node>_zerog and <node>_config), but the guard tested only $DATA_DIR/priv_validator_state.json — inferring the state of the config volume from a file on the data volume. Worse, the copy order wrote that guard file BEFORE the two key files, so an init interrupted between them left the data volume with the guard and the config volume without the keys. Every later start then took the 'Already initialized' branch, copied nothing, and panicked. Unrecoverable by restarting: the node wedges permanently. aristotle got there via the repeated build failures earlier today. Fix, two parts: - guard on everything 0gchaind needs to boot (both config keys AND the data state file), not one proxy file on the wrong volume; - write the keys FIRST and the guard file LAST, so an interrupted init re-runs on the next start instead of latching into the wedged state. Tested locally against the real 0gchaind binary (aristotle v1.0.6), sandboxed HOME: scenario before after fresh volumes keys created keys created (no regression) wedged (state, no keys) keys MISSING keys created (unwedges) partial (state+node_key) keys MISSING keys created healthy (all present) no re-init no re-init, and a SENTINEL written into priv_validator_key.json survives -> never clobbers an initialized node The 'wedged' row reproduces aristotle's production failure exactly. Note this regenerates node identity on an affected node (node_key.json, priv_validator_key.json). These are RPC nodes that never sign, so a fresh identity is harmless; chain data on the _zerog volume is untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>