Skip to content

autopilot+graph/db: drop unused address loading from cached node iteration#10796

Open
ellemouton wants to merge 3 commits intolightningnetwork:masterfrom
ellemouton:for-each-node-cached-autopilot
Open

autopilot+graph/db: drop unused address loading from cached node iteration#10796
ellemouton wants to merge 3 commits intolightningnetwork:masterfrom
ellemouton:for-each-node-cached-autopilot

Conversation

@ellemouton
Copy link
Copy Markdown
Collaborator

Change Description

Autopilot's graph-wide channel-scoring traversal calls ForEachNodesChannels, which previously asked graph/db to load each node's addresses alongside its cached channel data. The scoring code does not consume those addresses — they were only used to skip nodes with no advertised addresses. That bookkeeping had two costs:

  • On the SQL backend, every page of nodes did an extra batchLoadNodeAddressesHelper round-trip to load data that scoring threw away.
  • On the kvdb backend, ChannelGraph.ForEachNodeCached always took the slow database path because the withAddrs=true branch couldn't be served from the in-memory graph cache.

This PR removes the withAddrs parameter from ForEachNodeCached so cached node iteration consistently uses the in-memory graph cache when it is loaded, and tightens the autopilot callback signature accordingly:

  1. graph/db — drop withAddrs from Store.ForEachNodeCached and the SQL/kvdb implementations; remove the now-unneeded address batch-load on the SQL path.
  2. autopilot — change ChannelGraph.ForEachNodesChannels to hand the callback a NodeID (route.Vertex) instead of a Node interface, since it never needed an address-bearing wrapper. The address-bearing Node interface is still used by ForEachNode, where Agent.openChans does collect addresses for ConnectToPeer.
  3. docs — release note describing the perf change and a small observable side-effect on lncli getnetworkinfo.

Behaviour change worth flagging

ForEachNodesChannels previously skipped nodes with zero advertised addresses. After this PR it does not, so graph-wide stats derived from that traversal (median channel size, graph diameter in GetNetworkInfo) now include those nodes. In practice the only addressless nodes our local view knows about are nodes with no public channels — typically our own node or peers we share only private channels with — so the impact on the reported stats should be negligible. Address-based filtering is still applied at the dialing path (Agent.openChansForEachNode) before autopilot opens any channel.

Steps to Test

  • go test ./autopilot/... ./graph/db/...
  • make itest icase=graph_migration to exercise the SQL ForEachNodeCached path that was updated.
  • Manual: run lncli getnetworkinfo against a populated graph and confirm graph_diameter, median_channel_size_sat, etc. are returned and within the expected order of magnitude.

@ellemouton ellemouton force-pushed the for-each-node-cached-autopilot branch from 3351d43 to f263c0d Compare May 7, 2026 23:24
ForEachNodeCached is now only used for topology-oriented traversal,
so the address-loading option forced one autopilot scoring path to
bypass the in-memory graph cache for data it did not consume. Remove
the withAddrs parameter and the associated SQL/KV address plumbing
so cached node iteration can consistently use the graph cache when
it is loaded.

Autopilot still requires peer addresses before opening channels.
That filtering remains in Agent.openChans via ForEachNode, where the
selected candidates' addresses are collected for ConnectToPeer. The
trade-off is that ForEachNodesChannels no longer excludes
addressless nodes from graph-wide scoring inputs such as median
channel size or centrality, which also feed lncli getnetworkinfo
statistics like graph diameter. In practice the only addressless
nodes our local view tends to know about are nodes with no public
channels (e.g. our own node or peers we share only private channels
with), so the impact on the reported stats should be negligible.
Active channel candidates remain address-filtered before dialing.
@ellemouton ellemouton force-pushed the for-each-node-cached-autopilot branch from f263c0d to 49740f7 Compare May 7, 2026 23:29
@github-actions github-actions Bot added the severity-critical Requires expert review - security/consensus critical label May 7, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

🔴 PR Severity: CRITICAL

Automated classification | 9 files (excl. tests) | 168 lines changed (excl. tests)

🔴 Critical (1 file)
  • rpcserver.go - Core server coordination file; listed as CRITICAL in classification rules
