lnwallet: initialize first 255 accounts

This fixes lightninglabs/loop#437 by adding all accounts that are used
in liquidity products such as Loop or Pool. Since both of these products
use key families below 255, we can get by with that number.
The alternative to creating way too many accounts (which increases the
default wallet size by ~250kB) would be to hard code the exact accounts
used by Loop (99) and Pool (210). But that sounds like a bad idea given
that there could always be more accounts being added to those (or other)
products. By making sure the first 255 accounts exist, we have a lot
more flexibility in those products for choosing key families.
This commit is contained in:
Oliver Gugger
2022-01-05 11:04:32 +01:00
parent 0bdac59a8c
commit afc53d1c52
2 changed files with 60 additions and 81 deletions

View File

@@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/btcsuite/btcwallet/waddrmgr" "github.com/btcsuite/btcwallet/waddrmgr"
"github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
@@ -39,76 +40,6 @@ var (
Xpub: "tpubDDWAWrSLRSFrG1KdqXMQQyTKYGSKLKaY7gxpvK7RdV3e3Dkhvu" + Xpub: "tpubDDWAWrSLRSFrG1KdqXMQQyTKYGSKLKaY7gxpvK7RdV3e3Dkhvu" +
"W2GgsFvsPN4RGmuoYtUgZ1LHZE8oftz7T4mzc1BxGt5rt8zJcVQi" + "W2GgsFvsPN4RGmuoYtUgZ1LHZE8oftz7T4mzc1BxGt5rt8zJcVQi" +
"KTPPV", "KTPPV",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyMultiSig),
Xpub: "tpubDDXFHr67Ro2tHKVWG2gNjjijKUH1Lyv5NKFYdJnuaLGVNBVwyV" +
"5AbykhR43iy8wYozEMbw2QfmAqZhb8gnuL5mm9sZh8YsR6FjGAbe" +
"w1xoT",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyRevocationBase),
Xpub: "tpubDDXFHr67Ro2tKkccDqNfDqZpd5wCs2n6XRV2Uh185DzCTbkDaE" +
"d9v7P837zZTYBNVfaRriuxgGVgxbGjDui4CKxyzBzwz4aAZxjn2P" +
"hNcQy",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyHtlcBase),
Xpub: "tpubDDXFHr67Ro2tNH4KH41i4oTsWfRjFigoH1Ee7urvHow51opH9x" +
"J7mu1qSPMPVtkVqQZ5tE4NTuFJPrbDqno7TQietyUDmPTwyVviJb" +
"GCwXk",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyPaymentBase),
Xpub: "tpubDDXFHr67Ro2tQj5Zvav2ALhkU6dRQAhEtNPnYJVBC8hs2U1A9e" +
"cqxRY3XTiJKBDD7e8tudhmTRs8aGWJAiAXJN5kXy3Hi6cmiwGWjX" +
"K5Cv5",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyDelayBase),
Xpub: "tpubDDXFHr67Ro2tSSR2LLBJtotxx2U45cuESLWKA72YT9td3SzVKH" +
"AptzDEx5chsUNZ4WRMY5h6HJxRSebjRatxQKX1uUsux1LvKS1wsf" +
"NJ2PH",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyRevocationRoot),
Xpub: "tpubDDXFHr67Ro2tTwzfWvNoMoPpZbxdMEfe1WhbXJxvXikGixPa4g" +
"gSRZeGx6T5yxVHTVT3rjVh35Veqsowj7emX8SZfXKDKDKcLduXCe" +
"WPUU3",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyNodeKey),
Xpub: "tpubDDXFHr67Ro2tYEDS2EByRedfsUoEwBtrzVbS1qdPrX6sAkUYGL" +
"rZWvMmQv8KZDZ4zd9r8WzM9bJ2nGp7XuNVC4w2EBtWg7i76gbrmu" +
"EWjQh",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyStaticBackup),
Xpub: "tpubDDXFHr67Ro2tYpwnFJEQaM8eAPM2UV5uY6gFgXeSzS5aC5T9Tf" +
"zXuawYKBbQMZJn8qHXLafY4tAutoda1aKP5h6Nbgy3swPbnhWbFj" +
"S5wnX",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyTowerSession),
Xpub: "tpubDDXFHr67Ro2tddKpAjUegXqt7EGxRXnHkeLbUkfuFMGbLJYgRp" +
"G4ew5pMmGg2nmcGmHFQ29w3juNhd8N5ZZ8HwJdymC4f5ukQLJ4yg" +
"9rEr3",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyTowerID),
Xpub: "tpubDDXFHr67Ro2tgE89V8ZdgMytC2Jq1iT9ttGhdzR1X7haQJNBmX" +
"t8kau6taC6DGASYzbrjmo9z9w6JQFcaLNqbhS2h2PVSzKf79j265" +
"Zi8hF",
}} }}
) )
@@ -181,7 +112,7 @@ func testRemoteSigner(net *lntest.NetworkHarness, t *harnessTest) {
password := []byte("itestpassword") password := []byte("itestpassword")
var ( var (
signerNodePubKey = nodePubKey signerNodePubKey = nodePubKey
watchOnlyAccounts = accounts watchOnlyAccounts = deriveCustomScopeAccounts(t.t)
signer *lntest.HarnessNode signer *lntest.HarnessNode
err error err error
) )
@@ -261,3 +192,55 @@ func testRemoteSigner(net *lntest.NetworkHarness, t *harnessTest) {
} }
} }
} }
// deriveCustomScopeAccounts derives the first 255 default accounts of the custom lnd
// internal key scope.
func deriveCustomScopeAccounts(t *testing.T) []*lnrpc.WatchOnlyAccount {
allAccounts := make([]*lnrpc.WatchOnlyAccount, 0, 255+len(accounts))
allAccounts = append(allAccounts, accounts...)
extendedRootKey, err := hdkeychain.NewKeyFromString(rootKey)
require.NoError(t, err)
path := []uint32{
keychain.BIP0043Purpose + hdkeychain.HardenedKeyStart,
harnessNetParams.HDCoinType + hdkeychain.HardenedKeyStart,
}
coinTypeKey, err := derivePath(extendedRootKey, path)
require.NoError(t, err)
for idx := uint32(0); idx <= 255; idx++ {
accountPath := []uint32{idx + hdkeychain.HardenedKeyStart}
accountKey, err := derivePath(coinTypeKey, accountPath)
require.NoError(t, err)
accountXPub, err := accountKey.Neuter()
require.NoError(t, err)
allAccounts = append(allAccounts, &lnrpc.WatchOnlyAccount{
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: idx,
Xpub: accountXPub.String(),
})
}
return allAccounts
}
// derivePath derives the given path from an extended key.
func derivePath(key *hdkeychain.ExtendedKey, path []uint32) (
*hdkeychain.ExtendedKey, error) {
var (
currentKey = key
err error
)
for _, pathPart := range path {
currentKey, err = currentKey.Derive(pathPart)
if err != nil {
return nil, err
}
}
return currentKey, nil
}

View File

@@ -323,17 +323,13 @@ func (b *BtcWallet) Start() error {
err = walletdb.Update(b.db, func(tx walletdb.ReadWriteTx) error { err = walletdb.Update(b.db, func(tx walletdb.ReadWriteTx) error {
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey) addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
for _, keyFam := range keychain.VersionZeroKeyFamilies { // Generate all accounts that we could ever need. This includes
// If this is the multi-sig key family, then we can // all lnd key families as well as some key families used in
// return early as this is the default account that's // external liquidity tools.
// created. for keyFam := uint32(1); keyFam <= 255; keyFam++ {
if keyFam == keychain.KeyFamilyMultiSig {
continue
}
// Otherwise, we'll check if the account already exists, // Otherwise, we'll check if the account already exists,
// if so, we can once again bail early. // if so, we can once again bail early.
_, err := scope.AccountName(addrmgrNs, uint32(keyFam)) _, err := scope.AccountName(addrmgrNs, keyFam)
if err == nil { if err == nil {
continue continue
} }
@@ -341,7 +337,7 @@ func (b *BtcWallet) Start() error {
// If we reach this point, then the account hasn't yet // If we reach this point, then the account hasn't yet
// been created, so we'll need to create it before we // been created, so we'll need to create it before we
// can proceed. // can proceed.
err = scope.NewRawAccount(addrmgrNs, uint32(keyFam)) err = scope.NewRawAccount(addrmgrNs, keyFam)
if err != nil { if err != nil {
return err return err
} }