> ## Documentation Index
> Fetch the complete documentation index at: https://docs.unitynodes.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cosmos Hub Mainnet snapshot

export const SnapshotPicker = ({network}) => {
  const origin = "https://snapshots.unitynodes.com";
  const frame = useRef(null);
  const [height, setHeight] = useState(580);
  const sendTheme = () => {
    const win = frame.current && frame.current.contentWindow;
    const theme = document.documentElement.classList.contains("dark") ? "dark" : "light";
    if (win) win.postMessage({
      type: "unitynodes:theme",
      theme
    }, origin);
  };
  useEffect(() => {
    const onMessage = event => {
      if (event.origin !== origin || !frame.current || event.source !== frame.current.contentWindow) return;
      const data = event.data || ({});
      if (data.type === "unitynodes:height" && data.height > 100 && data.height < 4000) setHeight(Math.ceil(data.height));
      if (data.type === "unitynodes:ready") sendTheme();
    };
    window.addEventListener("message", onMessage);
    const observer = new MutationObserver(sendTheme);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    sendTheme();
    return () => {
      window.removeEventListener("message", onMessage);
      observer.disconnect();
    };
  }, []);
  return <iframe ref={frame} src={`${origin}/${network}/widget.html`} title="Snapshot picker" width="100%" allow="clipboard-write" onLoad={sendTheme} style={{
    height: `${height}px`,
    border: "none",
    background: "transparent",
    display: "block",
    borderRadius: "14px"
  }} />;
};

**Cosmos Hub Snapshots, provided by Unity Nodes.**

Bootstrap a Cosmos Hub `cosmoshub-4` mainnet node in minutes instead of a multi-day full sync, in
**goleveldb** or **pebbledb**. Pick the database and the variant below - the table and the command
update together, so you always see exactly what you are about to download.

<SnapshotPicker network="cosmos-mainnet" />

<Warning>
  Do not skip the `priv_validator_state.json` backup step in the command. That file records the
  last height and round your validator signed. Restoring somebody else's signing state - or an
  older copy of your own - is the classic way to double-sign and get slashed.

  The command stops at the first step that fails, so a failed or cut download never restarts `gaiad`
  on a partial `data/`. Your signing state then stays in `~/.gaia/priv_validator_state.json.backup`:
  fix the cause and run the command again starting from the `rm -rf` line.
</Warning>

<Note>
  A pebbledb snapshot needs **both** backend settings switched before the node starts - `db_backend`
  in `config.toml` and `app-db-backend` in `app.toml`. The pebbledb command in the picker above does it for you.
  Because the restore replaces the whole `data/` folder, this is also how you move an existing
  goleveldb node to pebbledb.
</Note>

## What's inside

* `data/` folder from a live Cosmos Hub (`cosmoshub-4`) `gaiad` full node with pruning (`custom` / `keep-recent=100` / `interval=19`).
* `wasm/state` - the CosmWasm **contract bytecode**. `x/wasm` keeps only the code hashes in
  `application.db` and the bytecode itself on disk, so a `data/`-only archive restores a node
  that cannot execute contracts. It is bundled here so the snapshot is self-sufficient.
  `wasm/cache` is deliberately left out: it is a compiled, machine-specific cache your node
  rebuilds by itself.

