What changed, and why it matters
This commit only adds a new Go interface definition and a package logger. It does not change any existing behavior, fix any bug, or alter how data is stored or accessed. There is no security-relevant change for users or operators.
No action required. This is a non-functional refactoring commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit introduces a chanstate.Store interface that mirrors the public methods of channeldb.ChannelStateDB, plus a compile-time type assertion and a new chanstate sub-logger registered in the root logger setup. No consumers are migrated to the interface and no implementation logic is modified. It is a pure refactoring/infrastructure change.
Changed components
chanstate/interface.gochanstate/log.golog.goInspect captured patch +261 / −0
diff --git a/chanstate/interface.go b/chanstate/interface.go
new file mode 100644
index 0000000..4934485
--- /dev/null
+++ b/chanstate/interface.go
@@ -0,0 +1,228 @@
+package chanstate
+
+import (
+ "github.com/btcsuite/btcd/btcec/v2"
+ "github.com/btcsuite/btcd/wire"
+ "github.com/lightningnetwork/lnd/channeldb"
+ "github.com/lightningnetwork/lnd/graph/db/models"
+ "github.com/lightningnetwork/lnd/lnwire"
+)
+
+// Store is the full persistence contract for the channel-state subsystem.
+// Consumers depend on this interface rather than the concrete
+// channeldb.ChannelStateDB so the underlying storage can be swapped without
+// touching call sites.
+//
+// NOTE: This is named Store instead of DB to avoid confusion with the existing
+// concrete channeldb.ChannelStateDB type during the migration. Once the channel
+// state implementation moves into this package and the old concrete type is no
+// longer part of consumer-facing code, this name can be revisited.
+type Store interface {
+ // OpenChannelStore owns open-channel records.
+ OpenChannelStore
+
+ // HistoricalChannelStore owns the post-close historical channel view.
+ HistoricalChannelStore
+
+ // ClosedChannelStore owns closed-channel summaries and lifecycle
+ // mutations.
+ ClosedChannelStore
+
+ // FinalHTLCStore owns final HTLC outcome data.
+ FinalHTLCStore
+
+ // ChannelSetupStore owns temporary state used while setting up a
+ // channel.
+ ChannelSetupStore
+
+ // LinkNodeMaintainer owns link-node maintenance derived from channel
+ // state.
+ LinkNodeMaintainer
+}
+
+// OpenChannelStore owns open-channel records.
+type OpenChannelStore interface {
+ // FetchOpenChannels starts a new database transaction and returns
+ // all stored currently active/open channels associated with the
+ // target nodeID. In the case that no active channels are known to
+ // have been created with this node, then a zero-length slice is
+ // returned.
+ FetchOpenChannels(nodeID *btcec.PublicKey) (
+ []*channeldb.OpenChannel, error)
+
+ // FetchChannel attempts to locate a channel specified by the passed
+ // channel point. If the channel cannot be found, then an error will
+ // be returned.
+ FetchChannel(chanPoint wire.OutPoint) (*channeldb.OpenChannel, error)
+
+ // 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)
+
+ // FetchAllChannels attempts to retrieve all open channels currently
+ // stored within the database, including pending open, fully open and
+ // channels waiting for a closing transaction to confirm.
+ FetchAllChannels() ([]*channeldb.OpenChannel, error)
+
+ // FetchAllOpenChannels will return all channels that have the
+ // funding transaction confirmed, and is not waiting for a closing
+ // transaction to be confirmed.
+ FetchAllOpenChannels() ([]*channeldb.OpenChannel, error)
+
+ // FetchPendingChannels will return channels that have completed the
+ // process of generating and broadcasting funding transactions, but
+ // whose funding transactions have yet to be confirmed on the
+ // blockchain.
+ FetchPendingChannels() ([]*channeldb.OpenChannel, error)
+
+ // FetchWaitingCloseChannels will return all channels that have been
+ // opened, but are now waiting for a closing transaction to be
+ // confirmed.
+ //
+ // NOTE: This includes channels that are also pending to be opened.
+ FetchWaitingCloseChannels() ([]*channeldb.OpenChannel, error)
+
+ // FetchPermAndTempPeers returns a map where the key is the remote
+ // node's public key and the value is a struct that has a tally of
+ // the pending-open channels and whether the peer has an open or
+ // closed channel with us.
+ FetchPermAndTempPeers(chainHash []byte) (
+ map[string]channeldb.ChanCount, error)
+
+ // RestoreChannelShells reconstructs the state of an OpenChannel from
+ // the ChannelShell. We'll attempt to write the new channel to disk,
+ // create a LinkNode instance with the passed node addresses, and
+ // finally create an edge within the graph for the channel as well.
+ // This method is idempotent, so repeated calls with the same set of
+ // channel shells won't modify the database after the initial call.
+ RestoreChannelShells(channelShells ...*channeldb.ChannelShell) error
+}
+
+// HistoricalChannelStore owns the post-close historical channel view.
+type HistoricalChannelStore interface {
+ // FetchHistoricalChannel fetches open channel data from the
+ // historical channel bucket.
+ FetchHistoricalChannel(outPoint *wire.OutPoint) (
+ *channeldb.OpenChannel, error)
+}
+
+// ClosedChannelStore owns closed-channel summaries and lifecycle mutations.
+type ClosedChannelStore interface {
+ // FetchClosedChannels attempts to fetch all closed channels from the
+ // database. The pendingOnly bool toggles if channels that aren't yet
+ // fully closed should be returned in the response or not. When a
+ // channel was cooperatively closed, it becomes fully closed after a
+ // single confirmation. When a channel was forcibly closed, it will
+ // become fully closed after _all_ the pending funds (if any) have
+ // been swept.
+ FetchClosedChannels(pendingOnly bool) (
+ []*channeldb.ChannelCloseSummary, error)
+
+ // FetchClosedChannel queries for a channel close summary using the
+ // channel point of the channel in question.
+ FetchClosedChannel(chanID *wire.OutPoint) (
+ *channeldb.ChannelCloseSummary, error)
+
+ // FetchClosedChannelForID queries for a channel close summary using
+ // the channel ID of the channel in question.
+ FetchClosedChannelForID(cid lnwire.ChannelID) (
+ *channeldb.ChannelCloseSummary, error)
+
+ // MarkChanFullyClosed marks a channel as fully closed within the
+ // database. A channel should be marked as fully closed if the
+ // channel was initially cooperatively closed and it's reached a
+ // single confirmation, or after all the pending funds in a channel
+ // that has been forcibly closed have been swept.
+ MarkChanFullyClosed(chanPoint *wire.OutPoint) error
+
+ // CloseChannel marks the given channel as closed: the open-channel
+ // record is removed and the supplied ChannelCloseSummary is
+ // archived so the channel becomes retrievable via
+ // FetchClosedChannel and FetchClosedChannelForID. Any ChannelStatus
+ // values are merged into the archived summary. Returns
+ // ErrChannelCloseSummaryNil if summary is nil.
+ CloseChannel(channel *channeldb.OpenChannel,
+ summary *channeldb.ChannelCloseSummary,
+ statuses ...channeldb.ChannelStatus) error
+
+ // AbandonChannel attempts to remove the target channel from the open
+ // channel database. If the channel was already removed (has a closed
+ // channel entry), then we'll return a nil error. Otherwise, we'll
+ // insert a new close summary into the database.
+ AbandonChannel(chanPoint *wire.OutPoint, bestHeight uint32) error
+}
+
+// FinalHTLCStore owns final HTLC outcome data.
+type FinalHTLCStore interface {
+ // LookupFinalHtlc retrieves a final htlc resolution from the
+ // database. If the htlc has no final resolution yet, ErrHtlcUnknown
+ // is returned.
+ LookupFinalHtlc(chanID lnwire.ShortChannelID,
+ htlcIndex uint64) (*channeldb.FinalHtlcInfo, error)
+
+ // PutOnchainFinalHtlcOutcome stores the final on-chain outcome of an
+ // htlc in the database.
+ PutOnchainFinalHtlcOutcome(chanID lnwire.ShortChannelID,
+ htlcID uint64, settled bool) error
+}
+
+// ChannelSetupStore owns temporary state used while setting up a channel. This
+// state should be deleted once the link comes up.
+type ChannelSetupStore interface {
+ // SaveChannelOpeningState saves the serialized channel state for the
+ // provided chanPoint to the channelOpeningStateBucket.
+ SaveChannelOpeningState(outPoint, serializedState []byte) error
+
+ // GetChannelOpeningState fetches the serialized channel state for
+ // the provided outPoint from the database, or returns
+ // ErrChannelNotFound if the channel is not found.
+ GetChannelOpeningState(outPoint []byte) ([]byte, error)
+
+ // DeleteChannelOpeningState removes any state for outPoint from the
+ // database.
+ DeleteChannelOpeningState(outPoint []byte) error
+
+ // SaveInitialForwardingPolicy saves the serialized forwarding policy
+ // for the provided permanent channel id.
+ SaveInitialForwardingPolicy(chanID lnwire.ChannelID,
+ forwardingPolicy *models.ForwardingPolicy) error
+
+ // GetInitialForwardingPolicy fetches the serialized forwarding policy
+ // for the provided channel id from the database, or returns
+ // ErrChannelNotFound if a forwarding policy for this channel id is not
+ // found.
+ GetInitialForwardingPolicy(chanID lnwire.ChannelID) (
+ *models.ForwardingPolicy, error)
+
+ // DeleteInitialForwardingPolicy removes the forwarding policy for a
+ // given channel from the database.
+ DeleteInitialForwardingPolicy(chanID lnwire.ChannelID) error
+}
+
+// LinkNodeMaintainer owns link-node maintenance derived from channel state.
+type LinkNodeMaintainer interface {
+ // PruneLinkNodes attempts to prune all link nodes found within the
+ // database with whom we no longer have any open channels with.
+ PruneLinkNodes() error
+
+ // RepairLinkNodes scans all channels in the database and ensures
+ // that a link node exists for each remote peer. This should be
+ // called on startup to ensure that our database is consistent.
+ RepairLinkNodes(network wire.BitcoinNet) error
+}
+
+// Compile-time assertion that channeldb.ChannelStateDB satisfies the Store
+// contract. If a method signature drifts on the concrete type,
+// this assertion will fail to build before any consumer migration.
+//
+// NOTE: This assertion lives in the interface file as a temporary exception to
+// the established pattern (see invoices/sql_store.go, payments/db/kv_store.go,
+// graph/db/kv_store.go), where each implementation asserts itself in its own
+// file. The implementation still lives in channeldb/, and channeldb must not
+// import chanstate to avoid a cycle, so the assertion has no local
+// implementation file to live in yet. When the KV implementation moves into
+// this package (chanstate/kv_store.go), this assertion MUST be removed from
+// here and re-stated next to the local implementation, matching the precedent
+// packages.
+var _ Store = (*channeldb.ChannelStateDB)(nil)
diff --git a/chanstate/log.go b/chanstate/log.go
new file mode 100644
index 0000000..c41e9bb
--- /dev/null
+++ b/chanstate/log.go
@@ -0,0 +1,31 @@
+package chanstate
+
+import (
+ "github.com/btcsuite/btclog/v2"
+ "github.com/lightningnetwork/lnd/build"
+)
+
+// log is a logger that is initialized with no output filters. This means the
+// package will not perform any logging by default until the caller requests
+// it.
+//
+//nolint:unused
+var log btclog.Logger
+
+// init initializes the package-global logger instance.
+func init() {
+ UseLogger(build.NewSubLogger("CHST", nil))
+}
+
+// DisableLog disables all library log output. Logging output is disabled by
+// default until UseLogger is called.
+func DisableLog() {
+ UseLogger(btclog.Disabled)
+}
+
+// UseLogger uses a specified Logger to output package logging info. This
+// should be used in preference to SetLogWriter if the caller is also using
+// btclog.
+func UseLogger(logger btclog.Logger) {
+ log = logger
+}
diff --git a/log.go b/log.go
index 5f80bb7..563ee3e 100644
--- a/log.go
+++ b/log.go
@@ -17,6 +17,7 @@ import (
"github.com/lightningnetwork/lnd/chanfitness"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/channelnotifier"
+ "github.com/lightningnetwork/lnd/chanstate"
"github.com/lightningnetwork/lnd/cluster"
"github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/discovery"
@@ -177,6 +178,7 @@ func SetupLoggers(root *build.SubLoggerManager, interceptor signal.Interceptor)
AddSubLogger(root, "IRPC", interceptor, invoicesrpc.UseLogger)
AddSubLogger(root, "CHNF", interceptor, channelnotifier.UseLogger)
AddSubLogger(root, "CHBU", interceptor, chanbackup.UseLogger)
+ AddSubLogger(root, "CHST", interceptor, chanstate.UseLogger)
AddSubLogger(root, "PROM", interceptor, monitoring.UseLogger)
AddSubLogger(root, "WTCL", interceptor, wtclient.UseLogger)
AddSubLogger(root, "PRNF", interceptor, peernotifier.UseLogger)
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.