malcom moves chain state between machines over an untrusted P2P network. The integrity of every artifact depends on understanding which checks prove what.
The malcom snapshot fetch peer set is untrusted. A peer may
withhold chunks, return garbage, or fabricate an entire snapshot
covering a fake chain history. Any node ID can be generated for
free; do not assume "the peer claimed to be X" means anything.
The application.db produced by malcom snapshot import is
trusted only after malcom verify succeeds against a trusted
RPC.
Every cosmos-sdk snapshot carries a Metadata blob with one
SHA-256 per chunk. malcom snapshot fetch recomputes each chunk's
hash and compares it against the peer's advertised value before
writing the chunk to disk. A mismatch aborts the fetch.
This proves: the bytes on disk are byte-identical to what the peer's snapshot offer advertised.
This does not prove:
- That the snapshot reflects the real chain state at that height.
- That the peer is honest.
- That the snapshot was generated by a node that was ever in consensus with the rest of the network.
A malicious peer can construct a self-consistent fake snapshot: a
set of chunks whose hashes match its advertised Metadata, whose
overall hash matches its advertised SnapshotsResponse.Hash, and
whose payload encodes anything — modified balances, omitted
transactions, fabricated validator sets. Every per-chunk check
passes. The fetcher cannot tell the difference.
malcom verify is the trust anchor for an imported snapshot. It:
- Reads
CommitInfofrom the importedapplication.dbat the snapshot height (the same struct cosmos-sdk'sBeginBlockerreads). - Computes the consensus
AppHashlocally from that CommitInfo. - Fetches the real
AppHashforheight+1from an operator-supplied RPC (or set of RPCs), which means it comes from a block header that consensus already agreed on. - Compares the two. A match means the imported state is bit-identical to what every honest validator agreed the state should be at that height.
This depends entirely on the RPC being a node the operator trusts.
A compromised RPC plus a compromised snapshot peer plus matching
forged AppHash would defeat verify. Mitigate by passing multiple
independent RPCs to --rpc-list; verify takes the first one
that responds with a usable AppHash but the diagnostic logs which
one, so cross-check across runs.
- Always run
malcom verifybefore using an imported snapshot in production. Skipping verify means trusting your peers, which is the wrong default. - Use multiple independent RPCs in the verify step. A single RPC is a single point of compromise.
- Treat the
malcom snapshot servepeer set as adversarial. Rate limits (ChunkRatePerPeer,GlobalRate) bound the damage a hostile peer can do; they don't make any peer trustworthy.
- A consensus-level attack on the chain being snapshotted (51%, long-range, etc.). Those compromise the AppHash itself, so even verify can't help.
- An attacker who controls both your snapshot peer and your verify RPC. The two-source design forces an attacker to compromise independent infrastructure; it doesn't make compromise impossible.
- Side-channel attacks on the host (disk corruption beyond what fsync covers, RAM bitflips, etc.). Out of scope.