From d66f93cecdbae6a88bfb710e0d95d62340bf2460 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sat, 7 Mar 2015 12:38:33 +0100 Subject: accounts, core, eth, xeth: use account manager for everything The account manager is now responsible for picking the default account and the coinbase. --- accounts/account_manager.go | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) (limited to 'accounts/account_manager.go') diff --git a/accounts/account_manager.go b/accounts/account_manager.go index 3e9fa7799..3b7785231 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -42,7 +42,10 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) -var ErrLocked = errors.New("account is locked; please request passphrase") +var ( + ErrLocked = errors.New("account is locked") + ErrNoKeys = errors.New("no keys in store") +) // TODO: better name for this struct? type Account struct { @@ -56,17 +59,39 @@ type AccountManager struct { mutex sync.RWMutex } -func NewAccountManager(keyStore crypto.KeyStore2, unlockMilliseconds time.Duration) AccountManager { - keysMap := make(map[string]crypto.Key) - am := &AccountManager{ +func NewAccountManager(keyStore crypto.KeyStore2, unlockMilliseconds time.Duration) *AccountManager { + return &AccountManager{ keyStore: keyStore, - unlockedKeys: keysMap, + unlockedKeys: make(map[string]crypto.Key), unlockMilliseconds: unlockMilliseconds, } - return *am } -func (am AccountManager) DeleteAccount(address []byte, auth string) error { +// Coinbase returns the account address that mining rewards are sent to. +func (am *AccountManager) Coinbase() (addr []byte, err error) { + // TODO: persist coinbase address on disk + return am.firstAddr() +} + +// MainAccount returns the primary account used for transactions. +func (am *AccountManager) Default() (*Account, error) { + // TODO: persist main account address on disk + addr, err := am.firstAddr() + return &Account{Address: addr}, err +} + +func (am *AccountManager) firstAddr() ([]byte, error) { + addrs, err := am.keyStore.GetKeyAddresses() + if err != nil { + return nil, err + } + if len(addrs) == 0 { + return nil, ErrNoKeys + } + return addrs[0], nil +} + +func (am *AccountManager) DeleteAccount(address []byte, auth string) error { return am.keyStore.DeleteKey(address, auth) } -- cgit v1.2.3 From fda7b4c79d070f1cb4f5d7ef5b4d077d9dcf2774 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sun, 8 Mar 2015 00:18:13 +0100 Subject: accounts: use pointers consistently Account is now always a non-pointer. This will be important once the manager starts remembering accounts. AccountManager is now always a pointer because it contains locks and locks cannot be copied. --- accounts/account_manager.go | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'accounts/account_manager.go') diff --git a/accounts/account_manager.go b/accounts/account_manager.go index 3b7785231..86f9c5916 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -47,7 +47,6 @@ var ( ErrNoKeys = errors.New("no keys in store") ) -// TODO: better name for this struct? type Account struct { Address []byte } @@ -74,10 +73,10 @@ func (am *AccountManager) Coinbase() (addr []byte, err error) { } // MainAccount returns the primary account used for transactions. -func (am *AccountManager) Default() (*Account, error) { +func (am *AccountManager) Default() (Account, error) { // TODO: persist main account address on disk addr, err := am.firstAddr() - return &Account{Address: addr}, err + return Account{Address: addr}, err } func (am *AccountManager) firstAddr() ([]byte, error) { @@ -95,9 +94,9 @@ func (am *AccountManager) DeleteAccount(address []byte, auth string) error { return am.keyStore.DeleteKey(address, auth) } -func (am *AccountManager) Sign(fromAccount *Account, toSign []byte) (signature []byte, err error) { +func (am *AccountManager) Sign(a Account, toSign []byte) (signature []byte, err error) { am.mutex.RLock() - unlockedKey := am.unlockedKeys[string(fromAccount.Address)] + unlockedKey := am.unlockedKeys[string(a.Address)] am.mutex.RUnlock() if unlockedKey.Address == nil { return nil, ErrLocked @@ -106,28 +105,25 @@ func (am *AccountManager) Sign(fromAccount *Account, toSign []byte) (signature [ return signature, err } -func (am *AccountManager) SignLocked(fromAccount *Account, keyAuth string, toSign []byte) (signature []byte, err error) { - key, err := am.keyStore.GetKey(fromAccount.Address, keyAuth) +func (am *AccountManager) SignLocked(a Account, keyAuth string, toSign []byte) (signature []byte, err error) { + key, err := am.keyStore.GetKey(a.Address, keyAuth) if err != nil { return nil, err } am.mutex.RLock() - am.unlockedKeys[string(fromAccount.Address)] = *key + am.unlockedKeys[string(a.Address)] = *key am.mutex.RUnlock() - go unlockLater(am, fromAccount.Address) + go unlockLater(am, a.Address) signature, err = crypto.Sign(toSign, key.PrivateKey) return signature, err } -func (am AccountManager) NewAccount(auth string) (*Account, error) { +func (am *AccountManager) NewAccount(auth string) (Account, error) { key, err := am.keyStore.GenerateNewKey(crand.Reader, auth) if err != nil { - return nil, err - } - ua := &Account{ - Address: key.Address, + return Account{}, err } - return ua, err + return Account{Address: key.Address}, nil } func (am *AccountManager) Accounts() ([]Account, error) { -- cgit v1.2.3 From afc530ea411e18223b0323d7e11aa0fab9289d65 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sun, 8 Mar 2015 00:35:23 +0100 Subject: accounts: use time.Duration correctly There is no point to using time.Duration if the value is interpreted as milliseconds. Callers should use the standard multiplication idiom to choose the unit. In fact, the only caller outside of the tests already does so. --- accounts/account_manager.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'accounts/account_manager.go') diff --git a/accounts/account_manager.go b/accounts/account_manager.go index 86f9c5916..f87cce65f 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -33,6 +33,7 @@ and accounts persistence is derived from stored keys' addresses package accounts import ( + "crypto/ecdsa" crand "crypto/rand" "errors" @@ -52,17 +53,17 @@ type Account struct { } type AccountManager struct { - keyStore crypto.KeyStore2 - unlockedKeys map[string]crypto.Key - unlockMilliseconds time.Duration - mutex sync.RWMutex + keyStore crypto.KeyStore2 + unlockedKeys map[string]crypto.Key + unlockTime time.Duration + mutex sync.RWMutex } -func NewAccountManager(keyStore crypto.KeyStore2, unlockMilliseconds time.Duration) *AccountManager { +func NewAccountManager(keyStore crypto.KeyStore2, unlockTime time.Duration) *AccountManager { return &AccountManager{ - keyStore: keyStore, - unlockedKeys: make(map[string]crypto.Key), - unlockMilliseconds: unlockMilliseconds, + keyStore: keyStore, + unlockedKeys: make(map[string]crypto.Key), + unlockTime: unlockTime, } } @@ -144,7 +145,7 @@ func (am *AccountManager) Accounts() ([]Account, error) { func unlockLater(am *AccountManager, addr []byte) { select { - case <-time.After(time.Millisecond * am.unlockMilliseconds): + case <-time.After(am.unlockTime): } am.mutex.RLock() // TODO: how do we know the key is actually gone from memory? -- cgit v1.2.3 From d6a7332993cf32960ef94947341cedd3061559a7 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sun, 8 Mar 2015 00:36:06 +0100 Subject: accounts: fix uses of sync.RWMutex RWMutexes must be write-locked when writing in order to actually protect the writes. --- accounts/account_manager.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'accounts/account_manager.go') diff --git a/accounts/account_manager.go b/accounts/account_manager.go index f87cce65f..c0f2953bd 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -111,9 +111,9 @@ func (am *AccountManager) SignLocked(a Account, keyAuth string, toSign []byte) ( if err != nil { return nil, err } - am.mutex.RLock() + am.mutex.Lock() am.unlockedKeys[string(a.Address)] = *key - am.mutex.RUnlock() + am.mutex.Unlock() go unlockLater(am, a.Address) signature, err = crypto.Sign(toSign, key.PrivateKey) return signature, err @@ -147,8 +147,10 @@ func unlockLater(am *AccountManager, addr []byte) { select { case <-time.After(am.unlockTime): } - am.mutex.RLock() + am.mutex.Lock() // TODO: how do we know the key is actually gone from memory? delete(am.unlockedKeys, string(addr)) - am.mutex.RUnlock() + am.mutex.Unlock() +} + } -- cgit v1.2.3 From 3750ec7b7de04d8482b798e73f04637ea9e1ca89 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sun, 8 Mar 2015 01:27:30 +0100 Subject: accounts: prevent early drops and zero keys in memory when dropping Private keys would be locked early if SignLocked was called more than once because the unlockLater was still running. Terminate it properly. --- accounts/account_manager.go | 69 ++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 19 deletions(-) (limited to 'accounts/account_manager.go') diff --git a/accounts/account_manager.go b/accounts/account_manager.go index c0f2953bd..bb6d970b2 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -53,17 +53,24 @@ type Account struct { } type AccountManager struct { - keyStore crypto.KeyStore2 - unlockedKeys map[string]crypto.Key - unlockTime time.Duration - mutex sync.RWMutex + keyStore crypto.KeyStore2 + unlocked map[string]*unlocked + unlockTime time.Duration + mutex sync.RWMutex +} + +type unlocked struct { + addr []byte + abort chan struct{} + + *crypto.Key } func NewAccountManager(keyStore crypto.KeyStore2, unlockTime time.Duration) *AccountManager { return &AccountManager{ - keyStore: keyStore, - unlockedKeys: make(map[string]crypto.Key), - unlockTime: unlockTime, + keyStore: keyStore, + unlocked: make(map[string]*unlocked), + unlockTime: unlockTime, } } @@ -97,9 +104,9 @@ func (am *AccountManager) DeleteAccount(address []byte, auth string) error { func (am *AccountManager) Sign(a Account, toSign []byte) (signature []byte, err error) { am.mutex.RLock() - unlockedKey := am.unlockedKeys[string(a.Address)] + unlockedKey, found := am.unlocked[string(a.Address)] am.mutex.RUnlock() - if unlockedKey.Address == nil { + if !found { return nil, ErrLocked } signature, err = crypto.Sign(toSign, unlockedKey.PrivateKey) @@ -111,10 +118,8 @@ func (am *AccountManager) SignLocked(a Account, keyAuth string, toSign []byte) ( if err != nil { return nil, err } - am.mutex.Lock() - am.unlockedKeys[string(a.Address)] = *key - am.mutex.Unlock() - go unlockLater(am, a.Address) + u := am.addUnlocked(a.Address, key) + go am.dropLater(u) signature, err = crypto.Sign(toSign, key.PrivateKey) return signature, err } @@ -143,14 +148,40 @@ func (am *AccountManager) Accounts() ([]Account, error) { return accounts, err } -func unlockLater(am *AccountManager, addr []byte) { - select { - case <-time.After(am.unlockTime): - } +func (am *AccountManager) addUnlocked(addr []byte, key *crypto.Key) *unlocked { + u := &unlocked{addr: addr, abort: make(chan struct{}), Key: key} am.mutex.Lock() - // TODO: how do we know the key is actually gone from memory? - delete(am.unlockedKeys, string(addr)) + prev, found := am.unlocked[string(addr)] + if found { + // terminate dropLater for this key to avoid unexpected drops. + close(prev.abort) + zeroKey(prev.PrivateKey) + } + am.unlocked[string(addr)] = u am.mutex.Unlock() + return u } +func (am *AccountManager) dropLater(u *unlocked) { + t := time.NewTimer(am.unlockTime) + defer t.Stop() + select { + case <-u.abort: + // just quit + case <-t.C: + am.mutex.Lock() + if am.unlocked[string(u.addr)] == u { + zeroKey(u.PrivateKey) + delete(am.unlocked, string(u.addr)) + } + am.mutex.Unlock() + } +} + +// zeroKey zeroes a private key in memory. +func zeroKey(k *ecdsa.PrivateKey) { + b := k.D.Bits() + for i := range b { + b[i] = 0 + } } -- cgit v1.2.3 From fb53a9362e1238d8edb466d77427dc3cbb13eb20 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sun, 8 Mar 2015 01:52:49 +0100 Subject: accounts: AccountManager -> Manager --- accounts/account_manager.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'accounts/account_manager.go') diff --git a/accounts/account_manager.go b/accounts/account_manager.go index bb6d970b2..97cf7c878 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -52,7 +52,7 @@ type Account struct { Address []byte } -type AccountManager struct { +type Manager struct { keyStore crypto.KeyStore2 unlocked map[string]*unlocked unlockTime time.Duration @@ -66,8 +66,8 @@ type unlocked struct { *crypto.Key } -func NewAccountManager(keyStore crypto.KeyStore2, unlockTime time.Duration) *AccountManager { - return &AccountManager{ +func NewManager(keyStore crypto.KeyStore2, unlockTime time.Duration) *Manager { + return &Manager{ keyStore: keyStore, unlocked: make(map[string]*unlocked), unlockTime: unlockTime, @@ -75,19 +75,19 @@ func NewAccountManager(keyStore crypto.KeyStore2, unlockTime time.Duration) *Acc } // Coinbase returns the account address that mining rewards are sent to. -func (am *AccountManager) Coinbase() (addr []byte, err error) { +func (am *Manager) Coinbase() (addr []byte, err error) { // TODO: persist coinbase address on disk return am.firstAddr() } // MainAccount returns the primary account used for transactions. -func (am *AccountManager) Default() (Account, error) { +func (am *Manager) Default() (Account, error) { // TODO: persist main account address on disk addr, err := am.firstAddr() return Account{Address: addr}, err } -func (am *AccountManager) firstAddr() ([]byte, error) { +func (am *Manager) firstAddr() ([]byte, error) { addrs, err := am.keyStore.GetKeyAddresses() if err != nil { return nil, err @@ -98,11 +98,11 @@ func (am *AccountManager) firstAddr() ([]byte, error) { return addrs[0], nil } -func (am *AccountManager) DeleteAccount(address []byte, auth string) error { +func (am *Manager) DeleteAccount(address []byte, auth string) error { return am.keyStore.DeleteKey(address, auth) } -func (am *AccountManager) Sign(a Account, toSign []byte) (signature []byte, err error) { +func (am *Manager) Sign(a Account, toSign []byte) (signature []byte, err error) { am.mutex.RLock() unlockedKey, found := am.unlocked[string(a.Address)] am.mutex.RUnlock() @@ -113,7 +113,7 @@ func (am *AccountManager) Sign(a Account, toSign []byte) (signature []byte, err return signature, err } -func (am *AccountManager) SignLocked(a Account, keyAuth string, toSign []byte) (signature []byte, err error) { +func (am *Manager) SignLocked(a Account, keyAuth string, toSign []byte) (signature []byte, err error) { key, err := am.keyStore.GetKey(a.Address, keyAuth) if err != nil { return nil, err @@ -124,7 +124,7 @@ func (am *AccountManager) SignLocked(a Account, keyAuth string, toSign []byte) ( return signature, err } -func (am *AccountManager) NewAccount(auth string) (Account, error) { +func (am *Manager) NewAccount(auth string) (Account, error) { key, err := am.keyStore.GenerateNewKey(crand.Reader, auth) if err != nil { return Account{}, err @@ -132,7 +132,7 @@ func (am *AccountManager) NewAccount(auth string) (Account, error) { return Account{Address: key.Address}, nil } -func (am *AccountManager) Accounts() ([]Account, error) { +func (am *Manager) Accounts() ([]Account, error) { addresses, err := am.keyStore.GetKeyAddresses() if err != nil { return nil, err @@ -148,7 +148,7 @@ func (am *AccountManager) Accounts() ([]Account, error) { return accounts, err } -func (am *AccountManager) addUnlocked(addr []byte, key *crypto.Key) *unlocked { +func (am *Manager) addUnlocked(addr []byte, key *crypto.Key) *unlocked { u := &unlocked{addr: addr, abort: make(chan struct{}), Key: key} am.mutex.Lock() prev, found := am.unlocked[string(addr)] @@ -162,7 +162,7 @@ func (am *AccountManager) addUnlocked(addr []byte, key *crypto.Key) *unlocked { return u } -func (am *AccountManager) dropLater(u *unlocked) { +func (am *Manager) dropLater(u *unlocked) { t := time.NewTimer(am.unlockTime) defer t.Stop() select { -- cgit v1.2.3 From 6684ef201a1a133aafdec6b24564533756de3cd4 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sun, 8 Mar 2015 02:45:02 +0100 Subject: accounts: don't store address in unlocked and add commentary This was suggested during review. --- accounts/account_manager.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'accounts/account_manager.go') diff --git a/accounts/account_manager.go b/accounts/account_manager.go index 97cf7c878..bb664878a 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -60,10 +60,8 @@ type Manager struct { } type unlocked struct { - addr []byte - abort chan struct{} - *crypto.Key + abort chan struct{} } func NewManager(keyStore crypto.KeyStore2, unlockTime time.Duration) *Manager { @@ -119,7 +117,7 @@ func (am *Manager) SignLocked(a Account, keyAuth string, toSign []byte) (signatu return nil, err } u := am.addUnlocked(a.Address, key) - go am.dropLater(u) + go am.dropLater(a.Address, u) signature, err = crypto.Sign(toSign, key.PrivateKey) return signature, err } @@ -149,7 +147,7 @@ func (am *Manager) Accounts() ([]Account, error) { } func (am *Manager) addUnlocked(addr []byte, key *crypto.Key) *unlocked { - u := &unlocked{addr: addr, abort: make(chan struct{}), Key: key} + u := &unlocked{Key: key, abort: make(chan struct{})} am.mutex.Lock() prev, found := am.unlocked[string(addr)] if found { @@ -162,7 +160,7 @@ func (am *Manager) addUnlocked(addr []byte, key *crypto.Key) *unlocked { return u } -func (am *Manager) dropLater(u *unlocked) { +func (am *Manager) dropLater(addr []byte, u *unlocked) { t := time.NewTimer(am.unlockTime) defer t.Stop() select { @@ -170,9 +168,13 @@ func (am *Manager) dropLater(u *unlocked) { // just quit case <-t.C: am.mutex.Lock() - if am.unlocked[string(u.addr)] == u { + // only drop if it's still the same key instance that dropLater + // was launched with. we can check that using pointer equality + // because the map stores a new pointer every time the key is + // unlocked. + if am.unlocked[string(addr)] == u { zeroKey(u.PrivateKey) - delete(am.unlocked, string(u.addr)) + delete(am.unlocked, string(addr)) } am.mutex.Unlock() } -- cgit v1.2.3 From c2e5dacf555d93cb96b8fbffa700a2a6fece8bf0 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 9 Mar 2015 23:02:43 +0100 Subject: accounts: add Manager.HasAccount, delete Manager.Default --- accounts/account_manager.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'accounts/account_manager.go') diff --git a/accounts/account_manager.go b/accounts/account_manager.go index bb664878a..4575334bf 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -33,6 +33,7 @@ and accounts persistence is derived from stored keys' addresses package accounts import ( + "bytes" "crypto/ecdsa" crand "crypto/rand" @@ -72,19 +73,22 @@ func NewManager(keyStore crypto.KeyStore2, unlockTime time.Duration) *Manager { } } +func (am *Manager) HasAccount(addr []byte) bool { + accounts, _ := am.Accounts() + for _, acct := range accounts { + if bytes.Compare(acct.Address, addr) == 0 { + return true + } + } + return false +} + // Coinbase returns the account address that mining rewards are sent to. func (am *Manager) Coinbase() (addr []byte, err error) { // TODO: persist coinbase address on disk return am.firstAddr() } -// MainAccount returns the primary account used for transactions. -func (am *Manager) Default() (Account, error) { - // TODO: persist main account address on disk - addr, err := am.firstAddr() - return Account{Address: addr}, err -} - func (am *Manager) firstAddr() ([]byte, error) { addrs, err := am.keyStore.GetKeyAddresses() if err != nil { @@ -135,9 +139,7 @@ func (am *Manager) Accounts() ([]Account, error) { if err != nil { return nil, err } - accounts := make([]Account, len(addresses)) - for i, addr := range addresses { accounts[i] = Account{ Address: addr, -- cgit v1.2.3 From 487f68ec4892794cb994cffd95d5bc2bf3052d3e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 10 Mar 2015 00:09:39 +0100 Subject: accounts: add {Timed,}Unlock, remove SignLocked --- accounts/account_manager.go | 48 +++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 17 deletions(-) (limited to 'accounts/account_manager.go') diff --git a/accounts/account_manager.go b/accounts/account_manager.go index 4575334bf..fdd7d83e9 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -54,10 +54,9 @@ type Account struct { } type Manager struct { - keyStore crypto.KeyStore2 - unlocked map[string]*unlocked - unlockTime time.Duration - mutex sync.RWMutex + keyStore crypto.KeyStore2 + unlocked map[string]*unlocked + mutex sync.RWMutex } type unlocked struct { @@ -65,11 +64,10 @@ type unlocked struct { abort chan struct{} } -func NewManager(keyStore crypto.KeyStore2, unlockTime time.Duration) *Manager { +func NewManager(keyStore crypto.KeyStore2) *Manager { return &Manager{ - keyStore: keyStore, - unlocked: make(map[string]*unlocked), - unlockTime: unlockTime, + keyStore: keyStore, + unlocked: make(map[string]*unlocked), } } @@ -115,15 +113,28 @@ func (am *Manager) Sign(a Account, toSign []byte) (signature []byte, err error) return signature, err } -func (am *Manager) SignLocked(a Account, keyAuth string, toSign []byte) (signature []byte, err error) { - key, err := am.keyStore.GetKey(a.Address, keyAuth) +// TimedUnlock unlocks the account with the given address. +// When timeout has passed, the account will be locked again. +func (am *Manager) TimedUnlock(addr []byte, keyAuth string, timeout time.Duration) error { + key, err := am.keyStore.GetKey(addr, keyAuth) if err != nil { - return nil, err + return err } - u := am.addUnlocked(a.Address, key) - go am.dropLater(a.Address, u) - signature, err = crypto.Sign(toSign, key.PrivateKey) - return signature, err + u := am.addUnlocked(addr, key) + go am.dropLater(addr, u, timeout) + return nil +} + +// Unlock unlocks the account with the given address. The account +// stays unlocked until the program exits or until a TimedUnlock +// timeout (started after the call to Unlock) expires. +func (am *Manager) Unlock(addr []byte, keyAuth string) error { + key, err := am.keyStore.GetKey(addr, keyAuth) + if err != nil { + return err + } + am.addUnlocked(addr, key) + return nil } func (am *Manager) NewAccount(auth string) (Account, error) { @@ -155,6 +166,9 @@ func (am *Manager) addUnlocked(addr []byte, key *crypto.Key) *unlocked { if found { // terminate dropLater for this key to avoid unexpected drops. close(prev.abort) + // the key is zeroed here instead of in dropLater because + // there might not actually be a dropLater running for this + // key, i.e. when Unlock was used. zeroKey(prev.PrivateKey) } am.unlocked[string(addr)] = u @@ -162,8 +176,8 @@ func (am *Manager) addUnlocked(addr []byte, key *crypto.Key) *unlocked { return u } -func (am *Manager) dropLater(addr []byte, u *unlocked) { - t := time.NewTimer(am.unlockTime) +func (am *Manager) dropLater(addr []byte, u *unlocked, timeout time.Duration) { + t := time.NewTimer(timeout) defer t.Stop() select { case <-u.abort: -- cgit v1.2.3 From 4ba7871374fd3af08bfad972509267842db6df99 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 10 Mar 2015 15:41:08 +0100 Subject: accounts: return ErrNoKeys if key directory does not exist --- accounts/account_manager.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'accounts/account_manager.go') diff --git a/accounts/account_manager.go b/accounts/account_manager.go index fdd7d83e9..646dc8376 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -36,6 +36,7 @@ import ( "bytes" "crypto/ecdsa" crand "crypto/rand" + "os" "errors" "sync" @@ -89,7 +90,9 @@ func (am *Manager) Coinbase() (addr []byte, err error) { func (am *Manager) firstAddr() ([]byte, error) { addrs, err := am.keyStore.GetKeyAddresses() - if err != nil { + if os.IsNotExist(err) { + return nil, ErrNoKeys + } else if err != nil { return nil, err } if len(addrs) == 0 { @@ -147,7 +150,9 @@ func (am *Manager) NewAccount(auth string) (Account, error) { func (am *Manager) Accounts() ([]Account, error) { addresses, err := am.keyStore.GetKeyAddresses() - if err != nil { + if os.IsNotExist(err) { + return nil, ErrNoKeys + } else if err != nil { return nil, err } accounts := make([]Account, len(addresses)) -- cgit v1.2.3