Skip to content

Checkpoint + restore a post-init stack to eliminate startup wait during dev #17

Closed

Description

@frrist

Motivation

Current stack startup is dominated by on-chain initialization, not container boot:

  • Each piri node registers with the delegator, registers with the PDP contract, waits for approval, and creates an on-chain data set.
  • Every one of those operations waits ~6 epochs × 3s ≈ 18s minimum.
  • With multiple piri nodes the waits serialize into multiple minutes.

For test iteration this is brutal — per-run stack startup is ~10× the duration of the test itself. The natural urge is "just reuse the stack" (e.g. SMELT_KEEP=1), but that only helps after the first boot of the day and risks state drift across runs.

The better fix is to checkpoint a fully-initialized network once, then resume from that checkpoint on subsequent boots. Startup collapses to container boot time; on-chain init runs zero times.

This is an extension of what we already do with systems/blockchain/state/anvil-state.json (chain + deployed contracts + funded addresses). We widen the snapshot to include post-piri-registration contract state and each service's persistent volume / keys.

Plan

Phase 0 — prerequisite cleanup

The snapshot logic for the PDP contracts currently lives in a shell script in the sibling repo:

That script is doing double duty (init + dump) and is too tangled to extend reliably. Clean it up first: separate init-mode from dump-mode paths, parameterize output location, add tests. Track as a separate issue in filecoin-services (out of scope for this repo, but blocks phase 2).

Phase 1 — manifest + CLI surface

Extend smelt.yml to declare what each service contributes to a checkpoint:

version: 1
piri:
  nodes:
    - storage: { db: sqlite, blob: filesystem }
checkpoint:
  name: default                   # checkpoint ID; multiple checkpoints allowed
  includes:
    - blockchain                  # Anvil state.json (already implemented)
    - piri                        # piri data volumes + keys
    - delegator                   # UCAN store volume
    - indexer                     # indexer state volume

Add cmd/smelt subcommands:

  • smelt snapshot save [--name NAME] — stop the stack, dump anvil state, archive each listed service's volume + keys into generated/snapshots/<name>/, write a manifest descriptor.
  • smelt snapshot load [--name NAME] — restore volumes + keys before compose up, point anvil at the saved state file.
  • smelt snapshot list / smelt snapshot rm NAME — housekeeping.

Phase 2 — integrate with boot

  • make up learns a --from-snapshot=NAME path (or env var) that calls snapshot load before compose up.
  • Piri's entrypoint learns to skip the delegator/contract registration step when it detects a "already registered" marker restored from the snapshot. (This is the piece that actually saves minutes — restoring the volume isn't enough if piri re-runs init.)
  • Document the two intended flows:
    • Cold: make fresh && make up — full init, ~N minutes.
    • Warm: make up --from-snapshot=default — container boot time, seconds.

Phase 3 — Go SDK hook

Extend pkg/stack with WithSnapshot(name string) so e2e tests can opt into snapshot restore for local iteration:

s := stack.MustNewStack(t, stack.WithSnapshot("default"))

CI must not use snapshots (defeats the point — it needs cold-boot coverage). Gate by env var or explicit opt-in; never default.

Out of scope

  • CI using snapshots. Never — CI needs cold-boot coverage and can't rely on dev-produced artifacts.
  • SMELT_KEEP=1-style "reuse the running stack". Orthogonal concern; might be worth a follow-up but this issue is about boot time, not container reuse.
  • Automatic snapshot invalidation when smelt.yml / images / contracts change. Start manual (smelt snapshot rm + re-save). Add staleness detection later if it becomes a footgun.
  • Cross-machine snapshots. Treat snapshots as local to the developer's checkout.

Acceptance criteria

  • smelt snapshot save --name default on a healthy stack produces generated/snapshots/default/ with the chain state, service volumes, and keys.
  • A fresh make clean && make up --from-snapshot=default brings the stack to a "piri registered, ready to upload" state without any on-chain init waits.
  • A smoke test (tests/e2e/smoke_test.go or similar) that normally takes ~3 min to start completes startup in <30s with a snapshot.
  • Docs updated: docs/GETTING_STARTED.md and/or a new docs/SNAPSHOTS.md covering the two flows and how to invalidate.

Prior art referenced

  • systems/blockchain/state/anvil-state.json — existing chain snapshot; this plan generalizes the idea.
  • filecoin-services/service_contracts/localdev/entrypoint.sh — "Mode 2 dump mode"; source of the snapshot primitive for PDP contract state.

Activity

  1. self-assigned this
    on Apr 20, 2026
  2. linked a pull request that will close this issuefeat: stack snapshots for fast dev iteration #18on Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions