Skip to content

chanstate: move OpenChannel behind store interface#10808

Open
ziggie1984 wants to merge 33 commits into
lightningnetwork:masterfrom
ziggie1984:chanstate-openchannel-refactor-clean
Open

chanstate: move OpenChannel behind store interface#10808
ziggie1984 wants to merge 33 commits into
lightningnetwork:masterfrom
ziggie1984:chanstate-openchannel-refactor-clean

Conversation

@ziggie1984
Copy link
Copy Markdown
Collaborator

Change Description

This PR prepares the channel-state code for backend-independent storage by
moving the backend-neutral OpenChannel model and related value types into the
new chanstate package.

The end goal is to support multiple channel-state backends, such as the current
KV backend and a future native SQL backend, without forcing channel consumers to
depend on the concrete channeldb.ChannelStateDB implementation. This PR is
the first decomposition step: it introduces the package boundary and interface
shape while intentionally keeping the KV implementation in channeldb.

Review Story

The commits are structured to make the refactor reviewable in small steps:

  1. Create the chanstate.Store contract and split it into domain-focused
    facets instead of one unstructured interface. The store covers open channel
    records, lifecycle updates, status flags, shutdown state, close
    transactions, commitment state, forwarding packages, closed channel
    summaries, final HTLC outcomes, setup state, and link-node maintenance.

  2. Move backend-neutral channel-state value types from channeldb into
    chanstate, keeping compatibility aliases in channeldb for existing
    callers. This includes channel type flags, open channel errors, shutdown
    metadata, channel configs, commitments, log updates, commitment diffs,
    forwarding package types, revocation log types, snapshots, and taproot
    helpers.

  3. Move KV transaction bodies out of OpenChannel receiver methods and onto
    ChannelStateDB. The receivers now call store interface methods instead of
    reaching into the concrete KV backend.

  4. Add narrow migration hooks for fields that are private to OpenChannel but
    still need to be read or written by the KV store implementation while it
    remains in channeldb. These helpers are documented as preliminary store
    hooks and avoid exposing the fields as normal caller API.

  5. Move OpenChannel and its backend-neutral receiver methods into
    chanstate. channeldb.OpenChannel remains as a compatibility alias, so
    broad caller churn is deferred to a later PR.

  6. Remove the temporary generic parameter from the store interfaces once
    OpenChannel lives in chanstate. The final interface shape now uses
    *chanstate.OpenChannel directly while staying backend-independent.

Explicit Non-Goals

  • This PR does not implement a SQL channel-state backend.
  • This PR does not move the KV store implementation out of channeldb.
  • This PR does not broadly migrate callers from channeldb.OpenChannel to
    chanstate.OpenChannel; compatibility aliases intentionally keep that as a
    follow-up.
  • This PR does not remove the existing channeldb aliases. They are kept so
    the package boundary can be introduced without unrelated caller churn.

Current Package Boundary

After this PR:

  • chanstate owns the backend-neutral channel-state model and the store
    interface.
  • channeldb.ChannelStateDB satisfies chanstate.Store.
  • KV-specific bucket helpers, transaction bodies, and serialization helpers
    remain in channeldb/channel.go.
  • chanstate does not import channeldb or kvdb.

Follow-up PRs can then migrate consumers to direct chanstate imports and,
later, move KV implementation code into a chanstate/kvstore.go-style layout.

Steps to Test

Run:

go test ./chanstate ./channeldb
go test -run '^$' ./contractcourt ./htlcswitch ./lnwallet ./peer \
  ./funding ./chanbackup ./chanfitness ./channelnotifier \
  ./lnrpc/invoicesrpc ./lnrpc/walletrpc
make release-install
make lint-native
git diff --check
rg -n '"github.com/lightningnetwork/lnd/channeldb"|kvdb' chanstate \
  --glob '*.go'

