Skip to content

feat: Add external pathfinding scores support for LDK Node#3992

Merged
kaloudis merged 3 commits intoZeusLN:masterfrom
kaloudis:ldk-scorer
Apr 18, 2026
Merged

feat: Add external pathfinding scores support for LDK Node#3992
kaloudis merged 3 commits intoZeusLN:masterfrom
kaloudis:ldk-scorer

Conversation

@kaloudis
Copy link
Copy Markdown
Contributor

@kaloudis kaloudis commented Apr 18, 2026

Description

Summary

Wires up ldk-node's setPathfindingScoresSource(url) builder method through the React Native bridge, allowing Zeus LDK nodes to periodically download and merge pathfinding scorer data from an external server. This gives mobile nodes access to liquidity intelligence they could never build on their own, significantly improving payment success rates.

Problem

LDK mobile nodes have poor pathfinding compared to LND for several structural reasons:

  • Graph staleness: RGS snapshots are up to 12 hours old. Channels that went offline or exhausted liquidity hours ago still appear viable.
  • Limited payment history: A mobile wallet that opens once a day and makes a few payments has very little data to train its probabilistic scorer. The scorer starts near-blank on every fresh install.
  • No shared intelligence: Each Zeus user's node independently learns about network liquidity through its own successes and failures. There's no way to benefit from collective experience.

Solution

ldk-node (v0.5.0+) supports external pathfinding score sources via Builder::set_pathfinding_scores_source(url). When configured:

  1. On startup: Restores cached external scores from the previous session, then fetches fresh scores from the URL
  2. Every hour: Background task fetches the URL (5s timeout, 20 MB max), deserializes ChannelLiquidities data, and merges it with the local scorer
  3. Merge algorithm: For channels present in both local and external data, liquidity estimates are averaged — (external + local) / 2. External-only channels are inserted as-is. Local-only channels are untouched.
  4. Graceful failure: If the server is down, the fetch silently fails and retries next hour. The node continues using cached external + local scores.

Zeus operates a dedicated LDK scoring node that actively probes the Lightning network and exports its scorer data. Zeus mobile clients consume this data to get realistic liquidity priors from their first payment.

Changes

Native bridges

  • LdkNodeModule.kt (Android): Added setPathfindingScoresSource React Native method, storedScorerUrl property, and applyBuilderSettings integration
  • LdkNodeModule.swift (iOS): Same pattern — @objc bridge method, stored property, builder settings

TypeScript layer

  • LdkNodeInjection.ts: Added setPathfindingScoresSource wrapper, interface declaration, export, initializeNode parameter, and conditional call during node initialization
  • LdkNode.d.ts: Type declaration for the native module method

Settings

  • SettingsStore.ts: Added ldkScorerUrl field to node config interface, observable property, load/clear lifecycle

Initialization flow

  • LdkNodeUtils.ts: Added DEFAULT_SCORER_URL constant (https://scores.zeusln.com/latest.bin), threaded scorerUrl parameter through initNode, createLdkNodeWallet, and startLdkNodeWallet

Call sites

  • Wallet.tsx: Passes ldkScorerUrl || DEFAULT_SCORER_URL during node startup
  • SeedRecovery.tsx: Passes DEFAULT_SCORER_URL during wallet recovery
  • WalletConfiguration.tsx: Passes DEFAULT_SCORER_URL during wallet creation

Architecture

Zeus Scoring Node (server-side, probes network 24/7)
  └── export_pathfinding_scores() → raw bytes
      └── served at https://scores.zeusln.com/latest.bin

Zeus Mobile App (this PR)
  └── Builder.set_pathfinding_scores_source(url)
      └── ldk-node fetches hourly, merges with local scorer
      └── cached across restarts

Configuration

  • Default: All LDK nodes automatically use https://scores.zeusln.com/latest.bin
  • Custom: Users can override per-node via ldkScorerUrl in node settings (same pattern as custom RGS/Esplora servers)
  • Disable: Setting ldkScorerUrl to empty/undefined skips the scorer source configuration

Dependencies

  • Requires ldk-node build that includes set_pathfinding_scores_source on the builder (available in the uniffi bindings since v0.5.0, present in Zeus's current ldk-node native libraries)
  • Requires the Zeus scoring server to be operational at the default URL (gracefully degrades if unavailable)

Testing

  • Fresh install: verify scorer URL is configured during wallet creation
  • Existing wallet: verify scorer URL is configured during node startup
  • Seed recovery: verify scorer URL is configured during wallet restore
  • Custom URL: verify per-node ldkScorerUrl override works
  • Server down: verify node starts and routes payments normally without external scores

PR Type

This pull request is categorized as a:

  • New feature
  • Bug fix
  • Code refactor
  • Configuration change
  • Locales update
  • Quality assurance
  • Other

Checklist

  • I’ve run yarn run tsc and made sure my code compiles correctly
  • I’ve run yarn run lint and made sure my code didn’t contain any problematic patterns
  • I’ve run yarn run prettier and made sure my code is formatted correctly
  • I’ve run yarn run test and made sure all of the tests pass

Testing

If you modified or added a utility file, did you add new unit tests?

  • No, I’m a fool
  • Yes
  • N/A

I have tested this PR on the following platforms (please specify OS version and phone model/VM):

  • Android
  • iOS

I have tested this PR with the following types of nodes (please specify node version and API version where appropriate):

On-device

  • LDK Node
  • Embedded LND

Remote

  • LND (REST)
  • LND (Lightning Node Connect)
  • Core Lightning (CLNRest)
  • Nostr Wallet Connect
  • LndHub

Locales

  • I’ve added new locale text that requires translations
  • I’m aware that new translations should be made on the ZEUS Transfix page and not directly to this repo

Third Party Dependencies and Packages

  • Contributors will need to run yarn after this PR is merged in
  • 3rd party dependencies have been modified:
    • verify that package.json and yarn.lock have been properly updated
    • verify that dependencies are installed for both iOS and Android platforms

Other:

  • Changes were made that require an update to the README
  • Changes were made that require an update to onboarding

@kaloudis kaloudis added this to the v13.0.0 milestone Apr 18, 2026
Copy link
Copy Markdown
Contributor

@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 introduces functionality to configure a pathfinding scores source (scorer URL) for the LDK Node. This involves adding scorerUrl parameters and methods across Android (LdkNodeModule.kt), iOS (LdkNodeModule.swift), and TypeScript interfaces (LdkNode.d.ts, LdkNodeInjection.ts). The SettingsStore.ts and various UI components (SeedRecovery.tsx, WalletConfiguration.tsx, Wallet.tsx) are updated to manage and apply this new setting. Feedback highlights the need for consistent promise resolution in the iOS module (resolving with nil for void operations) and a logical correction in Wallet.tsx to correctly interpret an empty ldkScorerUrl as disabling the feature, rather than falling back to a default URL.

Comment thread ios/LdkNodeMobile/LdkNodeModule.swift Outdated
Comment thread views/Wallet/Wallet.tsx Outdated
@kaloudis kaloudis marked this pull request as ready for review April 18, 2026 06:59
Copy link
Copy Markdown
Contributor

@shubhamkmr04 shubhamkmr04 left a comment

Choose a reason for hiding this comment

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

Image

hitting this every time while creating ldk node on iOS

@shubhamkmr04
Copy link
Copy Markdown
Contributor

@kaloudis c3c6611 is failing checks

@kaloudis kaloudis merged commit 32d0805 into ZeusLN:master Apr 18, 2026
4 checks passed
@kaloudis kaloudis deleted the ldk-scorer branch April 18, 2026 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants