walletunlocker: accept recovery window from InitWallet
This commit is contained in:
parent
c824af11a1
commit
f8c0357770
@ -14,7 +14,7 @@ import (
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// WalletInitMsg is a message sent to the UnlockerService when a user wishes to
|
||||
// WalletInitMsg is a message sent by the UnlockerService when a user wishes to
|
||||
// set up the internal wallet for the first time. The user MUST provide a
|
||||
// passphrase, but is also able to provide their own source of entropy. If
|
||||
// provided, then this source of entropy will be used to generate the wallet's
|
||||
@ -27,6 +27,28 @@ type WalletInitMsg struct {
|
||||
// WalletSeed is the deciphered cipher seed that the wallet should use
|
||||
// to initialize itself.
|
||||
WalletSeed *aezeed.CipherSeed
|
||||
|
||||
// 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
|
||||
// creation.
|
||||
RecoveryWindow uint32
|
||||
}
|
||||
|
||||
// WalletUnlockMsg is a message sent by the UnlockerService when a user wishes
|
||||
// to unlock the internal wallet after initial setup. The user can optionally
|
||||
// specify a recovery window, which will resume an interrupted rescan for used
|
||||
// addresses.
|
||||
type WalletUnlockMsg struct {
|
||||
// Passphrase is the passphrase that will be used to encrypt the wallet
|
||||
// itself. This MUST be at least 8 characters.
|
||||
Passphrase []byte
|
||||
|
||||
// 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
|
||||
// creation, but before any addresses have been created.
|
||||
RecoveryWindow uint32
|
||||
}
|
||||
|
||||
// UnlockerService implements the WalletUnlocker service used to provide lnd
|
||||
@ -37,10 +59,10 @@ type UnlockerService struct {
|
||||
// InitMsgs is a channel that carries all wallet init messages.
|
||||
InitMsgs chan *WalletInitMsg
|
||||
|
||||
// UnlockPasswords is a channel where passwords provided by the rpc
|
||||
// UnlockMsgs is a channel where unlock parameters provided by the rpc
|
||||
// client to be used to unlock and decrypt an existing wallet will be
|
||||
// sent.
|
||||
UnlockPasswords chan []byte
|
||||
UnlockMsgs chan *WalletUnlockMsg
|
||||
|
||||
chainDir string
|
||||
netParams *chaincfg.Params
|
||||
@ -52,10 +74,10 @@ func New(authSvc *macaroons.Service, chainDir string,
|
||||
params *chaincfg.Params) *UnlockerService {
|
||||
|
||||
return &UnlockerService{
|
||||
InitMsgs: make(chan *WalletInitMsg, 1),
|
||||
UnlockPasswords: make(chan []byte, 1),
|
||||
chainDir: chainDir,
|
||||
netParams: params,
|
||||
InitMsgs: make(chan *WalletInitMsg, 1),
|
||||
UnlockMsgs: make(chan *WalletUnlockMsg, 1),
|
||||
chainDir: chainDir,
|
||||
netParams: params,
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +95,7 @@ func (u *UnlockerService) GenSeed(ctx context.Context,
|
||||
// Before we start, we'll ensure that the wallet hasn't already created
|
||||
// so we don't show a *new* seed to the user if one already exists.
|
||||
netDir := btcwallet.NetworkDir(u.chainDir, u.netParams)
|
||||
loader := wallet.NewLoader(u.netParams, netDir)
|
||||
loader := wallet.NewLoader(u.netParams, netDir, 0)
|
||||
walletExists, err := loader.WalletExists()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -156,10 +178,17 @@ func (u *UnlockerService) InitWallet(ctx context.Context,
|
||||
"at least 8 characters")
|
||||
}
|
||||
|
||||
// Require that the recovery window be non-negative.
|
||||
recoveryWindow := in.RecoveryWindow
|
||||
if recoveryWindow < 0 {
|
||||
return nil, fmt.Errorf("recovery window %d must be "+
|
||||
"non-negative", recoveryWindow)
|
||||
}
|
||||
|
||||
// We'll then open up the directory that will be used to store the
|
||||
// wallet's files so we can check if the wallet already exists.
|
||||
netDir := btcwallet.NetworkDir(u.chainDir, u.netParams)
|
||||
loader := wallet.NewLoader(u.netParams, netDir)
|
||||
loader := wallet.NewLoader(u.netParams, netDir, uint32(recoveryWindow))
|
||||
|
||||
walletExists, err := loader.WalletExists()
|
||||
if err != nil {
|
||||
@ -198,8 +227,9 @@ func (u *UnlockerService) InitWallet(ctx context.Context,
|
||||
// now send over the wallet password and the seed. This will allow the
|
||||
// daemon to initialize itself and startup.
|
||||
initMsg := &WalletInitMsg{
|
||||
Passphrase: password,
|
||||
WalletSeed: cipherSeed,
|
||||
Passphrase: password,
|
||||
WalletSeed: cipherSeed,
|
||||
RecoveryWindow: uint32(recoveryWindow),
|
||||
}
|
||||
|
||||
u.InitMsgs <- initMsg
|
||||
@ -208,13 +238,16 @@ func (u *UnlockerService) InitWallet(ctx context.Context,
|
||||
}
|
||||
|
||||
// UnlockWallet sends the password provided by the incoming UnlockWalletRequest
|
||||
// over the UnlockPasswords channel in case it successfully decrypts an
|
||||
// existing wallet found in the chain's wallet database directory.
|
||||
// over the UnlockMsgs channel in case it successfully decrypts an existing
|
||||
// wallet found in the chain's wallet database directory.
|
||||
func (u *UnlockerService) UnlockWallet(ctx context.Context,
|
||||
in *lnrpc.UnlockWalletRequest) (*lnrpc.UnlockWalletResponse, error) {
|
||||
|
||||
password := in.WalletPassword
|
||||
recoveryWindow := uint32(in.RecoveryWindow)
|
||||
|
||||
netDir := btcwallet.NetworkDir(u.chainDir, u.netParams)
|
||||
loader := wallet.NewLoader(u.netParams, netDir)
|
||||
loader := wallet.NewLoader(u.netParams, netDir, recoveryWindow)
|
||||
|
||||
// Check if wallet already exists.
|
||||
walletExists, err := loader.WalletExists()
|
||||
@ -228,7 +261,7 @@ func (u *UnlockerService) UnlockWallet(ctx context.Context,
|
||||
}
|
||||
|
||||
// Try opening the existing wallet with the provided password.
|
||||
_, err = loader.OpenExistingWallet(in.WalletPassword, false)
|
||||
_, err = loader.OpenExistingWallet(password, false)
|
||||
if err != nil {
|
||||
// Could not open wallet, most likely this means that provided
|
||||
// password was incorrect.
|
||||
@ -244,17 +277,22 @@ func (u *UnlockerService) UnlockWallet(ctx context.Context,
|
||||
|
||||
// Attempt to create a password for the macaroon service.
|
||||
if u.authSvc != nil {
|
||||
err = u.authSvc.CreateUnlock(&in.WalletPassword)
|
||||
err = u.authSvc.CreateUnlock(&password)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create/unlock "+
|
||||
"macaroon store: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
walletUnlockMsg := &WalletUnlockMsg{
|
||||
Passphrase: password,
|
||||
RecoveryWindow: recoveryWindow,
|
||||
}
|
||||
|
||||
// At this point we was able to open the existing wallet with the
|
||||
// provided password. We send the password over the UnlockPasswords
|
||||
// provided password. We send the password over the UnlockMsgs
|
||||
// channel, such that it can be used by lnd to open the wallet.
|
||||
u.UnlockPasswords <- in.WalletPassword
|
||||
u.UnlockMsgs <- walletUnlockMsg
|
||||
|
||||
return &lnrpc.UnlockWalletResponse{}, nil
|
||||
}
|
||||
|
@ -37,8 +37,10 @@ var (
|
||||
|
||||
func createTestWallet(t *testing.T, dir string, netParams *chaincfg.Params) {
|
||||
netDir := btcwallet.NetworkDir(dir, netParams)
|
||||
loader := wallet.NewLoader(netParams, netDir)
|
||||
_, err := loader.CreateNewWallet(testPassword, testPassword, testSeed)
|
||||
loader := wallet.NewLoader(netParams, netDir, 0)
|
||||
_, err := loader.CreateNewWallet(
|
||||
testPassword, testPassword, testSeed, time.Time{},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creating wallet: %v", err)
|
||||
}
|
||||
@ -340,10 +342,10 @@ func TestUnlockWallet(t *testing.T) {
|
||||
|
||||
// Password should be sent over the channel.
|
||||
select {
|
||||
case pw := <-service.UnlockPasswords:
|
||||
if !bytes.Equal(pw, testPassword) {
|
||||
case unlockMsg := <-service.UnlockMsgs:
|
||||
if !bytes.Equal(unlockMsg.Passphrase, testPassword) {
|
||||
t.Fatalf("expected to receive password %x, got %x",
|
||||
testPassword, pw)
|
||||
testPassword, unlockMsg.Passphrase)
|
||||
}
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatalf("password not received")
|
||||
|
Loading…
Reference in New Issue
Block a user