Local verification performed:

  • go test ./chanstate ./channeldb passed.
  • The compile-only consumer test listed above passed.
  • make release-install passed.
  • git diff --check passed.
  • The rg check for channeldb/kvdb imports in chanstate returned no
    matches.
  • make lint-native reached the source lint step and was killed locally with
    Killed: 9 before producing diagnostics. This appears to be a local resource
    issue rather than an actionable lint finding.

Pull Request Checklist

Testing

  • Your PR passes all CI checks.
  • Tests covering the positive and negative (error paths) are included.
  • Bug fixes contain tests triggering the bug to prevent regressions.

Code Style and Documentation

No release notes are included because this is an internal refactor with no user
visible behavior change.

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.
Move OpenChannel and its backend-neutral receiver methods into the
chanstate package.

channeldb now keeps a compatibility alias while retaining the KV store
implementation and serialization helpers. Tests that used private
channel status fields now use store-facing accessors.
Drop the temporary channel type parameter from the channel-state
store interfaces now that OpenChannel lives in chanstate.

The domain store facets now refer to *OpenChannel directly while
retaining the same backend-independent shape. Update callers and
compatibility aliases to use the concrete Store and ChannelShell types.
@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 initiates a structural refactor to decouple channel-state storage from the existing KV implementation in channeldb. By introducing the chanstate package and a comprehensive Store interface, the PR establishes a backend-independent model for channel state. This change is a foundational step toward supporting future storage backends, such as SQL, while maintaining backward compatibility through aliases and preserving existing functionality.

Highlights

  • New Package Creation: Created the chanstate package to house backend-neutral channel models and storage interfaces.
  • Interface-Based Storage: Introduced the chanstate.Store interface and its domain-focused facets to decouple storage logic from the concrete KV implementation.
  • Model Migration: Moved OpenChannel and related value types to chanstate, while maintaining compatibility aliases in channeldb to minimize caller churn.
  • Packager Removal: Removed the Packager field from OpenChannel in favor of direct store-level operations.
  • Test Refactoring: Updated existing tests to utilize the new chanstate structures and interfaces, ensuring compatibility with the refactored architecture.
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 performs a significant refactor by moving channel state logic, types, and interfaces from channeldb into a new chanstate package. This change decouples the core channel state management from the specific key-value database implementation, introducing a more modular Store interface. Feedback highlights a critical bug in the newly moved HTLC.Copy method, where missing field assignments and unallocated slices for Signature and ExtraData result in data loss during copying operations.

Comment thread chanstate/commitment.go Outdated
@github-actions github-actions Bot added the severity-critical Requires expert review - security/consensus critical label May 15, 2026
@github-actions
Copy link
Copy Markdown

PR Severity: CRITICAL

Automated classification | 23 non-test files | ~6900 lines changed

Critical files (8): channeldb/channel.go, channeldb/chanstate_assertions.go, channeldb/db.go, channeldb/forwarding_package.go, channeldb/revocation_log.go, htlcswitch/test_utils.go, lnwallet/test_utils.go, peer/test_utils.go

Medium files (15): New chanstate package - chanstate/channel.go, channel_status.go, channel_type.go, close_summary.go, commitment.go, config.go, errors.go, forwarding.go, interface.go, open_channel.go, open_channel_types.go, revocation_log.go, shutdown.go, snapshot.go, taproot.go

Test files excluded (8): channeldb/channel_test.go, channeldb/close_channel_test.go, channeldb/db_test.go, contractcourt/breach_arbitrator_test.go, contractcourt/utils_test.go, htlcswitch/link_test.go, lnwallet/taproot_test_vectors_test.go, lnwallet/transactions_test.go

Analysis: This PR refactors channel state persistence by extracting types from channeldb into a new chanstate package. channeldb/ files are CRITICAL - core channel state persistence with ~2500 lines net change to channel.go, revocation_log.go, and forwarding_package.go. htlcswitch/, lnwallet/, peer/ test utilities also touched. Three bump triggers present (all moot at CRITICAL): 23 non-test files, ~6900 lines, multiple critical packages. Reviewers should verify chanstate/ extraction preserves all channeldb invariants around serialization, revocation logs, and HTLC forwarding.

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

