From a399c2ceeda3660e5648efc7f5a1ca1dd150b143 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 30 Mar 2020 18:33:00 +0200 Subject: [PATCH] Start exporting library functions --- cmd/chantools/chanbackup.go | 27 +--------- cmd/chantools/derivekey.go | 27 ++-------- cmd/chantools/dumpbackup.go | 27 +--------- cmd/chantools/dumpchannels.go | 59 ++-------------------- dump/dump.go | 94 +++++++++++++++++++++++++++++++++++ lnd/chanbackup.go | 35 +++++++++++++ lnd/hdkeychain.go | 36 ++++++++++++++ 7 files changed, 174 insertions(+), 131 deletions(-) create mode 100644 lnd/chanbackup.go diff --git a/cmd/chantools/chanbackup.go b/cmd/chantools/chanbackup.go index 20d925a..7e871f1 100644 --- a/cmd/chantools/chanbackup.go +++ b/cmd/chantools/chanbackup.go @@ -1,7 +1,6 @@ package main import ( - "bytes" "fmt" "path" @@ -9,7 +8,6 @@ import ( "github.com/guggero/chantools/lnd" "github.com/lightningnetwork/lnd/chanbackup" "github.com/lightningnetwork/lnd/channeldb" - "github.com/lightningnetwork/lnd/keychain" ) type chanBackupCommand struct { @@ -59,28 +57,5 @@ func (c *chanBackupCommand) Execute(_ []string) error { ExtendedKey: extendedKey, ChainParams: chainParams, } - return createChannelBackup(db, multiFile, keyRing) -} - -func createChannelBackup(db *channeldb.DB, multiFile *chanbackup.MultiFile, - ring keychain.KeyRing) error { - - singles, err := chanbackup.FetchStaticChanBackups(db) - if err != nil { - return fmt.Errorf("error extracting channel backup: %v", err) - } - multi := &chanbackup.Multi{ - Version: chanbackup.DefaultMultiVersion, - StaticBackups: singles, - } - var b bytes.Buffer - err = multi.PackToWriter(&b, ring) - if err != nil { - return fmt.Errorf("unable to pack backup: %v", err) - } - err = multiFile.UpdateAndSwap(b.Bytes()) - if err != nil { - return fmt.Errorf("unable to write backup file: %v", err) - } - return nil + return lnd.CreateChannelBackup(db, multiFile, keyRing) } diff --git a/cmd/chantools/derivekey.go b/cmd/chantools/derivekey.go index a4b8e5e..93f6e77 100644 --- a/cmd/chantools/derivekey.go +++ b/cmd/chantools/derivekey.go @@ -3,7 +3,6 @@ package main import ( "fmt" - "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/hdkeychain" "github.com/guggero/chantools/lnd" ) @@ -41,33 +40,15 @@ func deriveKey(extendedKey *hdkeychain.ExtendedKey, path string, neuter bool) error { fmt.Printf("Deriving path %s for network %s.\n", path, chainParams.Name) - parsedPath, err := lnd.ParsePath(path) + pubKey, wif, err := lnd.DeriveKey(extendedKey, path, chainParams) if err != nil { - return fmt.Errorf("could not parse derivation path: %v", err) - } - derivedKey, err := lnd.DeriveChildren(extendedKey, parsedPath) - if err != nil { - return fmt.Errorf("could not derive children: %v", err) - } - pubKey, err := derivedKey.ECPubKey() - if err != nil { - return fmt.Errorf("could not derive public key: %v", err) + return fmt.Errorf("could not derive keys: %v", err) } fmt.Printf("Public key: %x\n", pubKey.SerializeCompressed()) - if neuter { - return nil - } - - privKey, err := derivedKey.ECPrivKey() - if err != nil { - return fmt.Errorf("could not derive private key: %v", err) - } - wif, err := btcutil.NewWIF(privKey, chainParams, true) - if err != nil { - return fmt.Errorf("could not encode WIF: %v", err) + if !neuter { + fmt.Printf("Private key (WIF): %s\n", wif.String()) } - fmt.Printf("Private key (WIF): %s\n", wif.String()) return nil } diff --git a/cmd/chantools/dumpbackup.go b/cmd/chantools/dumpbackup.go index fe9ca0e..0b60e7f 100644 --- a/cmd/chantools/dumpbackup.go +++ b/cmd/chantools/dumpbackup.go @@ -55,34 +55,9 @@ func dumpChannelBackup(multiFile *chanbackup.MultiFile, 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{ - Version: single.Version, - IsInitiator: single.IsInitiator, - ChainHash: single.ChainHash.String(), - FundingOutpoint: single.FundingOutpoint.String(), - ShortChannelID: single.ShortChannelID, - RemoteNodePub: dump.PubKeyToString( - single.RemoteNodePub, - ), - Addresses: single.Addresses, - Capacity: single.Capacity, - LocalChanCfg: dump.ToChannelConfig( - chainParams, single.LocalChanCfg, - ), - RemoteChanCfg: dump.ToChannelConfig( - chainParams, single.RemoteChanCfg, - ), - ShaChainRootDesc: dump.ToKeyDescriptor( - chainParams, single.ShaChainRootDesc, - ), - } - } - spew.Dump(dump.BackupMulti{ Version: multi.Version, - StaticBackups: dumpSingles, + StaticBackups: dump.BackupDump(multi, chainParams), }) return nil } diff --git a/cmd/chantools/dumpchannels.go b/cmd/chantools/dumpchannels.go index 8cff7ff..51812dc 100644 --- a/cmd/chantools/dumpchannels.go +++ b/cmd/chantools/dumpchannels.go @@ -1,15 +1,12 @@ package main import ( - "bytes" - "encoding/hex" "fmt" "path" "github.com/davecgh/go-spew/spew" "github.com/guggero/chantools/dump" "github.com/lightningnetwork/lnd/channeldb" - "github.com/lightningnetwork/lnd/input" ) type dumpChannelsCommand struct { @@ -39,59 +36,9 @@ func dumpChannelInfo(chanDb *channeldb.DB) error { return err } - dumpChannels := make([]dump.OpenChannel, len(channels)) - for idx, channel := range channels { - var buf bytes.Buffer - if channel.FundingTxn != nil { - err = channel.FundingTxn.Serialize(&buf) - if err != nil { - return err - } - } - revPreimage, err := channel.RevocationProducer.AtIndex( - channel.LocalCommitment.CommitHeight, - ) - if err != nil { - return err - } - perCommitPoint := input.ComputeCommitmentPoint(revPreimage[:]) - - dumpChannels[idx] = dump.OpenChannel{ - ChanType: channel.ChanType, - ChainHash: channel.ChainHash, - FundingOutpoint: channel.FundingOutpoint.String(), - ShortChannelID: channel.ShortChannelID, - IsPending: channel.IsPending, - IsInitiator: channel.IsInitiator, - ChanStatus: channel.ChanStatus(), - FundingBroadcastHeight: channel.FundingBroadcastHeight, - NumConfsRequired: channel.NumConfsRequired, - ChannelFlags: channel.ChannelFlags, - IdentityPub: dump.PubKeyToString( - channel.IdentityPub, - ), - Capacity: channel.Capacity, - TotalMSatSent: channel.TotalMSatSent, - TotalMSatReceived: channel.TotalMSatReceived, - PerCommitPoint: dump.PubKeyToString(perCommitPoint), - LocalChanCfg: dump.ToChannelConfig( - chainParams, channel.LocalChanCfg, - ), - RemoteChanCfg: dump.ToChannelConfig( - chainParams, channel.RemoteChanCfg, - ), - LocalCommitment: channel.LocalCommitment, - RemoteCommitment: channel.RemoteCommitment, - RemoteCurrentRevocation: dump.PubKeyToString( - channel.RemoteCurrentRevocation, - ), - RemoteNextRevocation: dump.PubKeyToString( - channel.RemoteNextRevocation, - ), - FundingTxn: hex.EncodeToString(buf.Bytes()), - LocalShutdownScript: channel.LocalShutdownScript, - RemoteShutdownScript: channel.RemoteShutdownScript, - } + dumpChannels, err := dump.ChannelDump(channels, chainParams) + if err != nil { + return fmt.Errorf("error converting to dump format: %v", err) } spew.Dump(dumpChannels) diff --git a/dump/dump.go b/dump/dump.go index 880001e..784e90d 100644 --- a/dump/dump.go +++ b/dump/dump.go @@ -1,8 +1,10 @@ package dump import ( + "bytes" "encoding/hex" "fmt" + "github.com/lightningnetwork/lnd/input" "net" "github.com/btcsuite/btcd/btcec" @@ -90,6 +92,98 @@ type KeyDescriptor struct { PubKey string } +// ChannelDump converts the channels in the given channel DB into a dumpable +// format. +func ChannelDump(channels []*channeldb.OpenChannel, params *chaincfg.Params) ( + []OpenChannel, error) { + + dumpChannels := make([]OpenChannel, len(channels)) + for idx, channel := range channels { + var buf bytes.Buffer + if channel.FundingTxn != nil { + err := channel.FundingTxn.Serialize(&buf) + if err != nil { + return nil, err + } + } + revPreimage, err := channel.RevocationProducer.AtIndex( + channel.LocalCommitment.CommitHeight, + ) + if err != nil { + return nil, err + } + perCommitPoint := input.ComputeCommitmentPoint(revPreimage[:]) + + dumpChannels[idx] = OpenChannel{ + ChanType: channel.ChanType, + ChainHash: channel.ChainHash, + FundingOutpoint: channel.FundingOutpoint.String(), + ShortChannelID: channel.ShortChannelID, + IsPending: channel.IsPending, + IsInitiator: channel.IsInitiator, + ChanStatus: channel.ChanStatus(), + FundingBroadcastHeight: channel.FundingBroadcastHeight, + NumConfsRequired: channel.NumConfsRequired, + ChannelFlags: channel.ChannelFlags, + IdentityPub: PubKeyToString( + channel.IdentityPub, + ), + Capacity: channel.Capacity, + TotalMSatSent: channel.TotalMSatSent, + TotalMSatReceived: channel.TotalMSatReceived, + PerCommitPoint: PubKeyToString(perCommitPoint), + LocalChanCfg: ToChannelConfig( + params, channel.LocalChanCfg, + ), + RemoteChanCfg: ToChannelConfig( + params, channel.RemoteChanCfg, + ), + LocalCommitment: channel.LocalCommitment, + RemoteCommitment: channel.RemoteCommitment, + RemoteCurrentRevocation: PubKeyToString( + channel.RemoteCurrentRevocation, + ), + RemoteNextRevocation: PubKeyToString( + channel.RemoteNextRevocation, + ), + FundingTxn: hex.EncodeToString(buf.Bytes()), + LocalShutdownScript: channel.LocalShutdownScript, + RemoteShutdownScript: channel.RemoteShutdownScript, + } + } + return dumpChannels, nil +} + +// BackupDump converts the given multi backup into a dumpable format. +func BackupDump(multi *chanbackup.Multi, params *chaincfg.Params) []BackupSingle { + + dumpSingles := make([]BackupSingle, len(multi.StaticBackups)) + for idx, single := range multi.StaticBackups { + dumpSingles[idx] = BackupSingle{ + Version: single.Version, + IsInitiator: single.IsInitiator, + ChainHash: single.ChainHash.String(), + FundingOutpoint: single.FundingOutpoint.String(), + ShortChannelID: single.ShortChannelID, + RemoteNodePub: PubKeyToString( + single.RemoteNodePub, + ), + Addresses: single.Addresses, + Capacity: single.Capacity, + LocalChanCfg: ToChannelConfig( + params, single.LocalChanCfg, + ), + RemoteChanCfg: ToChannelConfig( + params, single.RemoteChanCfg, + ), + ShaChainRootDesc: ToKeyDescriptor( + params, single.ShaChainRootDesc, + ), + } + } + return dumpSingles +} + func ToChannelConfig(params *chaincfg.Params, cfg channeldb.ChannelConfig) ChannelConfig { diff --git a/lnd/chanbackup.go b/lnd/chanbackup.go new file mode 100644 index 0000000..b2f0276 --- /dev/null +++ b/lnd/chanbackup.go @@ -0,0 +1,35 @@ +package lnd + +import ( + "bytes" + "fmt" + + "github.com/lightningnetwork/lnd/chanbackup" + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/keychain" +) + +// CreateChannelBackup creates a channel backup file from all channels found in +// the given DB file, encrypted with the key in the key ring. +func CreateChannelBackup(db *channeldb.DB, multiFile *chanbackup.MultiFile, + ring keychain.KeyRing) error { + + singles, err := chanbackup.FetchStaticChanBackups(db) + if err != nil { + return fmt.Errorf("error extracting channel backup: %v", err) + } + multi := &chanbackup.Multi{ + Version: chanbackup.DefaultMultiVersion, + StaticBackups: singles, + } + var b bytes.Buffer + err = multi.PackToWriter(&b, ring) + if err != nil { + return fmt.Errorf("unable to pack backup: %v", err) + } + err = multiFile.UpdateAndSwap(b.Bytes()) + if err != nil { + return fmt.Errorf("unable to write backup file: %v", err) + } + return nil +} diff --git a/lnd/hdkeychain.go b/lnd/hdkeychain.go index 71b8fc0..9898ebd 100644 --- a/lnd/hdkeychain.go +++ b/lnd/hdkeychain.go @@ -2,6 +2,8 @@ package lnd import ( "fmt" + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcutil" "strconv" "strings" @@ -57,6 +59,40 @@ func ParsePath(path string) ([]uint32, error) { return indices, nil } +// DeriveKey derives the public key and private key in the WIF format for a +// given key path of the extended key. +func DeriveKey(extendedKey *hdkeychain.ExtendedKey, path string, + params *chaincfg.Params) (*btcec.PublicKey, *btcutil.WIF, error) { + + parsedPath, err := ParsePath(path) + if err != nil { + return nil, nil, fmt.Errorf("could not parse derivation path: "+ + "%v", err) + } + derivedKey, err := DeriveChildren(extendedKey, parsedPath) + if err != nil { + return nil, nil, fmt.Errorf("could not derive children: %v", + err) + } + pubKey, err := derivedKey.ECPubKey() + if err != nil { + return nil, nil, fmt.Errorf("could not derive public key: %v", + err) + } + + privKey, err := derivedKey.ECPrivKey() + if err != nil { + return nil, nil, fmt.Errorf("could not derive private key: %v", + err) + } + wif, err := btcutil.NewWIF(privKey, params, true) + if err != nil { + return nil, nil, fmt.Errorf("could not encode WIF: %v", err) + } + + return pubKey, wif, nil +} + type HDKeyRing struct { ExtendedKey *hdkeychain.ExtendedKey ChainParams *chaincfg.Params