What changed, and why it matters
This commit is a straightforward internal code reorganization. It moves existing functions for saving and retrieving channel shutdown information and closing transactions from being methods on individual channels to being methods on the channel database object, and adds matching interface definitions. There is no change to what data is stored, how it is protected, or how users interact with the software. It does not fix or introduce any security issue that can be seen in the diff.
No security action required. Treat as normal refactoring review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors persistence helpers in channeldb/channel.go: storeShutdownInfo, ShutdownInfo, MarkCommitmentBroadcasted, MarkCoopBroadcasted, BroadcastedCommitment, BroadcastedCooperative, and getClosingTx are renamed/restructured as ChannelStateDB methods (StoreChannelShutdownInfo, FetchChannelShutdownInfo, MarkChannelCommitmentBroadcasted, MarkChannelCoopBroadcasted, FetchChannelBroadcastedCommitment, FetchChannelBroadcastedCooperative, getClosingTx). OpenChannel receiver methods now delegate to c.Db.
Changed components
lnd/channeldb/channel.golnd/chanstate/interface.goInspect captured patch +117 / −28
diff --git a/channeldb/channel.go b/channeldb/channel.go
index b72cdca..5b02de1 100644
--- a/channeldb/channel.go
+++ b/channeldb/channel.go
@@ -1917,21 +1917,23 @@ func (c *OpenChannel) MarkShutdownSent(info *ShutdownInfo) error {
c.Lock()
defer c.Unlock()
- return c.storeShutdownInfo(info)
+ return c.Db.StoreChannelShutdownInfo(c, info)
}
-// storeShutdownInfo serialises the ShutdownInfo and persists it under the
-// shutdownInfoKey.
-func (c *OpenChannel) storeShutdownInfo(info *ShutdownInfo) error {
+// StoreChannelShutdownInfo persists the ShutdownInfo for the target channel.
+func (c *ChannelStateDB) StoreChannelShutdownInfo(channel *OpenChannel,
+ info *ShutdownInfo) error {
+
var b bytes.Buffer
err := encodeShutdownInfo(info, &b)
if err != nil {
return err
}
- return kvdb.Update(c.Db.backend, func(tx kvdb.RwTx) error {
+ return 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
@@ -1948,10 +1950,19 @@ func (c *OpenChannel) ShutdownInfo() (fn.Option[ShutdownInfo], error) {
c.RLock()
defer c.RUnlock()
+ return c.Db.FetchChannelShutdownInfo(c)
+}
+
+// FetchChannelShutdownInfo fetches the persisted ShutdownInfo for the target
+// channel.
+func (c *ChannelStateDB) FetchChannelShutdownInfo(
+ channel *OpenChannel) (fn.Option[ShutdownInfo], error) {
+
var shutdownInfo *ShutdownInfo
- 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 {
case err == nil:
@@ -2005,9 +2016,18 @@ func (c *OpenChannel) isBorked(chanBucket kvdb.RBucket) (bool, error) {
func (c *OpenChannel) MarkCommitmentBroadcasted(closeTx *wire.MsgTx,
closer lntypes.ChannelParty) error {
+ return c.Db.MarkChannelCommitmentBroadcasted(c, closeTx, closer)
+}
+
+// MarkChannelCommitmentBroadcasted marks the channel as having a commitment
+// transaction broadcast.
+func (c *ChannelStateDB) MarkChannelCommitmentBroadcasted(
+ channel *OpenChannel, closeTx *wire.MsgTx,
+ closer lntypes.ChannelParty) error {
+
return c.markBroadcasted(
- ChanStatusCommitBroadcasted, forceCloseTxKey, closeTx,
- closer,
+ channel, ChanStatusCommitBroadcasted, forceCloseTxKey,
+ closeTx, closer,
)
}
@@ -2021,25 +2041,33 @@ func (c *OpenChannel) MarkCommitmentBroadcasted(closeTx *wire.MsgTx,
func (c *OpenChannel) MarkCoopBroadcasted(closeTx *wire.MsgTx,
closer lntypes.ChannelParty) error {
+ return c.Db.MarkChannelCoopBroadcasted(c, closeTx, closer)
+}
+
+// MarkChannelCoopBroadcasted marks the channel as having a cooperative close
+// transaction broadcast.
+func (c *ChannelStateDB) MarkChannelCoopBroadcasted(channel *OpenChannel,
+ closeTx *wire.MsgTx, closer lntypes.ChannelParty) error {
+
return c.markBroadcasted(
- ChanStatusCoopBroadcasted, coopCloseTxKey, closeTx,
- closer,
+ channel, ChanStatusCoopBroadcasted, coopCloseTxKey,
+ closeTx, closer,
)
}
-// markBroadcasted is a helper function which modifies the channel status of the
-// receiving channel and inserts a close transaction under the requested key,
-// which should specify either a coop or force close. It adds a status which
-// indicates the party that initiated the channel close.
-func (c *OpenChannel) markBroadcasted(status ChannelStatus, key []byte,
- closeTx *wire.MsgTx, closer lntypes.ChannelParty) error {
+// markBroadcasted modifies the channel status and inserts a close transaction
+// under the requested key, which should specify either a coop or force close.
+// It adds a status which indicates the party that initiated the channel close.
+func (c *ChannelStateDB) markBroadcasted(channel *OpenChannel,
+ status ChannelStatus, key []byte, closeTx *wire.MsgTx,
+ closer lntypes.ChannelParty) error {
if closeTx == nil {
return fmt.Errorf("closeTx must be non-nil")
}
- c.Lock()
- defer c.Unlock()
+ channel.Lock()
+ defer channel.Unlock()
var b bytes.Buffer
if err := WriteElement(&b, closeTx); err != nil {
@@ -2059,29 +2087,48 @@ func (c *OpenChannel) markBroadcasted(status ChannelStatus, key []byte,
status |= ChanStatusRemoteCloseInitiator
}
- return c.Db.putChanStatus(c, status, putClosingTx)
+ return c.putChanStatus(channel, status, putClosingTx)
}
// BroadcastedCommitment retrieves the stored unilateral closing tx set during
// MarkCommitmentBroadcasted. If not found ErrNoCloseTx is returned.
func (c *OpenChannel) BroadcastedCommitment() (*wire.MsgTx, error) {
- return c.getClosingTx(forceCloseTxKey)
+ return c.Db.FetchChannelBroadcastedCommitment(c)
+}
+
+// FetchChannelBroadcastedCommitment fetches the stored unilateral closing
+// transaction.
+func (c *ChannelStateDB) FetchChannelBroadcastedCommitment(
+ channel *OpenChannel) (*wire.MsgTx, error) {
+
+ return c.getClosingTx(channel, forceCloseTxKey)
}
// BroadcastedCooperative retrieves the stored cooperative closing tx set during
// MarkCoopBroadcasted. If not found ErrNoCloseTx is returned.
func (c *OpenChannel) BroadcastedCooperative() (*wire.MsgTx, error) {
- return c.getClosingTx(coopCloseTxKey)
+ return c.Db.FetchChannelBroadcastedCooperative(c)
}
-// getClosingTx is a helper method which returns the stored closing transaction
-// for key. The caller should use either the force or coop closing keys.
-func (c *OpenChannel) getClosingTx(key []byte) (*wire.MsgTx, error) {
+// FetchChannelBroadcastedCooperative fetches the stored cooperative closing
+// transaction.
+func (c *ChannelStateDB) FetchChannelBroadcastedCooperative(
+ channel *OpenChannel) (*wire.MsgTx, error) {
+
+ return c.getClosingTx(channel, coopCloseTxKey)
+}
+
+// getClosingTx returns the stored closing transaction for key. The caller
+// should use either the force or coop closing keys.
+func (c *ChannelStateDB) getClosingTx(channel *OpenChannel,
+ key []byte) (*wire.MsgTx, error) {
+
var closeTx *wire.MsgTx
- 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:
diff --git a/chanstate/interface.go b/chanstate/interface.go
index f83f49f..3752661 100644
--- a/chanstate/interface.go
+++ b/chanstate/interface.go
@@ -5,6 +5,7 @@ import (
"github.com/btcsuite/btcd/wire/v2"
"github.com/lightningnetwork/lnd/fn/v2"
"github.com/lightningnetwork/lnd/graph/db/models"
+ "github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
)
@@ -32,6 +33,12 @@ type Store[Channel any] interface {
// records.
OpenChannelStatusStore[Channel]
+ // OpenChannelShutdownStore owns persisted shutdown state.
+ OpenChannelShutdownStore[Channel]
+
+ // OpenChannelCloseTxStore owns persisted closing transaction state.
+ OpenChannelCloseTxStore[Channel]
+
// ClosedChannelStore owns closed-channel summaries and lifecycle
// mutations.
ClosedChannelStore[Channel]
@@ -168,6 +175,41 @@ type OpenChannelStatusStore[Channel any] interface {
MarkChannelBorked(channel Channel) error
}
+// OpenChannelShutdownStore owns persisted shutdown state.
+type OpenChannelShutdownStore[Channel any] interface {
+ // StoreChannelShutdownInfo persists the ShutdownInfo for the target
+ // channel.
+ StoreChannelShutdownInfo(channel Channel, info *ShutdownInfo) error
+
+ // FetchChannelShutdownInfo fetches the persisted ShutdownInfo for the
+ // target channel.
+ FetchChannelShutdownInfo(channel Channel) (fn.Option[ShutdownInfo],
+ error)
+}
+
+// OpenChannelCloseTxStore owns persisted closing transaction state.
+type OpenChannelCloseTxStore[Channel any] interface {
+ // MarkChannelCommitmentBroadcasted marks the channel as having a
+ // commitment transaction broadcast.
+ MarkChannelCommitmentBroadcasted(channel Channel, closeTx *wire.MsgTx,
+ closer lntypes.ChannelParty) error
+
+ // MarkChannelCoopBroadcasted marks the channel as having a
+ // cooperative close transaction broadcast.
+ MarkChannelCoopBroadcasted(channel Channel, closeTx *wire.MsgTx,
+ closer lntypes.ChannelParty) error
+
+ // FetchChannelBroadcastedCommitment fetches the stored unilateral
+ // closing transaction.
+ FetchChannelBroadcastedCommitment(channel Channel) (*wire.MsgTx,
+ error)
+
+ // FetchChannelBroadcastedCooperative fetches the stored cooperative
+ // closing transaction.
+ FetchChannelBroadcastedCooperative(channel Channel) (*wire.MsgTx,
+ 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 14/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.