Copy all HTLC fields when cloning channel commitment state.

The old copy method only copied a subset of scalar fields and copied
into nil slices for Signature and ExtraData. Allocate those slices and
deep-copy custom record values so snapshots and channel copies retain
complete HTLC metadata.
@ziggie1984
Copy link
Copy Markdown
Collaborator Author

Code Review — Main Findings

Verdict: approve with minor follow-ups. No blockers. Build / go vet / scoped tests / compile-only consumer pass cleanly. rg confirms chanstate/ imports no channeldb/kvdb/bbolt. KV transaction bodies in the moved code are preserved byte-for-byte; locks and post-success in-memory mirror updates remain in the right place. Compatibility aliases are real type X = chanstate.X aliases (not wrappers).

Findings below are framed as either Phase-2 prep (cheaper to fix before a SQL backend lands) or minor polish.


Major

  1. OpenChannelLifecycleStore.RefreshChannel is a read-with-side-effect, not a lifecycle writechanstate/interface.go:142-143. Every other method in the facet writes persisted lifecycle state. Consider moving it to OpenChannelStore or a dedicated OpenChannelRefresher.

  2. ChannelSetupStore passes opaque serialized bytes through the contractchanstate/interface.go:373-401. SaveChannelOpeningState(outPoint, serializedState []byte) / GetChannelOpeningState([]byte) ([]byte, error) push KV serialization into a backend-neutral interface. A SQL backend will be forced to round-trip a BYTEA it cannot reason about, and the outpoint is opaque bytes rather than wire.OutPoint. Cheaper to type now (one caller) than after SQL lands.

  3. UpdateChannelCommitment returns map[uint64]bool keyed by HTLC indexchanstate/interface.go:240. The map shape implies in-memory accumulation per call and the bool is unnamed. A SQL backend that wants to stream rows would prefer []FinalHtlcResolution{Idx, Settled} or an iterator. The OpenChannel.UpdateCommitment wrapper can keep map semantics if internal callers need it.

  4. Serialization codecs live in the "neutral" packagechanstate/revocation_log.go:292-555 (SerializeRevocationLog, DeserializeRevocationLog, WriteTlvStream, ReadTlvStream, BigSize/uint16 compat shim). A SQL backend storing the log as structured columns inherits dead encoders. Follow-up PR is fine — split value types from byte codecs (e.g. chanstate/codec sub-package, or keep codecs in channeldb as the KV's responsibility).

  5. MarkChannelDataLoss wrapper does not update the in-memory mirrorchanstate/open_channel.go:524. Neighbours like MarkChannelConfirmationHeight (:438-449) and MarkAsOpen (:477-489) do refresh in-memory state after a successful store call. Inconsistent rules mean callers can't predict whether they need RefreshChannel() after a Mark* call. Pick one rule and document it.


Minor

  1. Per-facet Store conformance assertions are missingchanneldb/chanstate_assertions.go:7 only asserts the composite Store. Today the embedding makes this transitively complete, but a future contributor who adds a facet without embedding it into Store won't get a compile error. ~12 lines to harden:

    var (
        _ chanstate.Store                     = (*ChannelStateDB)(nil)
        _ chanstate.OpenChannelStore          = (*ChannelStateDB)(nil)
        _ chanstate.OpenChannelLifecycleStore = (*ChannelStateDB)(nil)
        // ... one per facet
    )
  2. Inconsistent lock acquisition for read-and-call-store methods on OpenChannelchanstate/open_channel.go. DataLossCommitPoint (:533), BroadcastedCommitment (:739), BroadcastedCooperative (:745), RemoteCommitChainTip (:872), UnsignedAckedUpdates (:878), RemoteUnsignedLocalUpdates (:884), LatestCommitments (:1164), RemoteRevocationStore (:1172) all call c.Db.<Fetch>(c) without holding any lock, while CommitmentHeight (:1009) and LoadFwdPkgs (:955) hold c.RLock(). Safe today (store impls only read immutable FundingOutpoint/ShortChannelID) but the inconsistency is a foot-gun. Either uniformly hold c.RLock() or document the invariant.

  3. MarkCommitmentBroadcasted / MarkCoopBroadcasted skip the channel lockchanstate/open_channel.go:718-735, yet MarkBorked (:540) locks. Align them.

  4. TestRefresh lost the Packager.source assertion without a replacementchanneldb/channel_test.go:1427-1453. The invariant (refresh repopulates SCID so packagers built from it target the right key) is now implicit. One-liner restores the regression net:

    require.Equal(t,
        chanOpenLoc,
        newChannelPackager(state).(*ChannelPackager).source)
  5. testChannelStateDB helper is duplicatedcontractcourt/utils_test.go:15-24 and htlcswitch/test_utils.go:46-56 carry verbatim copies. Consolidate into a small shared helper in a follow-up.

  6. NewShutdownInfo is a wrapper function while every other alias-constructor is var X = cstate.Xchanneldb/channel.go:3641-3645. Style consistency only.

  7. Naming drift between status-mutation verbsApplyChannelStatus/ClearChannelStatus (interface.go:175-179) and MarkChannelBorked/MarkChannelDataLoss (:183-192) are all status-bit ops. Defensible if Mark* is the domain verb and Apply/Clear* the generic; add a one-line interface header noting the convention.

  8. HistoricalChannelStore.FetchHistoricalChannel(*wire.OutPoint)chanstate/interface.go:130 — takes a pointer while OpenChannelStore.FetchChannel(wire.OutPoint) (:81) takes a value. Pick one.

  9. AdvanceCommitChainTail has four positional args including paired output indiceschanstate/interface.go:267-269. Easy to swap ourOutputIndex / theirOutputIndex. Consider an AdvanceCommitTailParams struct now while there is one caller per backend.

  10. OpenChannel.Packager field removal not called out in the PR description. Every caller now uses newChannelPackager(channel) which derives from channel.ShortChannelID updated in the same critical section. Functionally identical, but worth one bullet under "API impact" so reviewers grepping for .Packager in downstream forks know to expect compile errors.


Nits

  • ChanCount (chanstate/channel.go:4) — PeerChanCounts reads better at call sites.
  • OpenChannel.Db (chanstate/open_channel.go:219) holds a Store, not a *DB. Track for the follow-up that drops the channeldb aliases.
  • LinkNodeMaintainer (chanstate/interface.go:404-414) — LinkNodeAdmin better matches the Prune* / Repair* content.
  • FetchChannelBroadcastedCommitment / …Cooperative (chanstate/interface.go:221-227) — FetchBroadcastedCommitTx / FetchBroadcastedCoopTx mirror the existing Mark*Broadcasted(closeTx *wire.MsgTx, …) signature better.

Risk note

severity-critical is justified by the surface area (~4 kLoC moved), not by any consensus-path behavior change observable in this PR. The biggest unobserved risk is the migration-hook API (ForStore accessors) — clearly marked as transitional, but it exposes locks-by-caller-contract that future code might mishandle. Tracking removal alongside the KV move into chanstate will keep this honest.

@ziggie1984 ziggie1984 self-assigned this May 15, 2026
@github-project-automation github-project-automation Bot moved this to Backlog in lnd v0.22 May 15, 2026
@ziggie1984 ziggie1984 added this to the v0.22.0 milestone May 15, 2026
@ziggie1984
Copy link
Copy Markdown
Collaborator Author

Correction: pre-existing findings

ziggie pointed out (correctly) that this PR is mostly code-movement and most of my findings reproduce conditions already in master. I audited each one against master; here is the corrected ledger.

Withdrawn — pre-existing on master

  • B1 RefreshChannelRefresh() already had this read-with-side-effect shape on master (channeldb/channel.go:1378). The facet membership is new in this PR, but the method's semantics aren't. Soft suggestion only.
  • B2 ChannelSetupStore opaque bytes(*ChannelStateDB).SaveChannelOpeningState(outPoint, serializedState []byte) / GetChannelOpeningState([]byte) ([]byte, error) already existed verbatim on master (channeldb/db.go:1807,1823). The PR only promotes the pre-existing signature into the interface.
  • B3 UpdateChannelCommitment returns map[uint64]bool — already the return signature on master (channeldb/channel.go:2512). Not introduced here.
  • C7 Inconsistent lock acquisition for read methods — same pattern on master: DataLossCommitPoint, BroadcastedCommitment/BroadcastedCooperative (via getClosingTx), RemoteCommitChainTip, UnsignedAckedUpdates, LatestCommitments, RemoteRevocationStore all read lock-free; LoadFwdPkgs and CommitmentHeight take c.RLock(). Pre-existing.
  • C8 MarkCommitmentBroadcasted / MarkCoopBroadcasted skip the channel lock — same on master (channeldb/channel.go:2179, 2195). Both delegate to markBroadcasted without taking c.Lock(). Pre-existing.
  • C12 Mark* / Apply* / Clear* naming drift — already on master (ApplyChanStatus, ClearChanStatus alongside MarkBorked, MarkDataLoss, etc.). Pre-existing.
  • C13 FetchChannel(wire.OutPoint) vs FetchHistoricalChannel(*wire.OutPoint) pointer/value mismatch — already on master (db.go:711, 2088). Pre-existing.
  • C14 AdvanceCommitChainTail positional args — same signature on master (channeldb/channel.go:3493). Pre-existing.
  • D nits (ChanCount, LinkNodeMaintainer, FetchChannelBroadcasted* names) — names mirror their pre-existing master equivalents. The OpenChannel.Db nit (now holds a Store) is the only one genuinely new, and it's still cosmetic.

Retracted — finding was wrong

  • B5 MarkChannelDataLoss does not update the in-memory mirror. False. chanstate.OpenChannel.MarkDataLoss (open_channel.go:524) calls c.Db.MarkChannelDataLoss(c, …) which calls (*ChannelStateDB).putChanStatus(channel, …) (channeldb/channel.go:1355), and that function ends with channel.SetChannelStatusForStore(status) at line 1399 — exactly mirroring master's c.chanStatus = status at the end of putChanStatus. I was misled by reading only the thin wrapper without following the chain. Apologies.

Stands — genuinely about this PR

  • B4 Serialization codecs live in chanstate/revocation_log.go:292-555. The codecs themselves are pre-existing (just moved out of channeldb), but the choice to put them in the backend-neutral package is this PR's decision. A SQL backend that stores the log as structured columns inherits dead encoders. Follow-up PR is fine.
  • C6 Per-facet Store conformance assertions. channeldb/chanstate_assertions.go is a new file in this PR; the choice of a single composite assertion vs. per-facet is genuinely a decision being made here. ~12 lines to harden.
  • C9 TestRefresh lost the Packager.source assertionchanneldb/channel_test.go:1427-1453. The deletion is in this PR; the replacement one-liner (require.Equal(t, chanOpenLoc, newChannelPackager(state).(*ChannelPackager).source)) restores the regression net.
  • C10 testChannelStateDB helper duplicated in contractcourt/utils_test.go:15-24 and htlcswitch/test_utils.go:46-56. New code in this PR.
  • C11 NewShutdownInfo is a wrapper function while every other alias-constructor is var X = cstate.X (channeldb/channel.go:3641-3645). New aliasing pattern in this PR — pure style consistency.
  • B1 / D Db field name now holds a Store — cosmetic, but only relevant once the channeldb aliases drop.

Net

Genuinely actionable items for this PR: B4, C6, C9, C10, C11. Everything else is either pre-existing behavior preserved by the move (the goal of the PR) or a Phase-2 design conversation that doesn't need to gate this merge.

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: In progress

Development

Successfully merging this pull request may close these issues.

1 participant