Skip to content

chanstate: migrate consumers to Store interface (PR 2 of channel-state decomposition)#10790

Merged
yyforyongyu merged 7 commits into
lightningnetwork:masterfrom
ziggie1984:chanstate-sql-migration-pr2-consumers
May 14, 2026
Merged

chanstate: migrate consumers to Store interface (PR 2 of channel-state decomposition)#10790
yyforyongyu merged 7 commits into
lightningnetwork:masterfrom
ziggie1984:chanstate-sql-migration-pr2-consumers

Conversation

@ziggie1984
Copy link
Copy Markdown
Collaborator

Summary

Second PR in the channel-state decomposition series. Migrates every
in-tree consumer of *channeldb.ChannelStateDB over to the
chanstate.Store
interface introduced in PR 1, so subsequent PRs can swap in the
KV-backed and SQL-backed Store implementations without further churn
to call sites.

No data moves and no behavior changes — every commit is a pure
dependency-injection swap. The interface contract was sized in PR 1
exactly to cover the union of method calls touched by these consumers,
so each commit compiles against Store without expanding the
interface.

Stacked on top of #10777. Until that lands, this PR's diff includes
its 4 commits; once 10777 merges into
elle-base-branch-channelstate-native-sql, the diff here collapses to
the 8 commits below.

Seven consumer commits, one release-note commit:

  1. funding: depend on chanstate Store — funding manager only uses
    methods covered by the store contract, including channel-opening
    state and initial forwarding policy persistence.
  2. peer: depend on chanstate Store — Brontide only needs channel
    lookups, closed-channel lookup, and initial forwarding policy
    access.
  3. channelnotifier: depend on chanstate Store — notifier only fetches
    open and closed channel records to populate event payloads.
  4. contractcourt: use chanstate Store in breach arb — breach
    arbitrator only needs closed-channel reads and
    MarkChanFullyClosed.
  5. lnd: use chanstate Store for channel restorechanDBRestorer
    only needs RestoreChannelShells; it still builds channeldb
    channel-shell values.
  6. lnrpc: depend on chanstate Store — invoices/wallet RPC configs
    and subserver wiring; only hop-hint and waiting-close paths are
    touched.
  7. server: depend on chanstate Store — server now holds channel-state
    access as chanstate.Store. Link-node access stays a separate
    concrete *channeldb.LinkNodeDB field so LinkNodeDB does not leak
    into the channel-state contract.
  8. docs: release note for chanstate Store consumer migration
    sibling bullet under the existing v0.22 "Native SQL migration of
    the channel state and switch data" heading.

Test plan

@ziggie1984 ziggie1984 force-pushed the chanstate-sql-migration-pr2-consumers branch from a468106 to 014cbfc Compare May 5, 2026 17:31
@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 is the second installment in the channel-state decomposition series. It establishes a new persistence contract via the chanstate.Store interface and migrates all existing consumers of the concrete channeldb.ChannelStateDB to this abstraction. This change is purely architectural, ensuring that future work to swap the underlying storage backend (e.g., from KV to SQL) can be performed without requiring modifications to the various subsystems that depend on channel state.

Highlights

  • Interface Abstraction: Introduced the chanstate.Store interface to decouple channel-state consumers from the concrete channeldb.ChannelStateDB implementation.
  • Consumer Migration: Migrated all in-tree consumers, including funding, peer, channelnotifier, contractcourt, lnrpc, and server, to rely on the new chanstate.Store interface.
  • API Refinement: Updated the FetchChannelByID method signature in channeldb to remove the unnecessary transaction parameter.
  • Documentation: Added release notes to document the channel-state decomposition and migration effort.
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.

@ziggie1984 ziggie1984 force-pushed the chanstate-sql-migration-pr2-consumers branch from 014cbfc to a33d504 Compare May 5, 2026 17:32
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 introduces the chanstate.Store interface to decouple the channel-state subsystem from the concrete channeldb.ChannelStateDB implementation, facilitating a future SQL migration. It updates several components—including the server, funding manager, and various RPC services—to use this new interface. The feedback focuses on improving the consistency of parameter naming within the new interface to align with established LND conventions (e.g., using chanID for lnwire.ChannelID and chanPoint for wire.OutPoint) and notes a placeholder in the release notes that needs to be updated.

