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"
|
"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
|
// 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
|
// 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
|
// 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
|
// WalletSeed is the deciphered cipher seed that the wallet should use
|
||||||
// to initialize itself.
|
// to initialize itself.
|
||||||
WalletSeed *aezeed.CipherSeed
|
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
|
// 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 is a channel that carries all wallet init messages.
|
||||||
InitMsgs chan *WalletInitMsg
|
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
|
// client to be used to unlock and decrypt an existing wallet will be
|
||||||
// sent.
|
// sent.
|
||||||
UnlockPasswords chan []byte
|
UnlockMsgs chan *WalletUnlockMsg
|
||||||
|
|
||||||
chainDir string
|
chainDir string
|
||||||
netParams *chaincfg.Params
|
netParams *chaincfg.Params
|
||||||
@ -52,10 +74,10 @@ func New(authSvc *macaroons.Service, chainDir string,
|
|||||||
params *chaincfg.Params) *UnlockerService {
|
params *chaincfg.Params) *UnlockerService {
|
||||||
|
|
||||||
return &UnlockerService{
|
return &UnlockerService{
|
||||||
InitMsgs: make(chan *WalletInitMsg, 1),
|
InitMsgs: make(chan *WalletInitMsg, 1),
|
||||||
UnlockPasswords: make(chan []byte, 1),
|
UnlockMsgs: make(chan *WalletUnlockMsg, 1),
|
||||||
chainDir: chainDir,
|
chainDir: chainDir,
|
||||||
netParams: params,
|
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
|
// 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.
|
// so we don't show a *new* seed to the user if one already exists.
|
||||||
netDir := btcwallet.NetworkDir(u.chainDir, u.netParams)
|
netDir := btcwallet.NetworkDir(u.chainDir, u.netParams)
|
||||||
loader := wallet.NewLoader(u.netParams, netDir)
|
loader := wallet.NewLoader(u.netParams, netDir, 0)
|
||||||
walletExists, err := loader.WalletExists()
|
walletExists, err := loader.WalletExists()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -156,10 +178,17 @@ func (u *UnlockerService) InitWallet(ctx context.Context,
|
|||||||
"at least 8 characters")
|
"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
|
// 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.
|
// wallet's files so we can check if the wallet already exists.
|
||||||
netDir := btcwallet.NetworkDir(u.chainDir, u.netParams)
|
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()
|
walletExists, err := loader.WalletExists()
|
||||||
if err != nil {
|
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
|
// now send over the wallet password and the seed. This will allow the
|
||||||
// daemon to initialize itself and startup.
|
// daemon to initialize itself and startup.
|
||||||
initMsg := &WalletInitMsg{
|
initMsg := &WalletInitMsg{
|
||||||
Passphrase: password,
|
Passphrase: password,
|
||||||
WalletSeed: cipherSeed,
|
WalletSeed: cipherSeed,
|
||||||
|
RecoveryWindow: uint32(recoveryWindow),
|
||||||
}
|
}
|
||||||
|
|
||||||
u.InitMsgs <- initMsg
|
u.InitMsgs <- initMsg
|
||||||
@ -208,13 +238,16 @@ func (u *UnlockerService) InitWallet(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnlockWallet sends the password provided by the incoming UnlockWalletRequest
|
// UnlockWallet sends the password provided by the incoming UnlockWalletRequest
|
||||||
// over the UnlockPasswords channel in case it successfully decrypts an
|
// over the UnlockMsgs channel in case it successfully decrypts an existing
|
||||||
// existing wallet found in the chain's wallet database directory.
|
// wallet found in the chain's wallet database directory.
|
||||||
func (u *UnlockerService) UnlockWallet(ctx context.Context,
|
func (u *UnlockerService) UnlockWallet(ctx context.Context,
|
||||||
in *lnrpc.UnlockWalletRequest) (*lnrpc.UnlockWalletResponse, error) {
|
in *lnrpc.UnlockWalletRequest) (*lnrpc.UnlockWalletResponse, error) {
|
||||||
|
|
||||||
|
password := in.WalletPassword
|
||||||
|
recoveryWindow := uint32(in.RecoveryWindow)
|
||||||
|
|
||||||
netDir := btcwallet.NetworkDir(u.chainDir, u.netParams)
|
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.
|
// Check if wallet already exists.
|
||||||
walletExists, err := loader.WalletExists()
|
walletExists, err := loader.WalletExists()
|
||||||
@ -228,7 +261,7 @@ func (u *UnlockerService) UnlockWallet(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try opening the existing wallet with the provided password.
|
// Try opening the existing wallet with the provided password.
|
||||||
_, err = loader.OpenExistingWallet(in.WalletPassword, false)
|
_, err = loader.OpenExistingWallet(password, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Could not open wallet, most likely this means that provided
|
// Could not open wallet, most likely this means that provided
|
||||||
// password was incorrect.
|
// password was incorrect.
|
||||||
@ -244,17 +277,22 @@ func (u *UnlockerService) UnlockWallet(ctx context.Context,
|
|||||||
|
|
||||||
// Attempt to create a password for the macaroon service.
|
// Attempt to create a password for the macaroon service.
|
||||||
if u.authSvc != nil {
|
if u.authSvc != nil {
|
||||||
err = u.authSvc.CreateUnlock(&in.WalletPassword)
|
err = u.authSvc.CreateUnlock(&password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to create/unlock "+
|
return nil, fmt.Errorf("unable to create/unlock "+
|
||||||
"macaroon store: %v", err)
|
"macaroon store: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
walletUnlockMsg := &WalletUnlockMsg{
|
||||||
|
Passphrase: password,
|
||||||
|
RecoveryWindow: recoveryWindow,
|
||||||
|
}
|
||||||
|
|
||||||
// At this point we was able to open the existing wallet with the
|
// 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.
|
// channel, such that it can be used by lnd to open the wallet.
|
||||||
u.UnlockPasswords <- in.WalletPassword
|
u.UnlockMsgs <- walletUnlockMsg
|
||||||
|
|
||||||
return &lnrpc.UnlockWalletResponse{}, nil
|
return &lnrpc.UnlockWalletResponse{}, nil
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,10 @@ var (
|
|||||||
|
|
||||||
func createTestWallet(t *testing.T, dir string, netParams *chaincfg.Params) {
|
func createTestWallet(t *testing.T, dir string, netParams *chaincfg.Params) {
|
||||||
netDir := btcwallet.NetworkDir(dir, netParams)
|
netDir := btcwallet.NetworkDir(dir, netParams)
|
||||||
loader := wallet.NewLoader(netParams, netDir)
|
loader := wallet.NewLoader(netParams, netDir, 0)
|
||||||
_, err := loader.CreateNewWallet(testPassword, testPassword, testSeed)
|
_, err := loader.CreateNewWallet(
|
||||||
|
testPassword, testPassword, testSeed, time.Time{},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed creating wallet: %v", err)
|
t.Fatalf("failed creating wallet: %v", err)
|
||||||
}
|
}
|
||||||
@ -340,10 +342,10 @@ func TestUnlockWallet(t *testing.T) {
|
|||||||
|
|
||||||
// Password should be sent over the channel.
|
// Password should be sent over the channel.
|
||||||
select {
|
select {
|
||||||
case pw := <-service.UnlockPasswords:
|
case unlockMsg := <-service.UnlockMsgs:
|
||||||
if !bytes.Equal(pw, testPassword) {
|
if !bytes.Equal(unlockMsg.Passphrase, testPassword) {
|
||||||
t.Fatalf("expected to receive password %x, got %x",
|
t.Fatalf("expected to receive password %x, got %x",
|
||||||
testPassword, pw)
|
testPassword, unlockMsg.Passphrase)
|
||||||
}
|
}
|
||||||
case <-time.After(3 * time.Second):
|
case <-time.After(3 * time.Second):
|
||||||
t.Fatalf("password not received")
|
t.Fatalf("password not received")
|
||||||
|
Loading…
Reference in New Issue
Block a user