🟠 High (4 files)
  • graph/db/graph.go - Network graph maintenance (graph/*)
  • graph/db/interfaces.go - Network graph maintenance (graph/*)
  • graph/db/kv_store.go - Network graph maintenance (graph/*)
  • graph/db/sql_store.go - Network graph maintenance (graph/*)
🟡 Medium (4 files)
  • autopilot/graph.go - Autopilot (autopilot/*)
  • autopilot/interface.go - Autopilot (autopilot/*)
  • autopilot/prefattach.go - Autopilot (autopilot/*)
  • autopilot/simple_graph.go - Autopilot (autopilot/*)
🟢 Low (1 file, excluded from count)
  • docs/release-notes/release-notes-0.22.0.md - Release notes (docs/*)

Analysis

This PR is classified as CRITICAL because it touches rpcserver.go, which is the core RPC server coordination file and is explicitly listed as a CRITICAL-tier file. The bulk of the changes are in graph/db/* (HIGH tier) and autopilot/* (MEDIUM tier), but the highest severity file drives the overall classification.

The PR appears to be a refactoring/cleanup of graph-related interfaces — the change volumes are modest (9 non-test files, ~168 lines), so no severity bump was triggered. The rpcserver.go change is small (2 additions, 2 deletions) but its presence still warrants expert review attention.


To override, add a severity-override-{critical,high,medium,low} label.
<!-- pr-severity-bot -->

@ellemouton ellemouton force-pushed the for-each-node-cached-autopilot branch from 49740f7 to 0190889 Compare May 7, 2026 23:32
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly optimizes Autopilot's graph-wide channel scoring by removing the unnecessary loading of node addresses during graph iteration. By streamlining the ForEachNodeCached function and adjusting the ForEachNodesChannels callback signature, the system avoids costly database round-trips and leverages the in-memory graph cache more effectively. This change enhances performance, especially for the KVDB backend, and results in a minor, more inclusive adjustment to network statistics reported by lncli getnetworkinfo.

Highlights

  • Performance Optimization: Removed the withAddrs parameter from graph/db.ForEachNodeCached and its underlying implementations (SQL and KVDB), eliminating unnecessary address loading during graph iteration.
  • API Simplification: Modified autopilot.ChannelGraph.ForEachNodesChannels to pass a NodeID (pubkey) instead of a Node interface, as address information is not required for channel scoring.
  • Consistent Cache Usage: Ensured ForEachNodeCached consistently utilizes the in-memory graph cache when available, particularly benefiting the KVDB backend by avoiding slow database paths.
  • Network Statistics Adjustment: Updated lncli getnetworkinfo statistics (e.g., graph diameter, median channel size) to include nodes without advertised addresses, reflecting a more complete graph view.
  • Code Clean-up: Removed redundant code related to address handling and unused imports across several files.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors graph traversal methods to remove the withAddrs parameter, enabling Autopilot's scoring traversal to use the in-memory graph cache and avoid unnecessary database lookups for node addresses. This change improves performance but results in network statistics including nodes without advertised addresses. Review feedback identifies a consistency issue where one implementation of ForEachNodesChannels should be updated to skip nodes with no channels, matching the behavior of the cached implementation.

Comment thread autopilot/graph.go
ellemouton added 2 commits May 7, 2026 17:03
ForEachNodesChannels is a topology traversal: its callers only need
the node identity plus channel edges. After removing address loading
from ForEachNodeCached, constructing a Node for this callback is
misleading because Addrs is either unused or empty.

Pass NodeID directly through the interface and update the scoring
and simple graph callers to use that pubkey. This keeps the
address-bearing Node interface on ForEachNode, where autopilot
gathers connectable candidates and their addresses before dialing.
Note the performance improvement and the observable side-effect on
GetNetworkInfo stats so operators are not surprised by small shifts
in median channel size / graph diameter for nodes without advertised
addresses.
@ellemouton ellemouton force-pushed the for-each-node-cached-autopilot branch from 0190889 to 462c78c Compare May 8, 2026 00:03
@saubyk saubyk added this to lnd v0.22 May 8, 2026
@github-project-automation github-project-automation Bot moved this to Backlog in lnd v0.22 May 8, 2026
@saubyk saubyk moved this from Backlog to In progress in lnd v0.22 May 8, 2026
@ellemouton ellemouton requested review from bhandras and bitromortac May 8, 2026 17:11
Copy link
Copy Markdown
Collaborator

@bhandras bhandras left a comment

Choose a reason for hiding this comment

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

LGTM 🌮

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

Labels

severity-critical Requires expert review - security/consensus critical

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

3 participants