Comment thread chanstate/interface.go
// FetchChannelByID attempts to locate a channel specified by the
// passed channel ID. If the channel cannot be found, then an error
// will be returned.
FetchChannelByID(id lnwire.ChannelID) (*channeldb.OpenChannel, error)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

For consistency with other methods in this interface (e.g., SaveInitialForwardingPolicy) and LND conventions, the lnwire.ChannelID parameter should be named chanID instead of id.

Suggested change
FetchChannelByID(id lnwire.ChannelID) (*channeldb.OpenChannel, error)
FetchChannelByID(chanID lnwire.ChannelID) (*channeldb.OpenChannel, error)

Comment thread chanstate/interface.go Outdated

// FetchHistoricalChannel fetches open channel data from the
// historical channel bucket.
FetchHistoricalChannel(outPoint *wire.OutPoint) (
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The parameter name outPoint should be renamed to chanPoint to be consistent with FetchChannel and other methods in this interface that use wire.OutPoint.

Suggested change
FetchHistoricalChannel(outPoint *wire.OutPoint) (
FetchHistoricalChannel(chanPoint *wire.OutPoint) (

Comment thread chanstate/interface.go
Comment thread chanstate/interface.go
Comment thread chanstate/interface.go
Comment thread chanstate/interface.go Outdated
Comment thread docs/release-notes/release-notes-0.22.0.md Outdated
@github-actions github-actions Bot added the severity-critical Requires expert review - security/consensus critical label May 5, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 2026

🔴 PR Severity: CRITICAL

Highest-severity file determines label | 14 files (excl. tests) | ~308 lines changed (excl. tests)

🔴 Critical (5 files)
  • channeldb/db.go - channel state persistence (channeldb/*)
  • contractcourt/breach_arbitrator.go - on-chain dispute/breach handling (contractcourt/*)
  • funding/manager.go - channel funding workflow (funding/*)
  • peer/brontide.go - encrypted peer connection handling (peer/*)
  • server.go - core server coordination
🟠 High (3 files)
  • lnrpc/invoicesrpc/addinvoice.go - RPC/API definition (lnrpc/*)
  • lnrpc/invoicesrpc/config_active.go - RPC/API definition (lnrpc/*)
  • lnrpc/walletrpc/config_active.go - RPC/API definition (lnrpc/*)
🟡 Medium (5 files)
  • channelnotifier/channelnotifier.go - channel notification (uncategorized)
  • chanrestore.go - channel restore (uncategorized root file)
  • chanstate/interface.go - new chanstate package (uncategorized)
  • chanstate/log.go - new chanstate package (uncategorized)
  • subrpcserver_config.go - subrpc server config (uncategorized root file)
🟢 Low (1 file)
  • docs/release-notes/release-notes-0.22.0.md - release notes (docs/*)

Analysis

This PR introduces a new chanstate package and threads it through multiple critical subsystems. The highest-severity files span 5 distinct critical packages: channeldb, contractcourt, funding, peer, and server.go. Any one of these would alone classify the PR as CRITICAL — the breadth across all of them reinforces the classification and warrants careful expert review.

The bulk of the additions (~238 lines) are in the new chanstate/interface.go and chanstate/log.go files. The remaining changes appear to be mechanical refactors threading the new interface through existing callers, but reviewers should verify correctness of each integration point, particularly in contractcourt/breach_arbitrator.go and peer/brontide.go where state handling errors can have on-chain fund safety implications.


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

@ziggie1984 ziggie1984 self-assigned this May 5, 2026
@ziggie1984 ziggie1984 modified the milestone: v0.22.0 May 5, 2026
@github-project-automation github-project-automation Bot moved this to Backlog in lnd v0.22 May 5, 2026
@saubyk saubyk moved this from Backlog to In review in lnd v0.22 May 7, 2026
@Roasbeef
Copy link
Copy Markdown
Member

Roasbeef commented May 8, 2026

Can target master now? Or rather the 1st dep branch.

Copy link
Copy Markdown
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

LGTM 🧜🏼

Straight forward PR, only block dep is on the 1st in the series.

@ziggie1984 ziggie1984 changed the base branch from elle-base-branch-channelstate-native-sql to master May 9, 2026 12:52
@ziggie1984 ziggie1984 force-pushed the chanstate-sql-migration-pr2-consumers branch from a33d504 to 0c0abff Compare May 11, 2026 21:08
@github-actions github-actions Bot added severity-critical Requires expert review - security/consensus critical and removed severity-critical Requires expert review - security/consensus critical labels May 11, 2026
@ziggie1984 ziggie1984 requested a review from yyforyongyu May 11, 2026 21:22
@ziggie1984 ziggie1984 force-pushed the chanstate-sql-migration-pr2-consumers branch 2 times, most recently from 10e1d2f to 599ec09 Compare May 11, 2026 21:39
Replace the funding manager's concrete *channeldb.ChannelStateDB
dependency with chanstate.Store. The manager only uses methods covered
by the store contract, including channel opening state and initial
forwarding policy persistence.
Replace the peer config's concrete channel state DB dependency with
chanstate.Store. Brontide only needs channel lookups, closed-channel
lookup, and initial forwarding policy access from the channel-state
store.
Accept chanstate.Store in ChannelNotifier instead of the concrete
ChannelStateDB. The notifier only fetches open and closed channel
records to populate channel event payloads.
Replace BreachConfig's concrete ChannelStateDB dependency with
chanstate.Store. The breach arbitrator only needs closed-channel reads
and MarkChanFullyClosed from the channel-state store.
@ziggie1984 ziggie1984 force-pushed the chanstate-sql-migration-pr2-consumers branch from 599ec09 to 6659bde Compare May 11, 2026 21:54
Copy link
Copy Markdown
Member

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

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

Need to fix the CI first.

Make chanDBRestorer persist restored channel shells through
chanstate.Store instead of the concrete ChannelStateDB. The restorer
still builds channeldb channel shell values, but only needs
RestoreChannelShells from the store.
Replace concrete ChannelStateDB fields in the invoices and wallet RPC
configs with chanstate.Store, and update the subserver dependency
wiring to pass the interface. The affected RPC paths only need
channel-state store methods for hop hints and waiting-close channel
queries.
Store channel-state access on server as chanstate.Store instead of
*channeldb.ChannelStateDB. Keep link-node access as a separate concrete
*channeldb.LinkNodeDB field so LinkNodeDB does not leak into the
channel-state store contract.
@ziggie1984 ziggie1984 force-pushed the chanstate-sql-migration-pr2-consumers branch from 6659bde to 0376270 Compare May 12, 2026 14:26
@ziggie1984 ziggie1984 requested a review from yyforyongyu May 12, 2026 16:08
@ziggie1984
Copy link
Copy Markdown
Collaborator Author

Need to fix the CI first.

Addressed.

Comment thread server.go

chanStateDB *channeldb.ChannelStateDB
chanStateDB chanstate.Store
linkNodeDB *channeldb.LinkNodeDB
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nits: since this only needs FetchAllLinkNodes, could this be a small private interface instead of storing the concrete *channeldb.LinkNodeDB? That keeps LinkNodeDB out of chanstate.Store while avoiding another concrete field on server.

Comment thread funding/manager.go
ChannelDB *channeldb.ChannelStateDB
// ChannelDB is the database that keeps track of channel state used by
// the funding flow.
ChannelDB chanstate.Store
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nits: this only appears to use open-channel reads plus channel setup methods. Could this field use a narrower private interface embedding chanstate.OpenChannelStore and chanstate.ChannelSetupStore instead of the full chanstate.Store?

Comment thread peer/brontide.go
// ChannelDB is used to fetch opened channels, and closed channels.
ChannelDB *channeldb.ChannelStateDB
// ChannelDB is used to fetch channel state needed by the peer.
ChannelDB chanstate.Store
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nits: this only needs open-channel reads, closed-channel lookup, and initial forwarding policy access. Could this be narrowed to a small private interface rather than full chanstate.Store?

ntfnServer *subscribe.Server

chanDB *channeldb.ChannelStateDB
chanDB chanstate.Store
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nits: the notifier only calls FetchChannel and FetchClosedChannel, so a narrower private interface would preserve the benefit of the sub-interface split without requiring the full chanstate.Store.

@yyforyongyu yyforyongyu merged commit cc65a20 into lightningnetwork:master May 14, 2026
81 of 86 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in lnd v0.22 May 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog refactoring severity-critical Requires expert review - security/consensus critical sql

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants