mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-12 22:59:38 +02:00
multi: allow watch-only wallet creation
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcutil/hdkeychain"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
"github.com/btcsuite/btcwallet/wallet"
|
||||
"github.com/lightningnetwork/lnd/aezeed"
|
||||
"github.com/lightningnetwork/lnd/chanbackup"
|
||||
@@ -103,6 +104,18 @@ type WalletInitMsg struct {
|
||||
// through an extended key instead of an aezeed.
|
||||
ExtendedKeyBirthday time.Time
|
||||
|
||||
// WatchOnlyAccounts is a map of scoped account extended public keys
|
||||
// that should be imported to create a watch-only wallet.
|
||||
WatchOnlyAccounts map[waddrmgr.ScopedIndex]*hdkeychain.ExtendedKey
|
||||
|
||||
// WatchOnlyBirthday is the birthday of the master root key the above
|
||||
// watch-only account xpubs were derived from.
|
||||
WatchOnlyBirthday time.Time
|
||||
|
||||
// WatchOnlyMasterFingerprint is the fingerprint of the master root key
|
||||
// the above watch-only account xpubs were derived from.
|
||||
WatchOnlyMasterFingerprint uint32
|
||||
|
||||
// RecoveryWindow is the address look-ahead used when restoring a seed
|
||||
// with existing funds. A recovery window zero indicates that no
|
||||
// recovery should be attempted, such as after the wallet's initial
|
||||
@@ -495,6 +508,66 @@ func (u *UnlockerService) InitWallet(ctx context.Context,
|
||||
|
||||
initMsg.WalletExtendedKey = extendedKey
|
||||
|
||||
// The third option for creating a wallet is the watch-only mode:
|
||||
// Instead of providing the master root key directly, each individual
|
||||
// account is passed as an extended public key only. Because of the
|
||||
// hardened derivation path up to the account (depth 3), it is not
|
||||
// possible to create a master root extended _public_ key. Therefore, an
|
||||
// xpub must be derived and passed into the unlocker for _every_ account
|
||||
// lnd expects.
|
||||
case in.WatchOnly != nil && len(in.WatchOnly.Accounts) > 0:
|
||||
initMsg.WatchOnlyAccounts = make(
|
||||
map[waddrmgr.ScopedIndex]*hdkeychain.ExtendedKey,
|
||||
len(in.WatchOnly.Accounts),
|
||||
)
|
||||
|
||||
for _, acct := range in.WatchOnly.Accounts {
|
||||
scopedIndex := waddrmgr.ScopedIndex{
|
||||
Scope: waddrmgr.KeyScope{
|
||||
Purpose: acct.Purpose,
|
||||
Coin: acct.CoinType,
|
||||
},
|
||||
Index: acct.Account,
|
||||
}
|
||||
acctKey, err := hdkeychain.NewKeyFromString(acct.Xpub)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing xpub "+
|
||||
"%v: %v", acct.Xpub, err)
|
||||
}
|
||||
|
||||
// Just to make sure the user is doing the right thing,
|
||||
// we expect the public key to be at derivation depth
|
||||
// three (which is the account level) and the key not to
|
||||
// contain any private key material.
|
||||
if acctKey.Depth() != 3 {
|
||||
return nil, fmt.Errorf("xpub must be at " +
|
||||
"depth 3")
|
||||
}
|
||||
if acctKey.IsPrivate() {
|
||||
return nil, fmt.Errorf("xpub is not really " +
|
||||
"an xpub, contains private key")
|
||||
}
|
||||
|
||||
initMsg.WatchOnlyAccounts[scopedIndex] = acctKey
|
||||
}
|
||||
|
||||
// When importing a wallet from its extended public keys we
|
||||
// don't know the birthday as that information is not encoded in
|
||||
// that format. We therefore must set an arbitrary date to start
|
||||
// rescanning at if the user doesn't provide an explicit value
|
||||
// for it. Since lnd only uses SegWit addresses, we pick the
|
||||
// date of the first block that contained SegWit transactions
|
||||
// (481824).
|
||||
initMsg.WatchOnlyBirthday = time.Date(
|
||||
2017, time.August, 24, 1, 57, 37, 0, time.UTC,
|
||||
)
|
||||
if in.WatchOnly.MasterKeyBirthdayTimestamp != 0 {
|
||||
initMsg.WatchOnlyBirthday = time.Unix(
|
||||
int64(in.WatchOnly.MasterKeyBirthdayTimestamp),
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
// No key material was set, no wallet can be created.
|
||||
default:
|
||||
return nil, fmt.Errorf("must either specify cipher seed " +
|
||||
|
Reference in New Issue
Block a user