Skip to content

fix(peer): keep a later source's novel reach-hint when an earlier source fills the cap - #130

Merged
MichaelTaylor3d merged 1 commit into
mainfrom
fix/1620/union-locator-cap-order
Aug 2, 2026
Merged

fix(peer): keep a later source's novel reach-hint when an earlier source fills the cap#130
MichaelTaylor3d merged 1 commit into
mainfrom
fix/1620/union-locator-cap-order

Conversation

@MichaelTaylor3d

Copy link
Copy Markdown
Contributor

Closes #1620.

Problem

union_locator merges the address hints of the same peer_id named by multiple sources (#836/#97), then caps the combined set at MAX_ADDRS_PER_PROVIDER. But the cap ran after the merge (existing.addresses.extend(record.addresses)sanitize_address_hints) and kept the first MAX. So an earlier source that had already filled the cap with unreachable hints (a stale DHT record) silently dropped a later source's novel reachable hint (the live connected pool) for the same peer — the node then dialed only stale hints and missed a dialable holder. Masked in production only by wiring the reachable pool source first; any reorder reintroduced it (verified still-real against current main, per the ticket's "reproduce RED first" note).

Fix — reconciles #1620 with #836

merge_address_hints reserves the cap's slots for the later source's novel hints first, then leads with as many of the earlier source's hints as still fit:

  • The earlier source's HEAD keeps its lead position — #836 relies on this (best_address breaks ties by list order, and the pool source is wired first).
  • Only the earlier surplus TAIL is displaced when over the cap — never a later reachable hint.
  • When everything fits (combined ≤ MAX), the order is unchanged (earlier-then-later), so the existing #836 behaviour is byte-identical.

The shared order-preserving dedup is factored into dedup_hints; sanitize_address_hints (first-seen ingest) dedups-then-caps through it.

Blast radius (checked)

union_locator.rs only. merge_address_hints is called from the one Some(i) merge branch; the None (first-seen ingest) branch keeps its sanitize_address_hints cap. The dial consumer selects best_address() (dig-dht preference + list-order tie-break), which is unaffected — the earlier head still leads; the fix only guarantees the reachable hint is present to be chosen.

Tests

  • New: a_later_sources_novel_hint_survives_when_an_earlier_source_fills_the_cap — earlier source fills the cap + later source's one reachable hint → reachable survives, earlier head still leads. (Fails against the old code, which kept 8 earlier + dropped the reachable.)
  • The existing #836 tests stay green (same_peer_across_sources_merges_address_hints asserts first-seen leads; provider_address_hints_are_capped_and_deduped).
  • cargo test -p dig-node-core --lib union_locator6 passed, 0 failed. fmt clean; clippy -D warnings clean.

Version

0.72.10.72.2 (patchfix:, behaviour-correcting within the existing contract), re-locked.

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com


Generated by Claude Code

@MichaelTaylor3d
MichaelTaylor3dforce-pushed the fix/1620/union-locator-cap-order branch from d1937d9 to e742122CompareAugust 2, 2026 02:08
…rce fills the cap
union_locator merges the address hints of the same peer_id named by multiple sources
(#836/#97), then caps the combined set at MAX_ADDRS_PER_PROVIDER. But the cap ran
AFTER the merge and kept the FIRST MAX, so an earlier source that had already filled
the cap with unreachable hints (a stale DHT record) silently dropped a later source's
novel REACHABLE hint (the live pool connection) for the same peer (#1620). The node
then dialed only stale hints and missed a dialable holder. Masked in production only
by wiring the reachable pool source first — any reorder reintroduced it.
merge_address_hints now reserves the cap's slots for the later source's NOVEL hints
first, then leads with as many of the earlier source's hints as still fit — so the
earlier HEAD keeps its lead position (#836: best_address breaks ties by list order)
while only the earlier SURPLUS TAIL is displaced, never a later reachable hint. When
everything fits, the order is unchanged (earlier-then-later). The shared order-
preserving dedup is factored into dedup_hints; sanitize_address_hints (first-seen
ingest) dedups-then-caps through it.
Regression test: an earlier source filling the cap + a later source's one reachable
hint -> the reachable hint survives and the earlier head still leads. The existing
#836 merge/order tests stay green. union_locator suite 6/6; fmt + clippy -D warnings clean.
Closes #1620
Co-Authored-By: Claude <noreply@anthropic.com>
@MichaelTaylor3d
MichaelTaylor3dforce-pushed the fix/1620/union-locator-cap-order branch from e742122 to 4b4e64aCompareAugust 2, 2026 02:29
@MichaelTaylor3d
MichaelTaylor3d merged commit bd8d4ea into mainAug 2, 2026
15 checks passed
@MichaelTaylor3d
MichaelTaylor3d deleted the fix/1620/union-locator-cap-order branch August 2, 2026 02:47
Sign up for freeto 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

@MichaelTaylor3d@claude