Merge pull request #215 from ziggie1984/update-fixoldchannel-cmd

Enhance FixOldChannelBackup cmd
This commit is contained in:
Oli 2025-11-06 06:53:35 -06:00 committed by GitHub
commit 8049650042
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 77 additions and 4 deletions

View file

@ -8,6 +8,7 @@ import (
"github.com/lightninglabs/chantools/lnd"
"github.com/lightningnetwork/lnd/chanbackup"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/spf13/cobra"
)
@ -77,15 +78,64 @@ func fixOldChannelBackup(multiFile *chanbackup.MultiFile,
for idx, single := range multi.StaticBackups {
err := ring.CheckDescriptor(single.ShaChainRootDesc)
switch {
case err == nil:
// If the descriptor is correct or the error is because no
// public key is provided, skip the channel. This can happen
// if the backup file has partially valid and invalid channels.
case err == nil || errors.Is(err, lnd.ErrNoPublicKeyProvided):
log.Infof("The shachain root for channel %v is "+
"correct, skipping...", single.FundingOutpoint)
continue
case errors.Is(err, keychain.ErrCannotDerivePrivKey):
// Before fixing the descriptor, print the funding
// multisig P2WSH witness program hash. Derive the
// local multisig pubkey via its locator if needed
// (and possible).
localPub, err := ring.PubKeyForDescriptor(
single.LocalChanCfg.MultiSigKey,
)
if err != nil {
return fmt.Errorf("could not derive local "+
"multisig pubkey for channel %v: %w",
single.FundingOutpoint, err)
}
remotePub, err := ring.PubKeyForDescriptor(
single.RemoteChanCfg.MultiSigKey,
)
if err != nil {
return fmt.Errorf("could not derive remote "+
"multisig pubkey for channel %v: %w",
single.FundingOutpoint, err)
}
a := localPub.SerializeCompressed()
b := remotePub.SerializeCompressed()
msScript, err := input.GenMultiSigScript(a, b)
if err != nil {
return fmt.Errorf("could not generate "+
"multisig script for channel "+
"%v: %w",
single.FundingOutpoint, err)
}
msHash, err := input.WitnessScriptHash(msScript)
if err != nil {
return fmt.Errorf("could not compute "+
"multisig script hash: %w", err)
}
log.Infof("Channel %v funding multisig P2WSH "+
"(pubkey): %x",
single.FundingOutpoint, msHash)
// Fix the incorrect descriptor by deriving a default
// one and overwriting it in the backup.
log.Infof("The shachain root for channel %s could "+
log.Infof("The shachain root for channel %v could "+
"not be derived, must be in old format. "+
"Fixing...", single.FundingOutpoint.String())
"Fixing...", single.FundingOutpoint)
baseKeyDesc, err := ring.DeriveKey(keychain.KeyLocator{
Family: keychain.KeyFamilyRevocationRoot,
Index: 0,

View file

@ -21,6 +21,10 @@ import (
"github.com/lightningnetwork/lnd/shachain"
)
// ErrNoPublicKeyProvided is returned when a key descriptor check is attempted
// without a public key present in the descriptor.
var ErrNoPublicKeyProvided = errors.New("no public key provided to check")
const (
HardenedKeyStart = uint32(hdkeychain.HardenedKeyStart)
WalletDefaultDerivationPath = "m/84'/0'/0'"
@ -609,7 +613,7 @@ func (r *HDKeyRing) CheckDescriptor(
// A check doesn't make sense if there is no public key set.
if keyDesc.PubKey == nil {
return errors.New("no public key provided to check")
return ErrNoPublicKeyProvided
}
// Performance fix, derive static path only once.
@ -658,3 +662,22 @@ func (r *HDKeyRing) NodePubKey() (*btcec.PublicKey, error) {
return keyDesc.PubKey, nil
}
// PubKeyForDescriptor returns the public key for a given key descriptor. If the
// descriptor already contains a public key, it is returned as-is. Otherwise,
// the public key is derived using the descriptor's key locator.
func (r *HDKeyRing) PubKeyForDescriptor(desc keychain.KeyDescriptor) (
*btcec.PublicKey, error) {
if desc.PubKey != nil {
return desc.PubKey, nil
}
// Attempt to derive using the provided key locator.
kd, err := r.DeriveKey(desc.KeyLocator)
if err != nil {
return nil, err
}
return kd.PubKey, nil
}