Lock/unlock all account wallets.

Now that it has been decided that all account wallets will share the
same passphrase, the walletlock and walletpassphrase RPC handlers now
go through the accountstore to lock or unlock all account wallets,
rather than only changing the default account.
This commit is contained in:
Josh Rickmar 2014-01-27 15:48:12 -05:00
parent e2bf9a03da
commit b09e4f5200
3 changed files with 61 additions and 57 deletions

View file

@ -122,11 +122,18 @@ func (a *Account) Lock() error {
a.mtx.Lock()
defer a.mtx.Unlock()
err := a.Wallet.Lock()
if err == nil {
switch err := a.Wallet.Lock(); err {
case nil:
NotifyWalletLockStateChange(a.Name(), true)
}
return nil
case wallet.ErrWalletLocked:
// Do not pass wallet already locked errors to the caller.
return nil
default:
return err
}
}
// Unlock unlocks the underlying wallet for an account.
@ -134,11 +141,12 @@ func (a *Account) Unlock(passphrase []byte) error {
a.mtx.Lock()
defer a.mtx.Unlock()
err := a.Wallet.Unlock(passphrase)
if err == nil {
NotifyWalletLockStateChange(a.Name(), false)
if err := a.Wallet.Unlock(passphrase); err != nil {
return err
}
return a.Wallet.Unlock(passphrase)
NotifyWalletLockStateChange(a.Name(), false)
return nil
}
// Rollback reverts each stored Account to a state before the block

View file

@ -295,6 +295,42 @@ func (store *AccountStore) ChangePassphrase(old, new []byte) error {
return nil
}
// LockWallets locks all account's wallets in the store.
func (store *AccountStore) LockWallets() error {
store.RLock()
defer store.RUnlock()
for _, a := range store.accounts {
if err := a.Lock(); err != nil {
return err
}
}
return nil
}
// UnlockWallets unlocks all account's wallets in the store with the provided
// passphrase. If any wallet unlocks fail, all successfully unlocked wallets
// are locked again.
func (store *AccountStore) UnlockWallets(passphrase string) error {
store.RLock()
defer store.RUnlock()
unlockedAccts := make([]*Account, 0, len(store.accounts))
for _, a := range store.accounts {
if err := a.Unlock([]byte(passphrase)); err != nil {
for _, ua := range unlockedAccts {
ua.Lock()
}
return fmt.Errorf("cannot unlock account %v: %v",
a.name, err)
}
unlockedAccts = append(unlockedAccts, a)
}
return nil
}
// DumpKeys returns all WIF-encoded private keys associated with all
// accounts. All wallets must be unlocked for this operation to succeed.
func (store *AccountStore) DumpKeys() ([]string, error) {

View file

@ -1213,26 +1213,11 @@ func WalletIsLocked(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
return locked, nil
}
// WalletLock handles a walletlock request by locking the wallet,
// returning an error if the wallet is already locked.
//
// TODO(jrick): figure out how multiple wallets/accounts will work
// with this. Lock all the wallets, like if all accounts are locked
// for one bitcoind wallet?
// WalletLock handles a walletlock request by locking the all account
// wallets, returning an error if any wallet is not encrypted (for example,
// a watching-only wallet).
func WalletLock(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
a, err := accountstore.Account("")
switch err {
case nil:
break
case ErrAcctNotExist:
e := btcjson.Error{
Code: btcjson.ErrWallet.Code,
Message: "default account does not exist",
}
return nil, &e
default: // all other non-nil errors
if err := accountstore.LockWallets(); err != nil {
e := btcjson.Error{
Code: btcjson.ErrWallet.Code,
Message: err.Error(),
@ -1240,17 +1225,12 @@ func WalletLock(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
return nil, &e
}
if err := a.Lock(); err != nil {
return nil, &btcjson.ErrWalletWrongEncState
}
return nil, nil
}
// WalletPassphrase responds to the walletpassphrase request by unlocking
// the wallet. The decryption key is saved in the wallet until timeout
// seconds expires, after which the wallet is locked.
//
// TODO(jrick): figure out how to do this for non-default accounts.
func WalletPassphrase(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
// Type assert icmd to access parameters.
cmd, ok := icmd.(*btcjson.WalletPassphraseCmd)
@ -1258,19 +1238,7 @@ func WalletPassphrase(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
return nil, &btcjson.ErrInternal
}
a, err := accountstore.Account("")
switch err {
case nil:
break
case ErrAcctNotExist:
e := btcjson.Error{
Code: btcjson.ErrWallet.Code,
Message: "default account does not exist",
}
return nil, &e
default: // all other non-nil errors
if err := accountstore.UnlockWallets(cmd.Passphrase); err != nil {
e := btcjson.Error{
Code: btcjson.ErrWallet.Code,
Message: err.Error(),
@ -1278,20 +1246,12 @@ func WalletPassphrase(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
return nil, &e
}
switch err := a.Unlock([]byte(cmd.Passphrase)); err {
case nil:
go func(timeout int64) {
time.Sleep(time.Second * time.Duration(timeout))
_ = a.Lock()
_ = accountstore.LockWallets()
}(cmd.Timeout)
return nil, nil
case ErrAcctNotExist:
return nil, &btcjson.ErrWalletInvalidAccountName
default: // all other non-nil errors
return nil, &btcjson.ErrWalletPassphraseIncorrect
}
}
// WalletPassphraseChange responds to the walletpassphrasechange request