snapshot
Produces a consistent snapshot of the node's state at the current block. Two modes selected by the request body: stream the snapshot back as a gzipped tar response (operator path), or write it to a destination directory on the node's filesystem (zero-downtime upgrade-controller path).
Method: POST /snapshot
Authentication: required. Send the operator token in either header:
Authorization: Bearer <token>
X-Admin-Auth: <token>The token is the value of GENLAYERNODE_NODE_OPERATOR_TOKEN on the node process. When that variable is unset, the endpoint returns 401 to every caller regardless of header value (default-deny). The other ops routes (/metrics, /health, /balance) are unaffected and remain public.
Network exposure: the ops server is intended for in-host or in-cluster access (Prometheus scraping /metrics, k8s probes hitting /health). The endpoint may not be reachable from outside the host depending on the deployment's firewall. The recommended operator workflow is therefore one of:
- SSH onto the node and call the endpoint via
127.0.0.1:9153, or - Open an SSH tunnel from the operator workstation to the node (
ssh -L 9153:127.0.0.1:9153 <node>) and calllocalhost:9153through it.
Parameters:
-
scope(string, optional): Which stores the archive carries —all(default),genvmorops. An absent scope meansall, so a caller written before the store split keeps its behaviour. An unrecognised value is rejected with400.Scope Contents Portable between nodes allboth stores, operation store first No genvmchain-derived history only Yes opsthis node's consensus record only No Only
genvmmay be given to another operator.allandopscarry the vote salts this node generated and the nonce ownership of its operator key; restoring either onto a different node would make that node act on votes it never cast and nonce slots it never signed. The node refuses to start against an operation store stamped with another operator, but that guard runs at startup, not at copy time — treat a non-portable archive accordingly.Every archive carries a
snapshot.jsonmanifest recording the format version, the scopes inside, the rollup block the GenVM store was captured at, and — forallandops— the operator address that produced it.Manifest version remains
1.finalizedRootcontains a0x-prefixed, 32-byte chain-trie proof. The cursor and root are read from the completed GenVM checkpoint opened read-only, so they describe the archived files even while live replay advances. An absent root is unavailable, not a zero root. For a pristine empty store, the empty root isKeccak256(0x000000), the proof of an empty root branch. Replay from genesis maintains the finalized trie, including an empty root before any finalization. Every GenVM snapshot past genesis has this field unless its datadir predates root maintenance. Such datadirs require a resync from genesis to obtain roots; continuing replay or restoring their snapshots does not reconstruct missing history.The trie maps each address to the storage root of its latest finalized transaction with a storage effect. Only canonical replay finalization updates it, identically on full nodes and validators. A failed execution, a decision without storage state, or a successful execution whose proof equals its predecessor leaves the entry unchanged (and does not insert an absent address). A first empty storage generation also leaves the entry absent. Storage and root writes share one reversible batch, so a canonical reorg rolls both back. Speculative execution, acceptance and appeals do not update this root.
-
destDir(string, optional): Absolute path on the node's filesystem, which must resolve to a location inside the configured snapshot directory (node.admin.snapshot_dir, default<datadir>/snapshots). When set, switches to write-to-path mode; when omitted or empty, the snapshot is streamed back asapplication/gzip. Paths outside the snapshot directory are rejected with400.
Returns:
- Stream mode (
destDiromitted): gzipped tar archive in the response body,Content-Type: application/gzip. - Write-to-path mode (
destDirset): empty body,204 No Content.
Example Request — Stream Mode (operator):
On the node (after ssh <node>):
curl -X POST http://127.0.0.1:9153/snapshot \
-H "X-Admin-Auth: $GENLAYERNODE_NODE_OPERATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{}' \
-o snapshot.tar.gzOr via SSH tunnel from a workstation (forwards 9153 to the node's loopback):
ssh -L 9153:127.0.0.1:9153 -N <node> &
curl -X POST http://localhost:9153/snapshot \
-H "X-Admin-Auth: $GENLAYERNODE_NODE_OPERATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{}' \
-o snapshot.tar.gzThe response body is a stream — curl can write it to a file (as above) or pipe it through any tool that reads stdin, without staging on local disk.
Example Response — Stream Mode:
HTTP/1.1 200 OK
Content-Type: application/gzip
Content-Disposition: attachment; filename="snapshot.tar.gz"
<gzipped tar archive of the snapshot's files>Example Request — Write-to-Path Mode (upgrade controller):
curl -X POST http://127.0.0.1:9153/snapshot \
-H "X-Admin-Auth: $GENLAYERNODE_NODE_OPERATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"destDir": "/var/lib/genlayer/data/node/snapshots/bradbury-100"}'Take only the portable half, to hand to another operator:
curl -sS -X POST http://localhost:9153/snapshot \
-H "Authorization: Bearer $OPERATOR_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"scope": "genvm"}' -o genvm-snapshot.tar.gzExample Response — Write-to-Path Mode:
HTTP/1.1 204 No ContentHTTP Status Codes:
200 OK: Stream mode succeeded; body carries the gzipped tar archive.204 No Content: Write-to-path mode succeeded; snapshot is on disk atdestDir.400 Bad Request:destDiris not absolute, resolves outside the configured snapshot directory, or already exists.401 Unauthorized: Missing, invalid, or empty operator token (also returned whenGENLAYERNODE_NODE_OPERATOR_TOKENis unset on the node).500 Internal Server Error: Snapshot creation failed (e.g., disk full, DB checkpoint error).
Notes:
- A snapshot may be several GB. In stream mode the connection stays open for the duration of the snapshot — configure reverse proxies / load balancers with adequate read timeouts and disable response buffering.
- In stream mode, a dropped connection leaves no on-disk artifact on the node; retry the request from scratch.
- In write-to-path mode,
destDirmust be an absolute path that does not yet exist and that resolves (afterfilepath.Clean) to a location inside the configured snapshot directory; the node creates it. Paths that escape the directory via..or point elsewhere on the filesystem are rejected with400. This bounds where an operator-token holder can write a checkpoint — still treat the operator token as a credential that can write under the node user's filesystem permissions within that directory. - Snapshot directory (
node.admin.snapshot_dir): bounds write-to-path mode. A relative value resolves underdatadir(so the defaultsnapshotsis<datadir>/snapshots); an absolute value is used as-is, letting a node target a dedicated disk. The node creates the directory with0700permissions on first use if it does not exist. - Docker deploys: in write-to-path mode,
destDir(and the snapshot directory) is resolved inside the node container's filesystem, not on the host. The default<datadir>/snapshotsfalls under whatever volume the deployment mounts fordatadir, so it is host-reachable wherever that volume maps. To use a different location, setsnapshot_dirto a path that is itself volume-mapped identically on both sides, or stick with stream mode. Stream mode is unaffected — the response body is sent over HTTP regardless of where the node runs. - The snapshot includes the full chain database (SSTables, MANIFEST, WAL) at the moment of capture. Treat the artifact as sensitive — anyone holding it can reconstruct the node's state.
- Token comparison is constant-time and length-padded so neither the value nor the length of the secret can be inferred from response timing.
- Rotation: update
GENLAYERNODE_NODE_OPERATOR_TOKENand restart the node. Tokens are read once at startup and not hot-reloaded.
Restore A Portable Snapshot:
genlayernode snapshot restore genvm-snapshot.tar.gz --datadir /var/lib/genlayer/restored
# An extracted snapshot directory is also accepted
genlayernode run --config /path/to/network.yaml --config /path/to/restore-overlay.yamlThe overlay sets datadir: /var/lib/genlayer/restored and keeps the default
node.genvmdb: genvm.db and node.opsdb: ops.db. Use the source deployment's
network configuration; the manifest does not identify the network. The restore
command requires an absent or empty datadir, validates version 1 and exactly
scope=genvm, checks the manifest cursor and any roots against the checkpoint,
and installs the files at <datadir>/genvm.db. It refuses links, unexpected
archive entries, and nonportable scopes. It creates no operation store; normal
startup creates a fresh ops.db and resumes replay at the durable cursor + 1.
Archives are trusted local input with no extraction size cap. Written files and
directories are fsynced before installation, and the datadir is fsynced before
and after the rename.
Non-default node.genvmdb paths are not supported by restore. A rootless snapshot
with a non-zero cursor is accepted with a CLI warning: the restored node will not
maintain roots and needs a resync from genesis for root comparisons.
To capture an exact replay boundary, run in full mode with
consensus.sync_halt_block set to the target block and wait for
genlayer_node_sync_halted == 1 before requesting the snapshot. See the
configuration guide
for halt health and restart semantics. Restore verifies the checkpoint's
metadata, not the correctness of its historical execution. Compare snapshots
captured at the same halt block with sync-check.sh --expect-root or
--reference-snapshot; restoring at N and replaying to M preserves the same
finalized root as replaying from genesis to M.
sync-check.sh --network bradbury --checkpoint N --checkpoint M --halt-at H
captures an ascending chain on one datadir, saving snapshots/<block>.tar.gz
and .json under its work directory. Every output requires a finalized root.
--reference-dir <dir> compares available <block>.tar.gz references and
checkpoints.json records each halt, including mismatches before exit 4.
Without --halt-at, the final segment reaches its boot head; the timeout covers
all segments. --config overrides network defaults, and --genvm-root selects
the GenVM directory. The Task equivalent uses NETWORK, comma-separated
CHECKPOINTS, HALT_AT, REFERENCE_DIR, and GENVM_ROOT.
Forward-compatibility note: when the zero-downtime upgrade controller (Phase 3) lands, /snapshot will additionally accept a second role (upgrade) so the controller can drive the snapshot + stop + start sequence with its own credential. The operator-token path documented here remains the same — no migration is required for operator tooling.
cURL Example with Bearer header:
curl -X POST http://127.0.0.1:9153/snapshot \
-H "Authorization: Bearer $GENLAYERNODE_NODE_OPERATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{}' \
-o snapshot.tar.gz