Skip to content

feat(bootstrap): dial always-on bootstrap peers so a fresh node has a dialable peer - #245

Draft
MichaelTaylor3d wants to merge 3 commits into
mainfrom
loop/1871-923-connect
Draft

feat(bootstrap): dial always-on bootstrap peers so a fresh node has a dialable peer#245
MichaelTaylor3d wants to merge 3 commits into
mainfrom
loop/1871-923-connect

Conversation

@MichaelTaylor3d

Copy link
Copy Markdown
Contributor

DO NOT MERGE — gate round not yet run.

Closes nothing on its own; refs https://github.com/DIG-Network/dig_ecosystem/issues/923.

What changed

Adds the bootstrap seam (crates/dig-node-core/src/seams/dig_peer/bootstrap.rs) and wires it into
peer-network bring-up: resolve the anchor set, dial each over the full NAT traversal ladder, adopt
each verified connection into the connected-peer pool.

A freshly-installed node knows no peers. Peer exchange spreads only the peers a link's far end
knows, the DHT routes queries through peers already in the table, and a relay reservation makes the
node reachable without ever populating an address book. So a node on a machine that has never run
one has nothing to dial and reports connected_peers = 0 indefinitely.

Two findings that shaped the design

  1. An address alone is not dialable. GossipHandle::connect_via_nat pins the peer's certificate
    SPKI against an EXPECTED peer_id, and dig-node's existing PEX dial loop (pex.rs:613) already
    continues on any candidate lacking one. So a bootstrap entry needs an identity, not just an
    authority. An entry without one is SKIPPED rather than dialed unpinned — an unpinned dial would
    accept whatever identity answered at that address.
  2. dig-constants 0.11 cannot be adopted yet. The canonical set landed in dig-constants 0.11.0
    (feat(bootstrap): canonical DIG_BOOTSTRAP_PEERS so a fresh node has a dialable peer dig-constants#13), but this workspace pins dig-constants to 0.9: 0.10 moved to
    chia-protocol 0.36 while everything here builds against 0.26, and linking both stops Bytes32
    unifying across the workspace. That is the pin's own documented rationale
    (crates/dig-node-core/Cargo.toml:227), and I verified it empirically — bumping to 0.11 produces
    E0308 ... multiple different versions of crate chia_protocol. So compiled_in_targets() is
    explicitly empty and documented as such, and DIG_BOOTSTRAP_PEERS is the supported way to name
    an anchor until the chia 0.36 migration lands.

Neither of these is a shortcut: the anchor's own peer_id is not known yet either (see the report),
so the canonical entry would be skipped as unpinned regardless. The dial mechanism is complete and
exercised end-to-end through the env path.

Blast radius

impact was unavailable for this worktree (see report); radius established by grep + direct read
and stated honestly.

  • bootstrap.rs is a new module with no existing callers.
  • The one edit to existing code is an additive call in run_peer_network (peer.rs), plus a
    pub mod and a re-export line. No existing function signature, type, or test was modified.
  • run_peer_network is the peer-network bring-up entry point, so it is high-traffic — which is why
    the added call is a spawn that cannot fail bring-up and returns early when the target set is
    empty (the current default). With no anchors configured the behaviour is byte-identical to before
    apart from one INFO log.
  • No HIGH/CRITICAL risk to warn on: the change adds a code path and removes none.

How verified (locally — dig-node's Test + coverage check is known false-green, #2513)

  • cargo test -p dig-node-core --lib854 passed, 0 failed.
  • The 12 new bootstrap tests pass by name.
  • cargo clippy -p dig-node-core --all-targets -- -D warnings — clean, exit 0.
  • cargo fmt --check — clean.

Test design notes

Fixtures were built to distinguish the property from the nearest wrong implementation, not merely to
assert an outcome:

  • env_list_parses_every_entry uses two entries — one cannot tell "parses the list" from
    "parses the first element".
  • a_malformed_entry_is_dropped_without_discarding_the_list pairs each bad entry with a good
    neighbour
    — a list of only-bad entries yields empty either way and cannot tell "drops the entry"
    from "rejects the list".
  • a_blank_value_falls_back_rather_than_disabling carries a populated control through the same
    argument position, so it cannot pass merely because both arms are empty today.
  • compiled_targets_are_absent_for_now_and_pinned_whenever_present asserts the current empty state
    AND the pinning invariant, so it begins checking pinning rather than going vacuous the day the
    canonical set is adopted.
  • authority_resolution_prefers_ipv6 guards its assertion on the host actually offering both
    families, so it cannot pass vacuously on a single-family host.

Version

Workspace 0.126.0 → 0.127.0; dig-node-core 0.47.0 → 0.48.0 (minor: additive capability).

Not in this PR

dig_ecosystem#1871 (adopt_relayed_inbound never called) is not fixed here — it is blocked on a
dig-gossip API gap, detailed in the lane report. Shipping the naive call would count the peer while
stopping its peer-RPC from being served, which is a regression, not a fix.

MichaelTaylor3d and others added 3 commits August 18, 2026 14:11
… dialable peer

A freshly-installed node knows no peers. Peer exchange spreads only the peers a
link's far end knows, the DHT routes queries through peers already in the table,
and a relay reservation makes the node reachable without ever populating an
address book. So a node on a machine that has never run one has nothing to dial
and reports connected_peers = 0 for as long as it runs.

Adds the bootstrap seam: resolve the anchor set, then dial each over the full
NAT traversal ladder and adopt the verified connection into the pool. Dials are
spawned so bring-up never blocks on an anchor that may be unreachable.

An anchor is dialed only when its peer_id is known. The node<->node interface
pins the peer's certificate SPKI against an expected identity, so an entry with
no identity is skipped rather than dialed unpinned -- an unpinned dial would
accept whatever identity answered at the address.

The compiled-in set is empty for now and DIG_BOOTSTRAP_PEERS names the anchors:
the canonical set lives in dig-constants 0.11.0, which this workspace cannot
adopt until the chia 0.36 migration, per the dig-constants pin's own rationale.

Refs: DIG-Network/dig_ecosystem#923

Co-Authored-By: Claude <noreply@anthropic.com>
Without a hook the built .debs sit on the GitHub release while the apt repository
keeps serving the previous version until someone runs its deploy by hand.

repository_dispatch deliberately, not `on: release:` in apt.dig.net: a release
run sets github.ref to the TAG, so every job guarded on refs/heads/main skips
while the run still reports completed -- nothing red, nothing ran.

The job is INERT until apt.dig.net adds the matching listener; the dispatches API
returns 204 whether or not anything is listening, so this is documented in place
rather than left to look like a working hook.

Refs: DIG-Network/dig_ecosystem#425

Co-Authored-By: Claude <noreply@anthropic.com>
Reverting validated_peer_id to Some(_) left the skip test green: its only
unidentified fixture had no `@`, so it never reached identity validation and was
blind to that validation being deleted outright. Adds the `@`-present-but-empty
case, which fails on the revert as it should.

Co-Authored-By: Claude <noreply@anthropic.com>
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.

1 participant