Coin Brief ENDE

rippled merges parts 4–9 of a 28-part stack hardening ledger acquisition against bad data

The XRP Ledger server rippled merged six pull requests on 15 and 16 October 2026 that form parts 4 to 9 of a 28-part stack on how a node acquires ledgers from local storage and from peers, and what it does when the data it receives cannot belong to the ledger it asked for. The branch names in the stack carry the prefix bthomee/shamap-invalid. Each pull request states its own scope; together they introduce and enforce a single verdict: a map that has been proven invalid stays invalid.

Failing fast instead of timing out (#8082, part 4). When tryDB() finds a header that can never be satisfied — a hash or sequence that does not match the request, or a zero account hash — the acquisition already set a failed flag, but on two of three entry points nothing was told. Now init() and trigger() call done(), so whatever waits on the acquisition is signalled and the hash is recorded in recentFailures_; the pull request says this is what stops the next round from asking for the same doomed ledger instead of leaving it to run out the clock.

Zero account hash, judged on both routes (#8476, part 5). No ledger has an empty state map, so a header with a zero account hash cannot name a ledger. InboundLedger now rejects it the same way whether the header comes from the local database or from a peer, through one helper, before any header state is published. In the peer case the header is treated as the one requested and the peer is not blamed.

Data races on the sync path (#8083, part 6). Four fields that a background ledger-acquisition thread reads and writes concurrently with the thread driving it — state_, full_, ledgerSeq_ and fullBelowGen_ — become std::atomic. The pull request says this closes races that ThreadSanitizer can observe today, and static assertions keep the packed layout of SHAMapInnerNode byte-identical.

rippled merges parts 4–9 of a 28-part stack hardening ledger acquisition against bad data
rippled merges parts 4–9 of a 28-part stack hardening ledger acquisition against bad data — Coin Brief

Calling bad data bad (#8084, part 7). SHAMap::addKnownNode() now reports invalid() rather than merely "not useful" for two nodes that prove the requested root hash is impossible: an inner node at the depth only a leaf may occupy, and a node whose ID does not match where the descent stopped. The depth check moves ahead of the full-below cache, which is keyed by hash and shared across maps, so an unrelated map's cached entry cannot overturn the verdict.

No immutable invalid ledgers (#8085, part 8). SHAMap::setImmutable() and Ledger::setImmutable()/setAccepted() now return a [[nodiscard]] bool and refuse to succeed on a map or ledger already proven invalid; all 14 call sites were updated to branch on the result. State changes go through a compare-exchange that refuses to leave Invalid. The author notes the guard is best-effort: a walk that reaches the verdict after both maps are settled narrows the window rather than closing it.

Stopping the walk (#8086, part 9). SHAMap::getMissingNodes() now marks the map invalid and abandons the descent when it reaches a leaf-only position, and callers must re-check isValid() before reading an empty result as "nothing left to fetch". The same pull request adds per-sanitizer compile defines (XRPL_ASAN, XRPL_TSAN, XRPL_UBSAN).

Each part describes itself as an internal correctness change; part 4 states explicitly that it has no libxrpl, public-API or peer-protocol impact.

Source: XRPLF/rippled pull requests #8082, #8476, #8083, #8084, #8085 and #8086 — https://github.com/XRPLF/rippled/pull/8085

Primary source
rippled (GitHub)
https://github.com/XRPLF/rippled/pull/8085