Full archive listing: [snapshots.unitynodes.com/cosmos-mainnet/](https://snapshots.unitynodes.com/cosmos-mainnet/)

| Variant          | Taken at                         | Use it when                                                                                                                           |
| ---------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| **Latest**       | every 4 hours                    | normal bootstrap of a node                                                                                                            |
| **Pre-upgrade**  | `H-1`, taken at the upgrade halt | you want to apply the upgrade yourself. Start it on the NEW binary for that upgrade: it applies the upgrade at the halt height        |
| **Post-upgrade** | shortly after the upgrade height | you are joining after an upgrade and want migrated state with no upgrade handling at all. Start it on the NEW binary for that upgrade |
| **Wasm only**    | same cadence as Latest           | your node is already synced and you only need the CosmWasm contract bytecode                                                          |

## Compatible software and settings

| What                          | Setting                                                                                                                                                                                                                                                                                         |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Binary**                    | the `gaiad` version the snapshot was taken on, or newer. Every archive carries a `.txt` sidecar with the exact `node_version` it was produced by (currently `v28.2.0`). An older binary can refuse to start if the state has already been migrated by an upgrade the binary does not know about |
| **Pre/post-upgrade archives** | start them on the **new** binary for that upgrade. The `.txt` sidecar names it in `restore_binary`                                                                                                                                                                                              |
| **goleveldb archive**         | default settings, nothing to change                                                                                                                                                                                                                                                             |
| **pebbledb archive**          | set `db_backend = "pebbledb"` in `config.toml` **and** `app-db-backend = "pebbledb"` in `app.toml` before the first start                                                                                                                                                                       |
| **Pruning in the archive**    | `custom`, `keep-recent=100`, `interval=19`                                                                                                                                                                                                                                                      |

## File names

Each archive is published under a name carrying the chain ID, database backend, block height and
UTC creation time, with a matching `.sha256` and `.txt` next to it:

```
cosmoshub-4_pebbledb_33052362_20260920T051157Z.tar.lz4
cosmoshub-4_goleveldb_33052362_20260920T044334Z.tar.lz4
```

`latest.tar.lz4` and `latest-pebbledb.tar.lz4` always point at the newest of each, so scripts can
use a stable URL. Downloads support HTTP range requests, so `aria2c -x8` and resumed `curl -C -`
both work.

## Verify the download

```bash theme={null}
curl -fsSL -o snapshot.sha256 https://snapshots.unitynodes.com/cosmos-mainnet/latest.tar.lz4.sha256 && \
F=$(awk '{print $2}' snapshot.sha256) && \
curl -fL -o "$F" "https://snapshots.unitynodes.com/cosmos-mainnet/$F" && \
sha256sum -c snapshot.sha256
```

The `.sha256` file is fetched first: it names the dated archive it belongs to, so the file you download is
always the one the checksum is for, even if a new snapshot is published during a long download. The last line should read `<archive name>: OK`.
For pebbledb fetch `latest-pebbledb.tar.lz4.sha256` instead.

To restore from the verified file rather than streaming it, use `lz4 -dc "$F"` in place of
`curl -fL <url> | lz4 -dc -` in the picker command.

## FAQ

<AccordionGroup>
  <Accordion title="How often is the snapshot updated?">
    goleveldb every **4 hours**; the pebbledb snapshot for the same height follows about
    **30 minutes** later. The last 2 of each are kept online.
  </Accordion>

  <Accordion title="What db backend?">
    Both. `goleveldb` and `pebbledb`, always at the same height.
  </Accordion>

  <Accordion title="How is the pebbledb snapshot produced?">
    It is converted from the goleveldb snapshot of the same height with
    [pebblify](https://github.com/Dockermint/pebblify), using the same pebble library version
    `gaiad` itself uses. Before anything is published, every key and value of the converted database
    is compared against the goleveldb original; a single mismatch stops the release.
  </Accordion>

  <Accordion title="Can I use this to bootstrap a validator?">
    Yes. The tarball carries only `data/` and `wasm/state`. There is no `config/` directory in
    it, so no `priv_validator_key.json`, no `node_key.json` and no keyring - your identity files
    are never overwritten by a restore.
  </Accordion>

  <Accordion title="Do I need to download the wasm archive separately?">
    No. `wasm/state` is already inside the snapshots above, so a single download gives you a
    node that can execute contracts. The standalone `wasm.tar.lz4` exists only for topping up a
    node that is already synced.
  </Accordion>

  <Accordion title="Is the node stopped while the snapshot is taken?">
    Yes, briefly. The goleveldb archive is a cold tar taken with `gaiad` stopped, so the database is
    never copied mid-write. The pebbledb conversion works on that finished archive and never touches
    the running node.
  </Accordion>

  <Accordion title="My pebbledb node prints `panic: pebble: closed` when I stop it. Is my data damaged?">
    No. On `gaiad` v28 with pebbledb, IAVL's background pruning can still be reading when the database is
    closed during shutdown, and pebble reports that as a panic where goleveldb would just return an error.
    It happens after the last block is already committed. We reproduced it on our own pebbledb node and
    restarted from the same data: the node reopened in 20 seconds and kept producing app hashes identical
    to independent public RPCs.
  </Accordion>
</AccordionGroup>

## Status and support

The service is monitored around the clock: snapshot freshness, archive size, the pebbledb conversion
and public reachability of every download URL all raise alerts on two independent monitoring hosts.

If a snapshot looks stale, a download fails or a checksum does not match, write to
[contact@unitynodes.com](mailto:contact@unitynodes.com). Include the file name you were fetching
and the error. We answer with what happened and when it will be fixed.
