What changed, and why it matters
This commit is a straightforward internal code reorganization. It moves existing channel-status update logic from the OpenChannel object into a new subinterface on the ChannelStateDB storage layer. No new behavior, security checks, or bug fixes are introduced; the same database operations are performed through a different code path.
No security action required. Treat as normal refactoring; review in context of the larger chanstate store migration series if desired.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors LND’s channeldb/chanstate persistence layer. It adds an OpenChannelStatusStore interface in chanstate/interface.go and implements it on ChannelStateDB in channeldb/channel.go. OpenChannel methods (ApplyChanStatus, ClearChanStatus, MarkDataLoss, DataLossCommitPoint, MarkBorked, markBroadcasted) now delegate to ChannelStateDB methods (ApplyChannelStatus, ClearChannelStatus, MarkChannelDataLoss, FetchChannelDataLossCommitPoint, MarkChannelBorked, putChanStatus). The underlying kvdb read/write logic, key handling, and status bit manipulation remain identical. The broadcast path still uses a private putChanStatus helper pending a future closing-transaction subinterface.
Changed components
channeldb/channel.gochanstate/interface.goInspect captured patch +95 / −27
diff --git a/channeldb/channel.go b/channeldb/channel.go
index 103307b..b72cdca 100644
--- a/channeldb/channel.go
+++ b/channeldb/channel.go
@@ -1003,7 +1003,7 @@ func (c *OpenChannel) ApplyChanStatus(status ChannelStatus) error {
c.Lock()
defer c.Unlock()
- return c.putChanStatus(status)
+ return c.Db.ApplyChannelStatus(c, status)
}
// ClearChanStatus allows the caller to clear a particular channel status from
@@ -1013,7 +1013,7 @@ func (c *OpenChannel) ClearChanStatus(status ChannelStatus) error {
c.Lock()
defer c.Unlock()
- return c.clearChanStatus(status)
+ return c.Db.ClearChannelStatus(c, status)
}
// HasChanStatus returns true if the internal bitfield channel status of the
@@ -1625,6 +1625,14 @@ func (c *OpenChannel) MarkDataLoss(commitPoint *btcec.PublicKey) error {
c.Lock()
defer c.Unlock()
+ return c.Db.MarkChannelDataLoss(c, commitPoint)
+}
+
+// MarkChannelDataLoss marks the channel as local-data-loss and stores the
+// commit point needed if the remote force closes.
+func (c *ChannelStateDB) MarkChannelDataLoss(channel *OpenChannel,
+ commitPoint *btcec.PublicKey) error {
+
var b bytes.Buffer
if err := WriteElement(&b, commitPoint); err != nil {
return err
@@ -1634,17 +1642,26 @@ func (c *OpenChannel) MarkDataLoss(commitPoint *btcec.PublicKey) error {
return chanBucket.Put(dataLossCommitPointKey, b.Bytes())
}
- return c.putChanStatus(ChanStatusLocalDataLoss, putCommitPoint)
+ return c.putChanStatus(channel, ChanStatusLocalDataLoss, putCommitPoint)
}
// DataLossCommitPoint retrieves the stored commit point set during
// MarkDataLoss. If not found ErrNoCommitPoint is returned.
func (c *OpenChannel) DataLossCommitPoint() (*btcec.PublicKey, error) {
+ return c.Db.FetchChannelDataLossCommitPoint(c)
+}
+
+// FetchChannelDataLossCommitPoint retrieves the commit point stored when the
+// channel was marked as local-data-loss.
+func (c *ChannelStateDB) FetchChannelDataLossCommitPoint(
+ channel *OpenChannel) (*btcec.PublicKey, error) {
+
var commitPoint *btcec.PublicKey
- err := kvdb.View(c.Db.backend, func(tx kvdb.RTx) error {
+ err := kvdb.View(c.backend, func(tx kvdb.RTx) error {
chanBucket, err := fetchChanBucket(
- tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash,
+ tx, channel.IdentityPub, &channel.FundingOutpoint,
+ channel.ChainHash,
)
switch err {
case nil:
@@ -1681,7 +1698,12 @@ func (c *OpenChannel) MarkBorked() error {
c.Lock()
defer c.Unlock()
- return c.putChanStatus(ChanStatusBorked)
+ return c.Db.MarkChannelBorked(c)
+}
+
+// MarkChannelBorked marks the channel as irreconcilable.
+func (c *ChannelStateDB) MarkChannelBorked(channel *OpenChannel) error {
+ return c.ApplyChannelStatus(channel, ChanStatusBorked)
}
// SecondCommitmentPoint returns the second per-commitment-point for use in the
@@ -2037,7 +2059,7 @@ func (c *OpenChannel) markBroadcasted(status ChannelStatus, key []byte,
status |= ChanStatusRemoteCloseInitiator
}
- return c.putChanStatus(status, putClosingTx)
+ return c.Db.putChanStatus(c, status, putClosingTx)
}
// BroadcastedCommitment retrieves the stored unilateral closing tx set during
@@ -2085,30 +2107,41 @@ func (c *OpenChannel) getClosingTx(key []byte) (*wire.MsgTx, error) {
return closeTx, nil
}
-// putChanStatus appends the given status to the channel. fs is an optional
-// list of closures that are given the chanBucket in order to atomically add
-// extra information together with the new status.
-func (c *OpenChannel) putChanStatus(status ChannelStatus,
- fs ...func(kvdb.RwBucket) error) error {
+// ApplyChannelStatus adds the target status to the channel's persisted status
+// bit field.
+func (c *ChannelStateDB) ApplyChannelStatus(channel *OpenChannel,
+ status ChannelStatus) error {
+
+ return c.putChanStatus(channel, status)
+}
+
+// putChanStatus appends the given status to the channel. fs is an optional list
+// of closures that are given the chanBucket in order to atomically add extra
+// information together with the new status.
+func (c *ChannelStateDB) putChanStatus(channel *OpenChannel,
+ status ChannelStatus, fs ...func(kvdb.RwBucket) error) error {
- if err := kvdb.Update(c.Db.backend, func(tx kvdb.RwTx) error {
+ if err := kvdb.Update(c.backend, func(tx kvdb.RwTx) error {
chanBucket, err := fetchChanBucketRw(
- tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash,
+ tx, channel.IdentityPub, &channel.FundingOutpoint,
+ channel.ChainHash,
)
if err != nil {
return err
}
- channel, err := fetchOpenChannel(chanBucket, &c.FundingOutpoint)
+ diskChannel, err := fetchOpenChannel(
+ chanBucket, &channel.FundingOutpoint,
+ )
if err != nil {
return err
}
// Add this status to the existing bitvector found in the DB.
- status = channel.chanStatus | status
- channel.chanStatus = status
+ status = diskChannel.chanStatus | status
+ diskChannel.chanStatus = status
- if err := putOpenChannel(chanBucket, channel); err != nil {
+ if err := putOpenChannel(chanBucket, diskChannel); err != nil {
return err
}
@@ -2129,36 +2162,43 @@ func (c *OpenChannel) putChanStatus(status ChannelStatus,
}
// Update the in-memory representation to keep it in sync with the DB.
- c.chanStatus = status
+ channel.chanStatus = status
return nil
}
-func (c *OpenChannel) clearChanStatus(status ChannelStatus) error {
- if err := kvdb.Update(c.Db.backend, func(tx kvdb.RwTx) error {
+// ClearChannelStatus clears the target status from the channel's persisted
+// status bit field.
+func (c *ChannelStateDB) ClearChannelStatus(channel *OpenChannel,
+ status ChannelStatus) error {
+
+ if err := kvdb.Update(c.backend, func(tx kvdb.RwTx) error {
chanBucket, err := fetchChanBucketRw(
- tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash,
+ tx, channel.IdentityPub, &channel.FundingOutpoint,
+ channel.ChainHash,
)
if err != nil {
return err
}
- channel, err := fetchOpenChannel(chanBucket, &c.FundingOutpoint)
+ diskChannel, err := fetchOpenChannel(
+ chanBucket, &channel.FundingOutpoint,
+ )
if err != nil {
return err
}
// Unset this bit in the bitvector on disk.
- status = channel.chanStatus & ^status
- channel.chanStatus = status
+ status = diskChannel.chanStatus & ^status
+ diskChannel.chanStatus = status
- return putOpenChannel(chanBucket, channel)
+ return putOpenChannel(chanBucket, diskChannel)
}, func() {}); err != nil {
return err
}
// Update the in-memory representation to keep it in sync with the DB.
- c.chanStatus = status
+ channel.chanStatus = status
return nil
}
diff --git a/chanstate/interface.go b/chanstate/interface.go
index 46914f6..f83f49f 100644
--- a/chanstate/interface.go
+++ b/chanstate/interface.go
@@ -28,6 +28,10 @@ type Store[Channel any] interface {
// channel records.
OpenChannelLifecycleStore[Channel]
+ // OpenChannelStatusStore owns persisted status flags for open channel
+ // records.
+ OpenChannelStatusStore[Channel]
+
// ClosedChannelStore owns closed-channel summaries and lifecycle
// mutations.
ClosedChannelStore[Channel]
@@ -140,6 +144,30 @@ type OpenChannelLifecycleStore[Channel any] interface {
MarkChannelScidAliasNegotiated(channel Channel) error
}
+// OpenChannelStatusStore owns persisted status flags for open channel records.
+type OpenChannelStatusStore[Channel any] interface {
+ // ApplyChannelStatus adds the target status to the channel's
+ // persisted status bit field.
+ ApplyChannelStatus(channel Channel, status ChannelStatus) error
+
+ // ClearChannelStatus clears the target status from the channel's
+ // persisted status bit field.
+ ClearChannelStatus(channel Channel, status ChannelStatus) error
+
+ // MarkChannelDataLoss marks the channel as local-data-loss and stores
+ // the commit point needed if the remote force closes.
+ MarkChannelDataLoss(channel Channel,
+ commitPoint *btcec.PublicKey) error
+
+ // FetchChannelDataLossCommitPoint retrieves the commit point stored
+ // when the channel was marked as local-data-loss.
+ FetchChannelDataLossCommitPoint(channel Channel) (
+ *btcec.PublicKey, error)
+
+ // MarkChannelBorked marks the channel as irreconcilable.
+ MarkChannelBorked(channel Channel) error
+}
+
// ClosedChannelStore owns closed-channel summaries and lifecycle mutations.
type ClosedChannelStore[Channel any] interface {
// FetchClosedChannels attempts to fetch all closed channels from the
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.