Skip to content

mempool.dat reload drops ~2/3 of the mempool: same-second children re-admitted before parents #949

Closed

Description

@bkeroack

Summary

A clean restart loses most of the mempool. load_mempool re-admits mempool.dat records in time order, but time has one-second resolution, and ties keep file order. dump_mempool writes get_all_entries() in map order, which is not parent-first. So a child that shares its parent's second is often tried before the parent. It fails with missing-inputs, and every descendant behind it fails too.

Each restart makes this worse. Re-admission gives the txs it accepts a fresh time, so thousands of them end up in the same few seconds. On the next restart, most parent/child pairs are ties.

Evidence

On a synced mainnet node (0.6.0), over two consecutive clean restarts:

restart persisted re-admitted skipped
1 46,711 15,825 30,886 (66%)
2 36,121 13,799 22,322 (62%)

After restart 2, I parsed the mempool.dat it had loaded and ran each record through testmempoolaccept:

  • 20,030 missing-inputs
  • 19,871 of those have their parent in the same file
  • in 14,959 of those, the parent has the same time as the child
  • no case where the parent's time is later than the child's

The file has 1,935 distinct timestamps for 36,121 records. The largest same-second group is 1,883 txs, all stamped during restart 1's re-admission.

Nothing in the log shows this, because load_mempool discards the error (Err(_) => stats.skipped += 1). The only trace is the skipped= count.

Expected

Like Bitcoin Core, a restart should keep everything that is still valid. Core avoids this by writing mempool.dat in topological (depth) order.

Suggested fix

  • Write parents first in dump_mempool (topological / ancestor-count order), and/or have load_mempool order ties by in-file parent dependency. A retry pass for missing-inputs would also work, but costs more.
  • Keep each tx's original admission time on reload instead of stamping the reload time, so time stays meaningful (and so does mempool expiry).
  • Log or count skip reasons so a regression like this shows up in the log.
  • Test: a chain where the child has the same time as the parent and is written before it in the file must reload completely.

Activity

  1. added this to the 0.6.x milestone on Oct 9, 2026
  2. added a commit that references this issue on Oct 14, 2026
    1899cf2
  3. bkeroack commented on Oct 14, 2026

    @bkeroack
    ContributorAuthor

    Fixed on release/0.6 by #960 (1899cf2); ships in 0.6.1. Forward-port to master pending.

  4. added a commit that references this issue on Oct 15, 2026
    d5e3b6d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions