← Tech docs

Choosing peers for reach, not centrality

May 2026

"Who should I open a channel to?" is usually answered with centrality — connect to the most-connected nodes. We think centrality answers a different question than the one that matters for a small or mid-sized node, and use a two-stage ranking that scores reach instead.

Why centrality alone misleads

Centrality measures how well-connected a candidate is. But opening a channel to a node whose peers we can already reach in two hops buys little new reachability — we have added a parallel path, not a new destination. For a node with relatively few channels this is precisely the case with the large hubs: their peer sets overlap heavily with everyone's, so a channel there is mostly redundant.

The metric: diversity against the 2-hop set

Once per run we build, from the local describe_graph() dump, the set of nodes reachable within two hops of us (reachable_2hop). For each candidate we then compute:

diversity = |peers(candidate) not in reachable_2hop|
            ────────────────────────────────────────
                       |peers(candidate)|

That is the fraction of a candidate's peers we cannot already reach in two hops — the share that would genuinely extend our horizon. A 50-peer hub of which 40 peers are already inside our 2-hop set scores 20%. A smaller node off in a corner of the graph with 18 peers, 15 of them new to us, scores 83% — despite far lower centrality.

The baseline that made it work

The first version measured "new" against our direct peers rather than the 2-hop set. With few channels almost every candidate's peers look new by that definition, so the metric effectively re-ranked by size and recommended hubs — the outcome we were trying to avoid. Switching the baseline to the 2-hop reachable set is what gives the metric its discrimination: a candidate now scores well only if it reaches places we genuinely cannot get to yet.

Why the tiers

A hub and a small node occupy different structural regimes. A hub's diversity is inherently low (everyone connects to it); a small node's is inherently high. Ranked in one list, obscure small nodes would always win and we would never open to a hub. So candidates are bucketed by raw channel count and ranked within each bucket:

  • Hub — 100+ channels
  • Mid-tier — 30–99
  • Small — 10–29
  • Below 10 is dropped as noise.

The top 10 of each tier are surfaced; choosing the mix across tiers is left to the operator.

Two stages, for cost

Diversity needs a get_node_info call per candidate, which is slow. So stage one is a cheap prefilter: a centrality score from log-normalised channel count and capacity, used only to select the top 30 per tier. Stage two runs the live calls on that shortlist and reranks by diversity. It is roughly 90 round-trips, so it lives in the on-demand ln-operator plan command, never in the 2-hour pipeline.

Limitations

  • The 2-hop set comes from a local graph snapshot; gossip is incomplete and lags reality, so diversity is an approximation.
  • It scores reachability, not reliability or liquidity — a high-diversity peer can still route poorly. The metric narrows the field; the final choice is human.
  • Fee data is excluded from scoring on purpose, for the same unreliability reason that keeps it out of fee-setting (i.e. because of a potentially incomplete graph).
Like the thinking? Run it on your own node.