Add filterbackup command

pull/3/head
Oliver Gugger 4 years ago
parent 98075a7965
commit 22420b9aca
No known key found for this signature in database
GPG Key ID: 8E4256593F177720

@ -7,6 +7,7 @@
* [Commands](#commands)
+ [dumpbackup](#dumpbackup)
+ [dumpchannels](#dumpchannels)
+ [filterbackup](#filterbackup)
+ [forceclose](#forceclose)
+ [rescueclosed](#rescueclosed)
+ [showrootkey](#showrootkey)
@ -54,6 +55,7 @@ Available commands:
derivekey Derive a key with a specific derivation path from the BIP32 HD root key.
dumpbackup Dump the content of a channel.backup file.
dumpchannels Dump all channel information from lnd's channel database.
filterbackup Filter an lnd channel.backup file and remove certain channels.
forceclose Force-close the last state that is in the channel.db provided.
rescueclosed Try finding the private keys for funds that are in outputs of remotely force-closed channels.
showrootkey Extract and show the BIP32 HD root key from the 24 word lnd aezeed.
@ -126,6 +128,29 @@ Example command:
chantools dumpchannels --channeldb ~/.lnd/data/graph/mainnet/channel.db
```
### filterbackup
```text
Usage:
chantools [OPTIONS] filterbackup [filterbackup-OPTIONS]
[filterbackup command options]
--rootkey= BIP32 HD root key of the wallet that was used to create the backup. Leave empty to prompt for lnd 24 word aezeed.
--multi_file= The lnd channel.backup file to filter.
--discard= A comma separated list of channel funding outpoints (format <fundingTXID>:<index>) to remove from the backup file.
```
Filter an lnd `channel.backup` file by removing certain channels (identified by
their funding transaction outpoints).
Example command:
```bash
chantools filterbackup --rootkey xprvxxxxxxxxxx \
--multi_file ~/.lnd/data/chain/bitcoin/mainnet/channel.backup \
--discard 2abcdef2b2bffaaa...db0abadd:1,4abcdef2b2bffaaa...db8abadd:0
```
### forceclose
```text

@ -8,6 +8,7 @@ import (
"github.com/guggero/chantools/btc"
"github.com/guggero/chantools/dump"
"github.com/lightningnetwork/lnd/chanbackup"
"github.com/lightningnetwork/lnd/keychain"
)
type dumpBackupCommand struct {
@ -40,17 +41,20 @@ func (c *dumpBackupCommand) Execute(_ []string) error {
return fmt.Errorf("backup file is required")
}
multiFile := chanbackup.NewMultiFile(c.MultiFile)
multi, err := multiFile.ExtractMulti(&btc.ChannelBackupEncryptionRing{
keyRing := &btc.ChannelBackupEncryptionRing{
ExtendedKey: extendedKey,
ChainParams: chainParams,
})
if err != nil {
return fmt.Errorf("could not extract multi file: %v", err)
}
return dumpChannelBackup(multi)
return dumpChannelBackup(multiFile, keyRing)
}
func dumpChannelBackup(multi *chanbackup.Multi) error {
func dumpChannelBackup(multiFile *chanbackup.MultiFile,
ring keychain.KeyRing) error {
multi, err := multiFile.ExtractMulti(ring)
if err != nil {
return fmt.Errorf("could not extract multi file: %v", err)
}
dumpSingles := make([]dump.BackupSingle, len(multi.StaticBackups))
for idx, single := range multi.StaticBackups {
dumpSingles[idx] = dump.BackupSingle{

@ -0,0 +1,92 @@
package main
import (
"fmt"
"os"
"strings"
"time"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/guggero/chantools/btc"
"github.com/lightningnetwork/lnd/chanbackup"
"github.com/lightningnetwork/lnd/keychain"
)
type filterBackupCommand struct {
RootKey string `long:"rootkey" description:"BIP32 HD root key of the wallet that was used to create the backup. Leave empty to prompt for lnd 24 word aezeed."`
MultiFile string `long:"multi_file" description:"The lnd channel.backup file to filter."`
Discard string `long:"discard" description:"A comma separated list of channel funding outpoints (format <fundingTXID>:<index>) to remove from the backup file."`
}
func (c *filterBackupCommand) Execute(_ []string) error {
setupChainParams(cfg)
var (
extendedKey *hdkeychain.ExtendedKey
err error
)
// Check that root key is valid or fall back to console input.
switch {
case c.RootKey != "":
extendedKey, err = hdkeychain.NewKeyFromString(c.RootKey)
default:
extendedKey, err = rootKeyFromConsole()
}
if err != nil {
return fmt.Errorf("error reading root key: %v", err)
}
// Parse discard filter.
discard := strings.Split(c.Discard, ",")
// Check that we have a backup file.
if c.MultiFile == "" {
return fmt.Errorf("backup file is required")
}
multiFile := chanbackup.NewMultiFile(c.MultiFile)
keyRing := &btc.ChannelBackupEncryptionRing{
ExtendedKey: extendedKey,
ChainParams: chainParams,
}
return filterChannelBackup(multiFile, keyRing, discard)
}
func filterChannelBackup(multiFile *chanbackup.MultiFile, ring keychain.KeyRing,
discard []string) error {
multi, err := multiFile.ExtractMulti(ring)
if err != nil {
return fmt.Errorf("could not extract multi file: %v", err)
}
keep := make([]chanbackup.Single, 0, len(multi.StaticBackups))
for _, single := range multi.StaticBackups {
found := false
for _, discardChanPoint := range discard {
if single.FundingOutpoint.String() == discardChanPoint {
found = true
}
}
if found {
continue
}
keep = append(keep, single)
}
multi.StaticBackups = keep
fileName := fmt.Sprintf("results/backup-filtered-%s.backup",
time.Now().Format("2006-01-02-15-04-05"))
log.Infof("Writing result to %s", fileName)
f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
err = multi.PackToWriter(f, ring)
_ = f.Close()
if err != nil {
return err
}
return nil
}

@ -93,6 +93,10 @@ func runCommandParser() error {
"derivekey", "Derive a key with a specific derivation path "+
"from the BIP32 HD root key.", "", &deriveKeyCommand{},
)
_, _ = parser.AddCommand(
"filterbackup", "Filter an lnd channel.backup file and " +
"remove certain channels.", "", &filterBackupCommand{},
)
_, err := parser.Parse()
return err

@ -61,8 +61,8 @@ func (c *ListChannelsChannel) AsSummaryEntry() *SummaryEntry {
return &SummaryEntry{
RemotePubkey: c.RemotePubkey,
ChannelPoint: c.ChannelPoint,
FundingTXID: fundingTXID(c.ChannelPoint),
FundingTXIndex: fundingTXIndex(c.ChannelPoint),
FundingTXID: FundingTXID(c.ChannelPoint),
FundingTXIndex: FundingTXIndex(c.ChannelPoint),
Capacity: uint64(c.Capacity),
Initiator: c.Initiator,
LocalBalance: uint64(c.LocalBalance),
@ -115,8 +115,8 @@ func (c *PendingChannelsChannel) AsSummaryEntry() *SummaryEntry {
return &SummaryEntry{
RemotePubkey: c.Channel.RemotePubkey,
ChannelPoint: c.Channel.ChannelPoint,
FundingTXID: fundingTXID(c.Channel.ChannelPoint),
FundingTXIndex: fundingTXIndex(c.Channel.ChannelPoint),
FundingTXID: FundingTXID(c.Channel.ChannelPoint),
FundingTXIndex: FundingTXIndex(c.Channel.ChannelPoint),
Capacity: uint64(c.Channel.Capacity),
Initiator: false,
LocalBalance: uint64(c.Channel.LocalBalance),
@ -159,7 +159,7 @@ func (f *SummaryEntryFile) AsSummaryEntries() ([]*SummaryEntry, error) {
return f.Channels, nil
}
func fundingTXID(chanPoint string) string {
func FundingTXID(chanPoint string) string {
parts := strings.Split(chanPoint, ":")
if len(parts) != 2 {
panic(fmt.Errorf("channel point not in format <txid>:<idx>: %s",
@ -168,7 +168,7 @@ func fundingTXID(chanPoint string) string {
return parts[0]
}
func fundingTXIndex(chanPoint string) uint32 {
func FundingTXIndex(chanPoint string) uint32 {
parts := strings.Split(chanPoint, ":")
if len(parts) != 2 {
panic(fmt.Errorf("channel point %s not in format <txid>:<idx>",

Loading…
Cancel
Save