2020-01-04 22:31:38 +00:00
|
|
|
package main
|
2019-12-28 15:04:36 +00:00
|
|
|
|
|
|
|
import (
|
2023-09-18 13:45:53 +00:00
|
|
|
"errors"
|
2020-01-04 22:31:38 +00:00
|
|
|
"fmt"
|
2019-12-28 15:04:36 +00:00
|
|
|
|
|
|
|
"github.com/davecgh/go-spew/spew"
|
2023-05-31 09:12:42 +00:00
|
|
|
"github.com/lightninglabs/chantools/dump"
|
|
|
|
"github.com/lightninglabs/chantools/lnd"
|
2019-12-28 15:04:36 +00:00
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
2020-12-27 00:09:34 +00:00
|
|
|
"github.com/spf13/cobra"
|
2019-12-28 15:04:36 +00:00
|
|
|
)
|
|
|
|
|
2020-01-04 22:31:38 +00:00
|
|
|
type dumpChannelsCommand struct {
|
2022-08-25 20:06:16 +00:00
|
|
|
ChannelDB string
|
|
|
|
Closed bool
|
|
|
|
Pending bool
|
|
|
|
WaitingClose bool
|
2020-12-27 00:09:34 +00:00
|
|
|
|
|
|
|
cmd *cobra.Command
|
2020-01-04 22:31:38 +00:00
|
|
|
}
|
|
|
|
|
2020-12-27 00:09:34 +00:00
|
|
|
func newDumpChannelsCommand() *cobra.Command {
|
|
|
|
cc := &dumpChannelsCommand{}
|
|
|
|
cc.cmd = &cobra.Command{
|
|
|
|
Use: "dumpchannels",
|
|
|
|
Short: "Dump all channel information from an lnd channel " +
|
|
|
|
"database",
|
2020-12-27 00:40:51 +00:00
|
|
|
Long: `This command dumps all open and pending channels from the
|
|
|
|
given lnd channel.db gile in a human readable format.`,
|
|
|
|
Example: `chantools dumpchannels \
|
|
|
|
--channeldb ~/.lnd/data/graph/mainnet/channel.db`,
|
2020-12-27 00:09:34 +00:00
|
|
|
RunE: cc.Execute,
|
|
|
|
}
|
|
|
|
cc.cmd.Flags().StringVar(
|
|
|
|
&cc.ChannelDB, "channeldb", "", "lnd channel.db file to dump "+
|
|
|
|
"channels from",
|
|
|
|
)
|
|
|
|
cc.cmd.Flags().BoolVar(
|
|
|
|
&cc.Closed, "closed", false, "dump closed channels instead of "+
|
|
|
|
"open",
|
|
|
|
)
|
2022-08-25 20:06:16 +00:00
|
|
|
cc.cmd.Flags().BoolVar(
|
|
|
|
&cc.Pending, "pending", false, "dump pending channels instead "+
|
|
|
|
"of open",
|
|
|
|
)
|
|
|
|
cc.cmd.Flags().BoolVar(
|
|
|
|
&cc.WaitingClose, "waiting_close", false, "dump waiting close "+
|
|
|
|
"channels instead of open",
|
|
|
|
)
|
2020-12-27 00:09:34 +00:00
|
|
|
|
|
|
|
return cc.cmd
|
|
|
|
}
|
2020-02-10 10:25:32 +00:00
|
|
|
|
2020-12-27 00:09:34 +00:00
|
|
|
func (c *dumpChannelsCommand) Execute(_ *cobra.Command, _ []string) error {
|
2020-01-04 22:31:38 +00:00
|
|
|
// Check that we have a channel DB.
|
|
|
|
if c.ChannelDB == "" {
|
|
|
|
return fmt.Errorf("channel DB is required")
|
|
|
|
}
|
2020-12-14 22:30:18 +00:00
|
|
|
db, err := lnd.OpenDB(c.ChannelDB, true)
|
2020-01-04 22:31:38 +00:00
|
|
|
if err != nil {
|
2022-07-18 07:50:27 +00:00
|
|
|
return fmt.Errorf("error opening rescue DB: %w", err)
|
2020-01-04 22:31:38 +00:00
|
|
|
}
|
2021-01-01 11:56:19 +00:00
|
|
|
defer func() { _ = db.Close() }()
|
2020-12-14 22:30:18 +00:00
|
|
|
|
2022-08-25 20:06:16 +00:00
|
|
|
if (c.Closed && c.Pending) || (c.Closed && c.WaitingClose) ||
|
|
|
|
(c.Pending && c.WaitingClose) ||
|
|
|
|
(c.Closed && c.Pending && c.WaitingClose) {
|
|
|
|
|
|
|
|
return fmt.Errorf("can only specify one flag at a time")
|
|
|
|
}
|
|
|
|
|
2020-08-26 10:23:59 +00:00
|
|
|
if c.Closed {
|
2021-12-13 09:34:26 +00:00
|
|
|
return dumpClosedChannelInfo(db.ChannelStateDB())
|
2020-08-26 10:23:59 +00:00
|
|
|
}
|
2022-08-25 20:06:16 +00:00
|
|
|
if c.Pending {
|
|
|
|
return dumpPendingChannelInfo(db.ChannelStateDB())
|
|
|
|
}
|
|
|
|
if c.WaitingClose {
|
|
|
|
return dumpWaitingCloseChannelInfo(db.ChannelStateDB())
|
|
|
|
}
|
|
|
|
|
2021-12-13 09:34:26 +00:00
|
|
|
return dumpOpenChannelInfo(db.ChannelStateDB())
|
2020-01-04 22:31:38 +00:00
|
|
|
}
|
|
|
|
|
2021-12-13 09:34:26 +00:00
|
|
|
func dumpOpenChannelInfo(chanDb *channeldb.ChannelStateDB) error {
|
2019-12-28 15:04:36 +00:00
|
|
|
channels, err := chanDb.FetchAllChannels()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-08-26 10:23:59 +00:00
|
|
|
dumpChannels, err := dump.OpenChannelDump(channels, chainParams)
|
2020-03-30 16:33:00 +00:00
|
|
|
if err != nil {
|
2022-07-18 07:50:27 +00:00
|
|
|
return fmt.Errorf("error converting to dump format: %w", err)
|
2019-12-28 15:04:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
spew.Dump(dumpChannels)
|
2021-01-01 11:56:19 +00:00
|
|
|
|
|
|
|
// For the tests, also log as trace level which is disabled by default.
|
|
|
|
log.Tracef(spew.Sdump(dumpChannels))
|
|
|
|
|
2019-12-28 15:04:36 +00:00
|
|
|
return nil
|
|
|
|
}
|
2020-08-26 10:23:59 +00:00
|
|
|
|
2021-12-13 09:34:26 +00:00
|
|
|
func dumpClosedChannelInfo(chanDb *channeldb.ChannelStateDB) error {
|
2020-08-26 10:23:59 +00:00
|
|
|
channels, err := chanDb.FetchClosedChannels(false)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-09-14 08:57:03 +00:00
|
|
|
historicalChannels := make([]*channeldb.OpenChannel, len(channels))
|
|
|
|
for idx := range channels {
|
|
|
|
closedChan := channels[idx]
|
|
|
|
histChan, err := chanDb.FetchHistoricalChannel(
|
|
|
|
&closedChan.ChanPoint,
|
|
|
|
)
|
2023-09-18 13:45:53 +00:00
|
|
|
|
|
|
|
switch {
|
2023-09-14 08:57:03 +00:00
|
|
|
// The channel was closed in a pre-historic version of lnd.
|
|
|
|
// Ignore the error.
|
2023-09-18 13:45:53 +00:00
|
|
|
case errors.Is(err, channeldb.ErrNoHistoricalBucket):
|
|
|
|
case errors.Is(err, channeldb.ErrChannelNotFound):
|
2023-09-14 08:57:03 +00:00
|
|
|
|
2023-09-18 13:45:53 +00:00
|
|
|
case err == nil:
|
2023-09-14 08:57:03 +00:00
|
|
|
historicalChannels[idx] = histChan
|
|
|
|
|
|
|
|
// Non-nil error not due to older versions of lnd.
|
|
|
|
default:
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dumpChannels, err := dump.ClosedChannelDump(
|
|
|
|
channels, historicalChannels, chainParams,
|
|
|
|
)
|
2020-08-26 10:23:59 +00:00
|
|
|
if err != nil {
|
2022-07-18 07:50:27 +00:00
|
|
|
return fmt.Errorf("error converting to dump format: %w", err)
|
2020-08-26 10:23:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
spew.Dump(dumpChannels)
|
2021-01-01 11:56:19 +00:00
|
|
|
|
|
|
|
// For the tests, also log as trace level which is disabled by default.
|
|
|
|
log.Tracef(spew.Sdump(dumpChannels))
|
|
|
|
|
2020-08-26 10:23:59 +00:00
|
|
|
return nil
|
2020-12-14 22:30:18 +00:00
|
|
|
}
|
2022-08-25 20:06:16 +00:00
|
|
|
|
|
|
|
func dumpPendingChannelInfo(chanDb *channeldb.ChannelStateDB) error {
|
|
|
|
channels, err := chanDb.FetchPendingChannels()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
dumpChannels, err := dump.OpenChannelDump(channels, chainParams)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error converting to dump format: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
spew.Dump(dumpChannels)
|
|
|
|
|
|
|
|
// For the tests, also log as trace level which is disabled by default.
|
|
|
|
log.Tracef(spew.Sdump(dumpChannels))
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func dumpWaitingCloseChannelInfo(chanDb *channeldb.ChannelStateDB) error {
|
|
|
|
channels, err := chanDb.FetchWaitingCloseChannels()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
dumpChannels, err := dump.OpenChannelDump(channels, chainParams)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error converting to dump format: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
spew.Dump(dumpChannels)
|
|
|
|
|
|
|
|
// For the tests, also log as trace level which is disabled by default.
|
|
|
|
log.Tracef(spew.Sdump(dumpChannels))
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|