Skip to content

fix: Stop a ledger built from a header from claiming to be immutable - #8089

Open
bthomee wants to merge 1 commit into
bthomee/shamap-invalid-09-settle-before-completefrom
bthomee/shamap-invalid-10-header-ledger-mutable
Open

fix: Stop a ledger built from a header from claiming to be immutable#8089
bthomee wants to merge 1 commit into
bthomee/shamap-invalid-09-settle-before-completefrom
bthomee/shamap-invalid-10-header-ledger-mutable

Conversation

@bthomee

@bthomee bthomee commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Part 10/16 of a stack. Base: part 9 (bthomee/shamap-invalid-09-settle-before-complete).

High Level Overview of Change

The Ledger constructor built from a LedgerHeader (used by acquisition and replay) now starts
immutable_ false and only becomes immutable once setImmutable() confirms both maps are sound, instead
of claiming to be immutable from construction while its maps are still mid-sync.

Context of Change

Ledger(LedgerHeader const&, Rules, Family&) starts at immutable_ false. Its maps are constructed
Synching and filled in afterwards, by an acquisition syncing against the hashes the header carries or
by a replay that only reads the header, so the ledger is settled by setImmutable() once both maps are
sound rather than at construction. Every consumer of isImmutable() therefore sees an in-flight
acquisition for what it is, which is what LedgerHistory::insert() and LedgerReplayMsgHandler gate on.
InboundLedger::done() (part 9) already publishes completeness only after settling, so no reader
observes the flag before the ledger it describes is immutable.

mapHashesFromHeader_ records that this constructor's transaction and account hashes are input rather
than derived, and setImmutable() therefore leaves them alone. Deriving them from the maps would turn a
ledger verified against a hash we asked for into one that is merely self-consistent: a map that fell
short of its target would be relabelled instead of refused. It is fixed at construction, unlike
immutable_, and set by this constructor alone, so every other constructor still derives its map
hashes.

Two gtest cases cover it: the first builds a ledger from a header naming a chain root, checks both maps
report as syncing and the ledger does not report as immutable, then abandons the transaction map and
checks settling refuses; the second leaves the transaction map empty while the header names that root,
so settling succeeds and both the named root and the ledger hash it was verified against are still what
the header carried.

API Impact

  • libxrpl change (any change that may affect libxrpl or dependents of libxrpl)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR corrects the semantics of Ledger(LedgerHeader const&, Rules, Family&) so a ledger created from an externally supplied header (acquisition/replay paths) does not report isImmutable() until setImmutable() has successfully settled both maps, and so settling does not overwrite the header’s map hashes that the maps are intended to sync against.

Changes:

  • Initialize header-constructed ledgers with immutable_ = false and record that the header’s map hashes are externally supplied (mapHashesFromHeader_ = true).
  • Update Ledger::setImmutable() to skip deriving txHash/accountHash from maps when those hashes came from the header.
  • Add gtests covering (1) immutability stays false until settling succeeds and (2) header-provided hashes are preserved across settling.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/libxrpl/ledger/Ledger.cpp Makes header-based ledger construction start mutable and prevents setImmutable() from rewriting externally supplied map hashes.
include/xrpl/ledger/Ledger.h Documents the updated setImmutable() behavior and adds the mapHashesFromHeader_ flag.
src/tests/libxrpl/shamap/SHAMapSync.cpp Adds regression tests for immutability gating and preserving header map hashes when settling.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@bthomee
bthomee force-pushed the bthomee/shamap-invalid-10-header-ledger-mutable branch from f887be7 to 6b4b9cd Compare August 23, 2026 23:45
@bthomee
bthomee force-pushed the bthomee/shamap-invalid-10-header-ledger-mutable branch from 6b4b9cd to 619b615 Compare August 24, 2026 14:32
@bthomee
bthomee requested a lite review from Copilot August 24, 2026 14:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread include/xrpl/ledger/Ledger.h Outdated
@bthomee
bthomee force-pushed the bthomee/shamap-invalid-10-header-ledger-mutable branch from 619b615 to e5e1236 Compare August 24, 2026 15:00
@bthomee
bthomee force-pushed the bthomee/shamap-invalid-10-header-ledger-mutable branch from e5e1236 to dd8bd69 Compare August 24, 2026 15:24
@bthomee
bthomee force-pushed the bthomee/shamap-invalid-10-header-ledger-mutable branch from dd8bd69 to edd160f Compare August 25, 2026 15:02
@github-actions

Copy link
Copy Markdown

This PR has conflicts, please resolve them in order for the PR to be reviewed.

1 similar comment
@github-actions

Copy link
Copy Markdown

This PR has conflicts, please resolve them in order for the PR to be reviewed.

@bthomee
bthomee force-pushed the bthomee/shamap-invalid-10-header-ledger-mutable branch from edd160f to 3fa57e2 Compare August 25, 2026 19:36
@github-actions

Copy link
Copy Markdown

All conflicts have been resolved. Assigned reviewers can now start or resume their review.

@bthomee
bthomee force-pushed the bthomee/shamap-invalid-10-header-ledger-mutable branch from 3fa57e2 to db1bc1d Compare August 25, 2026 19:48
@bthomee
bthomee force-pushed the bthomee/shamap-invalid-10-header-ledger-mutable branch from db1bc1d to 14d643a Compare August 25, 2026 21:08
Ledger(LedgerHeader const&, Rules, Family&) now starts at immutable_
false: its maps are constructed Synching and filled in afterward by an
acquisition or a replay, so the ledger is only settled by setImmutable()
once both maps are sound. mapHashesFromHeader_ records that this
constructor's hashes are input rather than derived, so setImmutable()
leaves them alone - deriving them from the maps would relabel a map that
fell short of its target instead of refusing it.
@bthomee
bthomee force-pushed the bthomee/shamap-invalid-10-header-ledger-mutable branch from 14d643a to 720b42e Compare August 25, 2026 21:58
@bthomee
bthomee marked this pull request as ready for review August 26, 2026 00:20
@codecov

codecov Bot commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants