Skip to content

chanstate: move channel state kv store#10812

Open
ziggie1984 wants to merge 116 commits into
lightningnetwork:masterfrom
ziggie1984:chanstate-kv-store-move
Open

chanstate: move channel state kv store#10812
ziggie1984 wants to merge 116 commits into
lightningnetwork:masterfrom
ziggie1984:chanstate-kv-store-move

Conversation

@ziggie1984
Copy link
Copy Markdown
Collaborator

@ziggie1984 ziggie1984 commented May 18, 2026

Is based on #10808 and #10809

Context

Part of #10680. This PR continues the channel-state decomposition by
moving the OpenChannel type and KV-backed channel-state store facets into
chanstate. The goal is to make channel-state callers depend on the
chanstate store contract instead of backend-specific channeldb details,
while keeping the current KV backend behavior unchanged.

Story

The refactor is structured as a compatibility-preserving move. Existing
callers can still use channeldb.ChannelStateDB, but the concrete KV
implementation for channel-state facets now lives in chanstate.KVStore.
This lets later PRs introduce alternate backends behind the same domain
interfaces without first changing every call site.

The PR also moves OpenChannel and related value types into chanstate, then
updates consumers to use the chanstate type directly. channeldb keeps type
aliases and thin wrappers only as a transition layer for existing imports.

What moved

  • OpenChannel and channel-state value types now live in chanstate.
  • Store interfaces are split into domain facets and composed into Store.
  • KV-backed store methods moved by domain into chanstate kv_ files.
  • Open-channel lifecycle, status, close-tx, shutdown, commitment,
    forwarding-package, final-HTLC, historical-channel, closed-summary, and
    open-channel read paths are now implemented on chanstate.KVStore.
  • channeldb.ChannelStateDB now delegates most channel-state operations to
    chanstate.KVStore.

Intentional boundaries

  • Migration packages are not moved.
  • LinkNode ownership remains in channeldb for this PR. Methods that create,
    repair, or prune LinkNodes stay in channeldb until a follow-up LinkNode
    store boundary is introduced.
  • channeldb compatibility wrappers remain while production callers still use
    ChannelStateDB and while OpenChannel receiver methods still require a
    Store reference. A follow-up should remove OpenChannel.Db by converting
    persistence receiver calls to store-method calls.

Verification

  • go test ./chanstate ./channeldb
  • git diff --check
  • make lint-native
  • make release-install

ziggie1984 added 30 commits May 14, 2026 16:50
Move the small value types referenced by chanstate.Store out of
channeldb. This includes ChannelConfig, ChannelStatus,
ChannelCloseSummary, ChannelShell, ChanCount, and FinalHtlcInfo. Leave
aliases in channeldb so existing callers keep compiling while the
backend still lives there.

Parameterize the Store facets over the channel type and instantiate
current callers with *channeldb.OpenChannel. This removes the chanstate
-> channeldb import edge without moving OpenChannel yet, keeping the
first step reviewable and backend-neutral.
Move ChannelType and its flag helpers into chanstate while leaving
compatibility aliases in channeldb. This is a backend-neutral value
type and does not require moving any KV serialization logic.

Keep the full type documentation with the moved chanstate definition.
The channeldb aliases preserve the existing public surface while later
commits continue moving OpenChannel state out of the KV package.
Move the OpenChannel error definitions into chanstate and leave
channeldb aliases for existing callers. These errors describe channel
state behavior rather than a concrete KV bucket layout.

Keeping the aliases preserves the public channeldb API while later
commits move more OpenChannel state and receiver logic toward
chanstate.
Move the ShutdownInfo state type, constructor, and closer helper into
chanstate. The type describes channel shutdown state and is not tied to
the concrete KV backend.

Keep the TLV encode and decode helpers in channeldb for now, since
those functions describe the current persisted format. The channeldb
constructor remains as a compatibility wrapper.
Add a lifecycle facet to the chanstate Store contract for refresh,
confirmation, open-state, and SCID mutations. Implement the facet on
ChannelStateDB using the existing KV persistence code.

Update the matching OpenChannel receivers to call through the store
methods instead of reaching into the ChannelStateDB backend directly.
Also convert fullSync into a channeldb helper so that KV-specific code
is no longer an OpenChannel receiver.
Add a status facet to the chanstate Store contract for status bit
updates and data-loss commit point handling. Implement the facet on
ChannelStateDB using the existing persistence code.

Update the matching OpenChannel receivers to call through the store
methods. The broadcast path still uses a private channeldb helper until
its closing-transaction facet is introduced in a later commit.
Add shutdown and close-transaction facets to the chanstate Store
contract. These cover persisted shutdown info plus stored unilateral
and cooperative closing transactions.

Implement the facets on ChannelStateDB with the existing KV code and
update OpenChannel receivers to call through the store methods. The
backend-specific key selection remains private to channeldb.
Add pending-channel setup to the chanstate lifecycle store facet. This
covers the path that writes a new pending channel and records the
funding broadcast height.

Move the OpenChannel receiver to call through ChannelStateDB and pass
the backend explicitly into the channeldb sync helper. This keeps the
link-node persistence detail in channeldb while removing another direct
backend reference from OpenChannel.
Move ChannelCommitment and HTLC into chanstate so upcoming store facets
can name commitment state without importing channeldb.

Leave the KV serialization helpers in channeldb and keep aliases for
existing call sites. This preserves the current disk format and keeps
backend-specific persistence code out of chanstate for now.
Move LogUpdate into chanstate so commitment store interfaces can refer
to pending update state without importing channeldb.

Keep the log-update serialization helpers in channeldb. Those helpers
remain part of the existing KV disk format and can move with the KV
backend implementation later.
Add a commitment-focused store facet for updating local channel
commitment state. This lets OpenChannel call through the chanstate
store contract instead of reaching directly into the KV backend.

Keep the existing KV transaction body on ChannelStateDB for now. The
receiver still owns locking and in-memory state updates while the store
method owns persistence.
Move CommitDiff and its forwarding reference types into chanstate. This
lets the next commitment store facet name pending remote commitment
state without importing channeldb.

Keep forwarding package persistence and commit-diff serialization in
channeldb for now. The aliases preserve existing call sites while the
KV backend code remains in place.
Add the remote commitment-chain append method to the chanstate
commitment store facet.

Move the existing KV transaction body onto ChannelStateDB and have the
OpenChannel receiver call through the store. This removes another
direct backend dependency from OpenChannel while keeping KV persistence
code in channeldb.
Add read-side commitment lookup methods to the chanstate commitment
store facet.

Move the existing OpenChannel KV view transaction bodies onto
ChannelStateDB. Leave the OpenChannel receivers as store-call wrappers.
This removes three more direct backend references from the receiver
code without changing the persisted data format.
Add the next-revocation persistence method to the chanstate commitment
store facet.

Move the existing OpenChannel KV update body onto ChannelStateDB. The
OpenChannel receiver keeps the external locking behavior and delegates
persistence through the store interface.
Move FwdState, PkgFilter, and FwdPkg into chanstate with their existing
comments and helper methods.

Leave channeldb aliases for the moved value types and constructors so
current callers keep compiling. The KV forwarding package persistence
code stays in channeldb.
Add the commitment-tail advancement method to the chanstate commitment
store facet.

Move the existing AdvanceCommitChainTail KV transaction body onto
ChannelStateDB. The OpenChannel receiver now keeps locking and restored
channel checks before delegating persistence through the store.
Add a forwarding-package store facet to chanstate.Store.

Move the existing OpenChannel forwarding-package KV transaction bodies
onto ChannelStateDB. The OpenChannel receivers keep their locking
behavior and delegate package loading, acking, filtering, and removal
through the store.
Add commitment-height, latest-commitment, and remote revocation store
lookups to the chanstate commitment store facet.

Move the existing OpenChannel KV view transaction bodies onto
ChannelStateDB. This leaves the receivers as store-call wrappers while
keeping the persisted format and read behavior unchanged.
Move the remaining OpenChannel revocation-log KV reads onto
ChannelStateDB.

This keeps FindPreviousState and the unit-test tail-height helper as
OpenChannel wrappers. It removes direct backend access from the
receiver methods while leaving RevocationLog in channeldb for now.
Move the revocation-log value types and TLV serialization helpers into
chanstate.

Leave channeldb aliases and wrapper functions for the existing KV
persistence code and tests. Bucket keys, errors, and transaction
helpers stay in channeldb, so this commit only moves backend-neutral
state data.
Add FindPreviousState to the chanstate commitment store facet now that
RevocationLog is a chanstate value type.

This extends the store contract without changing runtime behavior. The
existing ChannelStateDB method already satisfies the new method.
Keep the revocation-log tail-height helper on ChannelStateDB instead of
the OpenChannel receiver.

The helper is only used by channeldb tests, so it should not become
part of the backend-independent chanstate store contract. The tests now
call the concrete helper directly.
Change OpenChannel.Db to the composed chanstate Store interface while
keeping the existing field name.

Tests that need raw channeldb access now assert the concrete test
backend explicitly instead of reaching through OpenChannel.Db. This
keeps backend setup out of the store contract.
Convert the KV-only OpenChannel helpers for TLV aux data and
borked-state lookup into package-level channeldb helpers.

This keeps serialization and bucket inspection code tied to the KV
backend while leaving the OpenChannel receiver set closer to the future
chanstate type.
Add transitional OpenChannel accessors for the channel status and
confirmed SCID fields used by KV store code.

These helpers keep the fields private while allowing channeldb backend
code to continue hydrating and serializing channel state after
OpenChannel moves to chanstate.
Remove the KV forwarding packager from OpenChannel and derive a
ChannelPackager inside the channeldb store methods that need one.

This keeps the backend-specific kvdb transaction helper in channeldb,
so the OpenChannel type no longer carries that dependency toward
chanstate.
Move the backend-neutral ChannelSnapshot value type into chanstate and
leave channeldb with a compatibility alias.

This keeps the future OpenChannel Snapshot receiver close to its return
type without changing existing channeldb callers.
Move the backend-neutral taproot shachain and verification nonce
helpers into chanstate with the thaw-height threshold they support.

Leave channeldb aliases for existing callers while OpenChannel and its
receiver methods are moved across the package boundary.
Add a transitional non-locking status predicate for channeldb store
code and use it from KV serialization helpers.

This avoids calling an unexported OpenChannel helper from channeldb
after the type moves into chanstate.
ziggie1984 added 18 commits May 18, 2026 10:26
Move the local commitment update path into the chanstate KV store
implementation. Keep channeldb as the public wrapper and pass the
final-HTLC storage option through to preserve existing behavior.
Move the close/archive channel paths into the chanstate KV store
implementation. Keep channeldb as the public wrapper and preserve the
existing sync/tombstone strategy selection at the boundary.
Move the refresh path into the chanstate open-channel KV store
implementation. Keep channeldb as a public wrapper and remove private
helpers that were only used by the old refresh implementation.
Move the pending open-channel write into the chanstate KV store
implementation while keeping link-node creation in channeldb. Preserve
the existing transaction boundary used by pending channels and restores.
Fold the channel key and thaw-height helpers into the store files
that own them, instead of keeping separate kv files that do not
represent their own stores.

The open-channel keys and thaw-height helpers now live with
kv_open_channel, closed-channel bucket ownership lives with
kv_close_summary, and commitment/update keys live with kv_commitment.
Move the KV-backed ChannelSetupStore implementation onto the
chanstate KVStore. This includes both channel-opening state and initial
forwarding policy persistence, which together make up the setup store
facet.

Keep the channeldb ChannelStateDB methods as compatibility wrappers so
callers can continue using the old package while the concrete KV store
implementation moves by facet.
Move the KV-backed FinalHTLCStore implementation onto KVStore. The
ChannelStateDB methods keep compatibility wrappers while final HTLC
lookup and on-chain outcome writes now live with the final HTLC KV store
code.

Carry the store-final-resolution option into KVStore so the on-chain
outcome path keeps the existing opt-in behavior.
Move the KV-backed OpenChannelFwdPkgStore implementation onto
KVStore. ChannelStateDB keeps the existing wrapper methods, but now
delegates through the channelstate KV store instead of passing its
backend into package-level helpers.

This keeps forwarding package persistence grouped with the existing
kv_forwarding_package code while removing another direct backend use
from the channeldb compatibility layer.
Move the KV-backed OpenChannelShutdownStore methods onto KVStore.
ChannelStateDB keeps the existing compatibility methods, but shutdown
state now flows through the channelstate KV store rather than backend
helper functions.

The bucket-level shutdown codec helper stays in kv_shutdown because it
is still the local serialization primitive used by the store method.
Move the KV-backed OpenChannelCloseTxStore implementation onto
KVStore. ChannelStateDB keeps compatibility wrappers for marking and
fetching broadcast close transactions while the KV logic now lives in
kv_close_tx.

Keep the generic close transaction fetch helper private to KVStore and
expose only the domain methods required by the channelstate interface.
Move the KV-backed OpenChannelStatusStore implementation onto
KVStore. ChannelStateDB keeps compatibility wrappers while status
updates, data-loss commit point lookup, and borked marking now flow
through the channelstate KV store.

Keep the status write helper private to KVStore so related KV store
facets can share the same status mutation path without passing raw
backends around.
Move the backend-local open channel lifecycle mutations onto KVStore.
ChannelStateDB keeps compatibility wrappers for refreshing channel state
and marking confirmation, open, real scid, and scid-alias negotiation
state.

Leave SyncPendingChannel in channeldb for now because that path still
creates link-node records, and LinkNodeDB ownership remains in channeldb
for this refactor.
Move the KV-backed open channel commitment store methods onto
KVStore. ChannelStateDB keeps compatibility wrappers for commitment
updates, pending commit diffs, revocation queries, and previous-state
lookups.

Carry the no-rev-log-amount-data option into KVStore alongside the
existing final HTLC option so revocation log and final-resolution writes
preserve their previous configuration behavior.
Move the KV-backed revocation log tail helper onto KVStore. This
removes the last direct backend call from the channeldb open channel
compatibility methods while keeping the test-facing helper in place.
Move closed-channel summary reads and CloseChannel onto KVStore.
ChannelStateDB keeps compatibility wrappers, while the KV code for close
summary lookup and close archiving now lives with kv_close_summary.

Carry the tombstone-close option into KVStore so the existing close
strategy selection remains unchanged. Leave MarkChanFullyClosed and
AbandonChannel in channeldb because they still coordinate link-node
pruning and cross-store behavior.
Move historical channel bucket lookup and FetchHistoricalChannel onto
KVStore. The channeldb wrapper still attaches itself to channel.Db so
existing callers continue to receive a compatibility store reference.

Move ErrNoHistoricalBucket into chanstate and keep the channeldb error
as an alias, matching the other channel-state errors that have moved.
Move the KV-backed open channel read and scan methods onto KVStore.
ChannelStateDB keeps compatibility wrappers that attach themselves to
returned OpenChannel values so existing receiver methods still use the
channeldb store.

Leave restore and sync paths in channeldb because they still coordinate
link-node creation and repair while LinkNodeDB ownership remains outside
chanstate.
Move the KV-backed AbandonChannel implementation onto KVStore.
ChannelStateDB keeps a compatibility wrapper while callers still import
channeldb for the channel-state store.

