Skip to content

feat(devnet): add loopback_only flag for LAN testnet support#84

Open
Nic-dorman wants to merge 2 commits intomainfrom
feat/devnet-loopback-only
Open

feat(devnet): add loopback_only flag for LAN testnet support#84
Nic-dorman wants to merge 2 commits intomainfrom
feat/devnet-loopback-only

Conversation

@Nic-dorman
Copy link
Copy Markdown

Summary

Adds an opt-in loopback_only: bool field on DevnetConfig (default
true) so the devnet harness can bind nodes to all interfaces instead
of loopback-only. Default-true preserves bit-identical behavior for all
existing callers; loopback_only: false enables a cross-host LAN
devnet path.

This is purely a dev-orchestration change — Devnet/DevnetConfig
are dev-only and not on the production node runtime path.

Why — LAN testnets for app testing

Every developer running an Autonomi-network app today needs to spin up
their own 25-node + Anvil stack locally to test against. That doesn't
scale across mixed-OS test fleets (Windows + macOS + Linux laptops on
one team). The motivating use case here is a "lab box" that hosts the
devnet once, with other devices on the same LAN acting as thin testers
that fetch the bootstrap manifest and run ant file upload/download.

A sibling tool (separate repo, testnet-lan) serves the rewritten
manifest over HTTP. It's not in this PR — that lives independently and
consumes whatever this exposes.

Changes

src/devnet.rs:

  • New loopback_only: bool field on DevnetConfig.
  • Default impl sets loopback_only: true.
  • start_node bifurcates the saorsa-core builder:
    • loopback_only=true: identical to today — .local(true) only.
    • loopback_only=false: .local(false).allow_loopback(true). The
      explicit allow_loopback is required because saorsa-core's
      local(false) would otherwise default it to false, which would
      reject the loopback bootstrap addresses devnet nodes still use to
      dial each other on the same lab host.

29 insertions, 3 deletions. No changes to manifest types or other public
API.

Backwards compatibility

Caller Result
DevnetConfig::default() loopback_only: true — historical behavior
DevnetConfig::minimal() / small() inherits ..Self::default() — historical
Struct-update syntax (DevnetConfig { evm_network: …, ..default() }) inherits — historical
Exhaustive struct literals would need to add the field; standard pattern is ..Default::default() so this is unlikely in practice

Compatibility with saorsa-labs/saorsa-core#105

This change is complementary, not in conflict, with
saorsa-labs/saorsa-core#105
(LAN-scoped DHT addresses). The two operate at different layers:

  • This PR: decides which interfaces devnet nodes bind to.
  • saorsa-core#105: decides which addresses get shared with which
    peers and tags them as AddressType::Lan.

When both land, the LAN testnet path improves: with loopback_only=false,
saorsa-transport's listen_addrs() reports LAN addresses, and
saorsa-core#105's peer_can_receive_lan_addresses heuristic correctly
hands LAN-tagged entries to clients on the same network. saorsa-core#105
alone wouldn't enable cross-host LAN devnets — without this PR, the
devnet has no LAN address to share. They depend on each other for
the full LAN-testnet story.

maybe_swap_same_lan_ip_to_loopback from #105 only triggers when a peer
announces our own LAN IP back at us (intra-host case), which doesn't
fire for clients on different hosts. No interaction issue.

Test plan

  • cargo build --lib clean
  • cargo test --lib: 448/448 passing on the unchanged default path
  • cargo fmt --all -- --check clean
  • No new clippy warnings (one pre-existing never_loop lint at
    line ~770 fires on bare main too; not introduced here)
  • Cross-host LAN smoke test against a second machine — pending the
    sibling testnet-lan tool reaching public review

🤖 Generated with Claude Code

Adds an opt-in `loopback_only: bool` field on `DevnetConfig`, defaulting
to `true`. When set to `false`, devnet nodes bind to all interfaces
(saorsa-core `local=false`) and explicitly enable `allow_loopback` in
the routing layer so inter-node bootstrap via loopback addresses on the
lab host continues to work.

The historical single-host code path is preserved unchanged: existing
callers using `DevnetConfig::default()`, `::minimal()`, or `::small()`
get bit-identical builder calls and behavior. 448/448 lib tests pass
without modification.

Use case: cross-host LAN devnets for app testing. One machine hosts
the devnet stack (Anvil + N antnodes); other devices on the same LAN
connect as thin testers via a sibling HTTP server (separate repo) that
serves the rewritten devnet manifest. Avoids rebuilding the full stack
on every Windows/macOS/Linux developer laptop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 29, 2026 13:03
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an opt-in loopback_only switch to devnet orchestration so devnet nodes can be bound to all interfaces for cross-host LAN scenarios while keeping the default behavior unchanged for existing callers.

Changes:

  • Added loopback_only: bool to DevnetConfig with a default of true (preserves historical loopback-only behavior).
  • Updated Devnet::start_node to choose between local(true) and local(false); when local(false) is used, allow_loopback(true) is set to preserve intra-host loopback bootstrap behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/devnet.rs
/// transport-layer `allow_loopback` flag is enabled explicitly in this
/// mode so inter-node bootstrap (which still uses loopback addresses
/// on the lab host) continues to work.
///
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

The docs for loopback_only read a bit like setting it to false is sufficient for cross-host clients. In this module bootstrap_addrs() (and the ant-devnet manifest it produces) still always uses Ipv4Addr::LOCALHOST, so remote clients will need a rewritten/overridden bootstrap list even when nodes bind to 0.0.0.0/::. Consider adding an explicit note to avoid confusion about what this flag does/doesn’t change.

Suggested change
///
///
/// Note: this only affects the addresses nodes bind/listen on. It does
/// not rewrite bootstrap addresses produced by this module (including
/// [`Self::bootstrap_addrs()`] and the generated `ant-devnet` manifest),
/// which still use localhost addresses. Remote clients on other hosts
/// must therefore override or rewrite the bootstrap list to use a
/// reachable LAN/WAN IP for the devnet host.
///

Copilot uses AI. Check for mistakes.
`saorsa_core::NodeConfigBuilder` isn't re-exported at the crate root,
so the intra-doc reference fails under `RUSTDOCFLAGS=-D warnings` in
the Documentation CI job. Replaced with plain prose + a code span.

Co-Authored-By: Claude Opus 4.7 (1M context) <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.

2 participants