Skip to content

Conversation

@Dunsin-cyber
Copy link
Contributor

@Dunsin-cyber Dunsin-cyber commented Jan 18, 2026

fixes #1985

Implemented handlers in both the HTTP server and Wails app to allow configuring the LDK chain source. You can now switch between Esplora, Electrum, and Bitcoind RPC, or reset to defaults.

Note: We will be able to display the current chain source in the UI once #2013 is merged.

Alby.Hub.-compressed.mp4

Summary by CodeRabbit

  • New Features

    • New "Chain Source" settings page to configure Esplora, Electrum, or Bitcoin RPC with client-side validation and a Save flow (requires restart to apply).
    • Added server APIs to save and apply user chain-source overrides.
  • Bug Fixes / Validation

    • End-to-end validation of configured chain sources before saving (connectivity and format checks).
  • Tests

    • Added comprehensive tests covering validation and failure cases.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 18, 2026

📝 Walkthrough

Walkthrough

Adds an LDK on-chain source configuration feature: validation helpers for Esplora/Electrum, a Config API method, frontend settings UI and route, HTTP/Wails endpoints to persist user overrides, tests and mocks, and LDK selection logic that prefers user overrides over environment fallbacks.

Changes

Cohort / File(s) Summary
Config validation & helpers
config/config.go
Added ValidateChainSource(backendType, url) error plus validateEsplora and validateElectrum helpers (HTTP health check for Esplora, TCP dial for Electrum, URL/prefix validation, 5s timeout).
Config models & API types
config/models.go
Added ValidateChainSource to Config interface and introduced UpdateChainConfigRequest struct (ChainSource, URL, Host, Port, User, Pass).
Config tests
config/tests/config_test.go
New TestValidateChainSource with table-driven cases exercising Esplora and Electrum validation, error paths, and unsupported backends.
Frontend: layout, route, component
frontend/src/components/layouts/SettingsLayout.tsx, frontend/src/routes.tsx, frontend/src/screens/settings/ChainSource.tsx
Added "Chain Source" settings link (LDK-only), route entry, and new ChainSource component with form state, client-side validation per backend, confirmation dialog, and PATCH to /api/ldk-onchain-source.
HTTP/Wails handlers
http/http_service.go, wails/wails_handlers.go
Added PATCH /ldk-onchain-source route and handlers that require LDK backend, bind UpdateChainConfigRequest, call cfg.ValidateChainSource, validate fields per source, and persist User* settings via SetUpdate/DB calls.
LDK client selection logic
lnclient/ldk/ldk.go
Implemented two-tier chain source resolution: user database overrides (bitcoind_rpc, electrum, esplora) take precedence; fall back to existing environment-based configuration when no valid override.
Mocks & tests utilities
tests/mocks/Config.go
Tightened mock helper signatures from interface{} to string, updated Run handlers, and added ValidateChainSource mock with Call/Run/Return helpers.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant FE as Frontend
    participant API as HTTP Service
    participant Config as Config Layer
    participant DB as Database
    participant LDK as LDK Client

    User->>FE: Open Chain Source settings
    FE->>FE: load useInfo()
    User->>FE: Select source and enter data
    FE->>FE: client-side validation
    User->>FE: Click Save
    FE->>API: PATCH /api/ldk-onchain-source (UpdateChainConfigRequest)
    API->>API: ensure LN backend == LDK
    API->>Config: ValidateChainSource(chainSource, url)
    Config->>Config: validateEsplora / validateElectrum (HTTP or TCP check)
    Config-->>API: Validation success/failure

    alt Validation success
        API->>DB: SetUpdate() user override fields
        DB-->>API: persisted
        API-->>FE: 200 OK
        FE->>User: success toast
    else Validation failed
        API-->>FE: 400 error
        FE->>User: show error
    end

    Note over LDK,DB: On next LDK init
    LDK->>DB: query UserChainSource
    alt user override exists and valid
        LDK->>LDK: configure user-selected chain source
    else
        LDK->>LDK: use environment-based chain source
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped in code to check the source,
Esplora, Electrum, RPC of course,
A form, a save, a tiny test,
User overrides now take the crest.
Restart LDK — the rabbit says: rejoice!

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main change: enabling users to update the LDK chain source through the UI, which is the primary objective of the changeset.
Linked Issues check ✅ Passed The PR implements all required features from issue #1985: validation and selection of three supported chain sources (Esplora, Electrum, Bitcoind RPC) with handlers in HTTP and Wails backends.
Out of Scope Changes check ✅ Passed All changes are directly related to supporting LDK chain source configuration: validation logic, UI components, route handlers, and mock updates for testing are all in-scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@Dunsin-cyber Dunsin-cyber marked this pull request as ready for review January 19, 2026 07:25
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Fix all issues with AI agents
In `@config/models.go`:
- Around line 94-105: The struct comment for UpdateChainConfigRequest's
ChainSource is incorrect and lists "bitcoind" whereas the handler expects
"bitcoind_rpc"; update the inline comment on the ChainSource field in type
UpdateChainConfigRequest to list "bitcoind_rpc" (so it reads something like
`"esplora", "electrum", "bitcoind_rpc", or "default"`) to match the
handler/clients and avoid 400 errors.

In `@config/tests/config_test.go`:
- Around line 365-412: The tests "Esplora - Connection Refused" and "Electrum -
Connection Refused" use a fixed port 127.0.0.1:54321 which can be flaky; replace
the hardcoded port with a dynamically reserved/free port that you immediately
close to simulate refusal. Update the cases in config_test.go to call a helper
(e.g., getFreePort or reserveFreePort) that does net.Listen("tcp",
"127.0.0.1:0"), captures the assigned port, closes the listener, and returns the
host:port string; then use that host:port in the Esplora URL and in the electrum
URL prefixes ("tcp://"+addr or "ssl://"+addr) and keep the same shouldError and
errorContains expectations. Ensure the helper is added to the test file (e.g.,
getFreePort) and used for both offending test cases.

In `@frontend/src/screens/settings/ChainSource.tsx`:
- Around line 61-98: The validateForm function currently allows invalid schemes
and missing ports; update it to require exact schemes and backend-compatible
formats: for esplora (in validateForm, checking formData.chainSource ===
"esplora") require formData.url.startsWith("http://") ||
formData.url.startsWith("https://") (not just "http"), and additionally ensure
the URL includes a host (e.g., non-empty hostname after the scheme). For
electrum (formData.chainSource === "electrum") require formData.url to start
with "ssl://" or "tcp://" and validate that the remainder contains host:port
(i.e., a colon and a numeric port), and that the port is a valid integer in
range 1-65535. For bitcoind_rpc keep the existing presence checks on
formData.host, formData.port, formData.user, formData.pass but tighten port
validation to ensure Number(formData.port) is an integer between 1 and 65535.
Add clear validationError messages referencing the specific field failures.

In `@http/http_service.go`:
- Around line 1600-1652: The code ignores errors returned by
httpSvc.cfg.SetUpdate in each switch case, which can mask DB write failures;
update the handler to check the returned error from every SetUpdate call (e.g.,
in the "default", "esplora", "electrum", and "bitcoind_rpc" branches) and if any
call returns an error, return an HTTP error response (e.g., c.JSON with
http.StatusInternalServerError and an ErrorResponse containing err.Error()) so
the API surfaces config write failures instead of reporting success; keep
existing input validation (ValidateChainSource and the strconv.ParseUint check)
and return early on the first SetUpdate error.

In `@lnclient/ldk/ldk.go`:
- Around line 163-176: The current bitcoind_rpc branch accepts an invalid or
empty UserBitcoindPort because it ignores ParseUint errors and treats a parsed 0
as valid; update the logic around host, portStr, strconv.ParseUint and
sourceConfigured so you only call builder.SetChainSourceBitcoindRpc and set
sourceConfigured = true when ParseUint returns no error and the parsed port is
within valid range (>0 and <=65535); if parsing fails or yields 0, do not mark
the override as configured so env fallback can proceed. Reference the host,
portStr, strconv.ParseUint call, builder.SetChainSourceBitcoindRpc and
sourceConfigured in your changes.

In `@wails/wails_handlers.go`:
- Around line 1210-1218: The JSON unmarshal error logging currently prints the
raw request body (which can contain Bitcoind RPC credentials) in
wails_handlers.go; update the error branch around the
config.UpdateChainConfigRequest decode so you do not log the raw body — replace
the "body" field with a redacted placeholder (e.g. "<redacted>" or a
masked/hashed summary) when calling logger.Logger.WithFields/WithError in that
error case, leaving other fields ("route", "method", error) intact; locate the
payload decode code that constructs payload :=
&config.UpdateChainConfigRequest{} and the subsequent json.Unmarshal error
handling and change the body field used in the log to a redacted value.
- Around line 1223-1275: The SetUpdate calls in the switch cases (e.g.,
cfg.SetUpdate in the "default", "esplora", "electrum", and "bitcoind_rpc"
branches) currently ignore returned errors which can cause a success response
without persisted changes; update each SetUpdate invocation to capture its
error, and if non-nil return a WailsRequestRouterResponse containing the error
(similar to how validation errors are returned), ensuring you short-circuit
further updates on failure so callers receive an accurate error when
cfg.SetUpdate fails.
🧹 Nitpick comments (1)
frontend/src/screens/settings/ChainSource.tsx (1)

103-109: Prevent double-submit while save is in-flight.
handleSubmit can be triggered multiple times before isLoading flips, resulting in duplicate requests.

🛡️ Simple guard against repeat submits
   const handleSubmit = async () => {
-    if (!validateForm()) {
+    if (isLoading || !validateForm()) {
       return;
     }
     setIsLoading(true);

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.

Feat: advanced setting for onchain source backend for LDK

1 participant