Keep the link-node-coupled close and repair methods in channeldb so
the follow-up LinkNode store can define that boundary explicitly.
@ziggie1984 ziggie1984 self-assigned this May 18, 2026
@github-actions github-actions Bot added the severity-critical Requires expert review - security/consensus critical label May 18, 2026
@ziggie1984 ziggie1984 added this to the v0.22.0 milestone May 18, 2026
@github-project-automation github-project-automation Bot moved this to Backlog in lnd v0.22 May 18, 2026
@github-actions
Copy link
Copy Markdown

🔴 PR Severity: CRITICAL

Automated classification | 74 non-test files | ~19,200 lines changed (non-test)

🔴 Critical (31 files)
  • channeldb/channel.go - channel state persistence (+463/-4929); massive refactor
  • channeldb/db.go - core database layer (+83/-982)
  • channeldb/forwarding_package.go - forwarding package persistence (+60/-994)
  • channeldb/revocation_log.go - revocation log persistence (+47/-668)
  • channeldb/codec.go - channel data serialization (+7/-421)
  • channeldb/forwarding_policy.go - forwarding policy persistence (+3/-83)
  • channeldb/chanstate_assertions.go - channel state assertion helpers (new)
  • channeldb/error.go - channeldb error definitions
  • channeldb/legacy_serialization.go - legacy serialization
  • contractcourt/chain_arbitrator.go - on-chain dispute coordination
  • contractcourt/channel_arbitrator.go - per-channel arbitration state machine
  • contractcourt/chain_watcher.go - chain event monitoring
  • contractcourt/anchor_resolver.go - anchor output resolution
  • contractcourt/breach_resolver.go - breach transaction handling
  • contractcourt/commit_sweep_resolver.go - commitment sweep resolution
  • contractcourt/contract_resolver.go - contract resolution base
  • contractcourt/htlc_lease_resolver.go - HTLC lease resolution
  • contractcourt/htlc_success_resolver.go - HTLC success resolution
  • contractcourt/htlc_timeout_resolver.go - HTLC timeout resolution
  • htlcswitch/link.go - HTLC forwarding link state machine
  • htlcswitch/switch.go - HTLC switch routing
  • htlcswitch/circuit_map.go - payment circuit tracking
  • htlcswitch/interfaces.go - switch interface definitions
  • htlcswitch/mock.go - switch mock (updated for interface changes)
  • lnwallet/channel.go - channel commitment management
  • lnwallet/commitment.go - commitment transaction construction
  • lnwallet/reservation.go - channel funding reservation
  • lnwallet/aux_leaf_store.go - auxiliary leaf storage
  • lnwallet/wallet.go - wallet operations
  • peer/brontide.go - encrypted peer connection handling
  • funding/manager.go - channel funding workflow
🟠 High (4 files)
  • discovery/ban.go - gossip peer banning
  • discovery/gossiper.go - network gossip protocol
  • lnrpc/invoicesrpc/addinvoice.go - invoice creation RPC
  • lnrpc/walletrpc/walletkit_server.go - wallet RPC server
🟡 Medium (39 files)
  • chanstate/kv_open_channel.go - new KV store for open channel data (+2150)
  • chanstate/kv_commitment.go - new KV store for commitments (+1350)
  • chanstate/kv_forwarding_package.go - new KV store for forwarding packages (+892)
  • chanstate/kv_revocation_log.go - new KV store for revocation logs (+698)
  • chanstate/kv_close_summary.go - new KV store for close summaries (+577)
  • chanstate/open_channel.go - open channel type definitions (+1256)
  • chanstate/codec.go - chanstate serialization (+464)
  • chanstate/interface.go - chanstate public interface (+234/-36)
  • chanstate/commitment.go - commitment types (+304)
  • chanstate/forwarding.go - forwarding types (+259)
  • chanstate/kv_final_htlc.go - KV store for final HTLCs (+256)
  • chanstate/kv_channel_setup.go - KV store for channel setup (+208)
  • chanstate/revocation_log.go - revocation log types (+200)
  • chanstate/kv_shutdown.go - KV store for shutdown (+136)
  • chanstate/close_summary.go - close summary types (+126)
  • chanstate/channel_type.go - channel type definitions (+157)
  • chanstate/channel_status.go - channel status types (+110)
  • chanstate/config.go - chanstate config (+108)
  • chanstate/errors.go - chanstate errors (+90)
  • chanstate/taproot.go - taproot-specific state (+79)
  • chanstate/snapshot.go - channel snapshot (+44)
  • chanstate/shutdown.go - shutdown types (+41)
  • chanstate/kv_store.go - KV store base (+35)
  • chanstate/channel.go - channel base types (+18)
  • chanstate/open_channel_types.go - open channel type aliases (+16)
  • chanbackup/backup.go - channel backup logic
  • chanbackup/pubsub.go - backup pub/sub
  • chanbackup/single.go - single channel backup
  • chanfitness/chaneventstore.go - channel fitness tracking
  • channelnotifier/channelnotifier.go - channel event notifications
  • netann/chan_status_manager.go - channel status announcements
  • netann/interface.go - netann interfaces
  • lnpeer/peer.go - peer interface definition
  • channel_notifier.go - root channel notifier
  • chanrestore.go - root channel restore

Analysis

This PR is a large-scale architectural refactoring that extracts channel state management code from channeldb into a new chanstate package. The severity is CRITICAL for multiple independent reasons:

  1. Multiple distinct critical packages touched: channeldb, contractcourt, htlcswitch, lnwallet, peer, and funding — six CRITICAL packages are modified.

  2. Massive channeldb restructuring: channeldb/channel.go alone sees +463/−4,929 lines, with db.go (−982), forwarding_package.go (−994), and revocation_log.go (−668) all experiencing large removals as code is extracted to the new chanstate package.

  3. Scale exceeds thresholds: 74 non-test files and ~19,200 non-test lines changed — both well beyond the 20-file and 500-line bump thresholds.

  4. New chanstate package: ~10,000 lines of new channel state persistence code. While not yet in the classified package list, this is functionally channel state database code (KV store implementations for commitments, HTLC packages, revocation logs, and channel lifecycle data) — the most safety-critical data in an LN node.

Reviewers should pay particular attention to the data migration path (if any), the correctness of the serialization code moved from channeldb to chanstate, and that all callers in contractcourt, htlcswitch, and lnwallet correctly use the new interfaces.


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

@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 continues the decomposition of the channel state management system by migrating core data types and KV-backed store logic into a dedicated 'chanstate' package. This refactor improves modularity by allowing channel-state callers to depend on a clean domain-driven contract rather than backend-specific implementation details. The changes are structured to be compatibility-preserving, ensuring existing codebases continue to function while providing a foundation for future backend support.

Highlights

  • Package Decomposition: Introduced the new 'chanstate' package to house channel state data types and KV-backed store implementations, decoupling them from 'channeldb'.
  • Store Contract Refactoring: Split store interfaces into domain-specific facets and composed them into a unified 'Store' interface, allowing for future backend flexibility.
  • Compatibility Layer: Maintained backward compatibility by retaining type aliases and thin wrappers in 'channeldb' while migrating production call sites to 'chanstate'.
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 the channel state management by migrating core types, constants, and logic from the channeldb package into a new, dedicated chanstate package. It introduces a Store interface to abstract the persistence layer, allowing for backend-independent channel state operations. Widespread changes across the codebase update references to use the new chanstate types, while channeldb retains compatibility aliases to facilitate an incremental transition. I have no feedback to provide as the review comments were found to be inaccurate regarding the provided code changes.

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

Labels

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

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant