aboutsummaryrefslogtreecommitdiffstats
path: root/accounts/keystore
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2017-02-08 21:53:02 +0800
committerPéter Szilágyi <peterke@gmail.com>2017-02-13 20:00:08 +0800
commitc5215fdd48231622dd56aba63a5187c6e42828d4 (patch)
tree98bdb47dccb9ef3deaa571585c32db9d19166a80 /accounts/keystore
parentfad5eb0a87abfc12812647344a26de8a43830182 (diff)
downloaddexon-c5215fdd48231622dd56aba63a5187c6e42828d4.tar.gz
dexon-c5215fdd48231622dd56aba63a5187c6e42828d4.tar.zst
dexon-c5215fdd48231622dd56aba63a5187c6e42828d4.zip
accounts, cmd, internal, mobile, node: canonical account URLs
Diffstat (limited to 'accounts/keystore')
-rw-r--r--accounts/keystore/account_cache.go14
-rw-r--r--accounts/keystore/account_cache_test.go49
-rw-r--r--accounts/keystore/key.go4
-rw-r--r--accounts/keystore/keystore.go20
-rw-r--r--accounts/keystore/keystore_plain_test.go8
-rw-r--r--accounts/keystore/keystore_test.go10
-rw-r--r--accounts/keystore/keystore_wallet.go25
-rw-r--r--accounts/keystore/presale.go4
8 files changed, 68 insertions, 66 deletions
diff --git a/accounts/keystore/account_cache.go b/accounts/keystore/account_cache.go
index cc8626afc..e2f826250 100644
--- a/accounts/keystore/account_cache.go
+++ b/accounts/keystore/account_cache.go
@@ -42,7 +42,7 @@ const minReloadInterval = 2 * time.Second
type accountsByURL []accounts.Account
func (s accountsByURL) Len() int { return len(s) }
-func (s accountsByURL) Less(i, j int) bool { return s[i].URL < s[j].URL }
+func (s accountsByURL) Less(i, j int) bool { return s[i].URL.Cmp(s[j].URL) < 0 }
func (s accountsByURL) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// AmbiguousAddrError is returned when attempting to unlock
@@ -55,7 +55,7 @@ type AmbiguousAddrError struct {
func (err *AmbiguousAddrError) Error() string {
files := ""
for i, a := range err.Matches {
- files += a.URL
+ files += a.URL.Path
if i < len(err.Matches)-1 {
files += ", "
}
@@ -104,7 +104,7 @@ func (ac *accountCache) add(newAccount accounts.Account) {
ac.mu.Lock()
defer ac.mu.Unlock()
- i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].URL >= newAccount.URL })
+ i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].URL.Cmp(newAccount.URL) >= 0 })
if i < len(ac.all) && ac.all[i] == newAccount {
return
}
@@ -155,10 +155,10 @@ func (ac *accountCache) find(a accounts.Account) (accounts.Account, error) {
if (a.Address != common.Address{}) {
matches = ac.byAddr[a.Address]
}
- if a.URL != "" {
+ if a.URL.Path != "" {
// If only the basename is specified, complete the path.
- if !strings.ContainsRune(a.URL, filepath.Separator) {
- a.URL = filepath.Join(ac.keydir, a.URL)
+ if !strings.ContainsRune(a.URL.Path, filepath.Separator) {
+ a.URL.Path = filepath.Join(ac.keydir, a.URL.Path)
}
for i := range matches {
if matches[i].URL == a.URL {
@@ -272,7 +272,7 @@ func (ac *accountCache) scan() ([]accounts.Account, error) {
case (addr == common.Address{}):
glog.V(logger.Debug).Infof("can't decode key %s: missing or zero address", path)
default:
- addrs = append(addrs, accounts.Account{Address: addr, URL: path})
+ addrs = append(addrs, accounts.Account{Address: addr, URL: accounts.URL{Scheme: KeyStoreScheme, Path: path}})
}
fd.Close()
}
diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go
index ea6f7d011..3e68351ea 100644
--- a/accounts/keystore/account_cache_test.go
+++ b/accounts/keystore/account_cache_test.go
@@ -37,15 +37,15 @@ var (
cachetestAccounts = []accounts.Account{
{
Address: common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
- URL: filepath.Join(cachetestDir, "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(cachetestDir, "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8")},
},
{
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
- URL: filepath.Join(cachetestDir, "aaa"),
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(cachetestDir, "aaa")},
},
{
Address: common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"),
- URL: filepath.Join(cachetestDir, "zzz"),
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(cachetestDir, "zzz")},
},
}
)
@@ -63,10 +63,11 @@ func TestWatchNewFile(t *testing.T) {
// Move in the files.
wantAccounts := make([]accounts.Account, len(cachetestAccounts))
for i := range cachetestAccounts {
- a := cachetestAccounts[i]
- a.URL = filepath.Join(dir, filepath.Base(a.URL))
- wantAccounts[i] = a
- if err := cp.CopyFile(a.URL, cachetestAccounts[i].URL); err != nil {
+ wantAccounts[i] = accounts.Account{
+ Address: cachetestAccounts[i].Address,
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, filepath.Base(cachetestAccounts[i].URL.Path))},
+ }
+ if err := cp.CopyFile(wantAccounts[i].URL.Path, cachetestAccounts[i].URL.Path); err != nil {
t.Fatal(err)
}
}
@@ -107,13 +108,13 @@ func TestWatchNoDir(t *testing.T) {
os.MkdirAll(dir, 0700)
defer os.RemoveAll(dir)
file := filepath.Join(dir, "aaa")
- if err := cp.CopyFile(file, cachetestAccounts[0].URL); err != nil {
+ if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil {
t.Fatal(err)
}
// ks should see the account.
wantAccounts := []accounts.Account{cachetestAccounts[0]}
- wantAccounts[0].URL = file
+ wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file}
for d := 200 * time.Millisecond; d < 8*time.Second; d *= 2 {
list = ks.Accounts()
if reflect.DeepEqual(list, wantAccounts) {
@@ -145,31 +146,31 @@ func TestCacheAddDeleteOrder(t *testing.T) {
accs := []accounts.Account{
{
Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
- URL: "-309830980",
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: "-309830980"},
},
{
Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"),
- URL: "ggg",
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: "ggg"},
},
{
Address: common.HexToAddress("8bda78331c916a08481428e4b07c96d3e916d165"),
- URL: "zzzzzz-the-very-last-one.keyXXX",
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: "zzzzzz-the-very-last-one.keyXXX"},
},
{
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
- URL: "SOMETHING.key",
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: "SOMETHING.key"},
},
{
Address: common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
- URL: "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8",
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8"},
},
{
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
- URL: "aaa",
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: "aaa"},
},
{
Address: common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"),
- URL: "zzz",
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: "zzz"},
},
}
for _, a := range accs {
@@ -210,7 +211,7 @@ func TestCacheAddDeleteOrder(t *testing.T) {
for i := 0; i < len(accs); i += 2 {
cache.delete(wantAccounts[i])
}
- cache.delete(accounts.Account{Address: common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e"), URL: "something"})
+ cache.delete(accounts.Account{Address: common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e"), URL: accounts.URL{Scheme: KeyStoreScheme, Path: "something"}})
select {
case <-notify:
@@ -245,19 +246,19 @@ func TestCacheFind(t *testing.T) {
accs := []accounts.Account{
{
Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
- URL: filepath.Join(dir, "a.key"),
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "a.key")},
},
{
Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"),
- URL: filepath.Join(dir, "b.key"),
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "b.key")},
},
{
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
- URL: filepath.Join(dir, "c.key"),
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "c.key")},
},
{
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
- URL: filepath.Join(dir, "c2.key"),
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "c2.key")},
},
}
for _, a := range accs {
@@ -266,7 +267,7 @@ func TestCacheFind(t *testing.T) {
nomatchAccount := accounts.Account{
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
- URL: filepath.Join(dir, "something"),
+ URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "something")},
}
tests := []struct {
Query accounts.Account
@@ -278,7 +279,7 @@ func TestCacheFind(t *testing.T) {
// by file
{Query: accounts.Account{URL: accs[0].URL}, WantResult: accs[0]},
// by basename
- {Query: accounts.Account{URL: filepath.Base(accs[0].URL)}, WantResult: accs[0]},
+ {Query: accounts.Account{URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Base(accs[0].URL.Path)}}, WantResult: accs[0]},
// by file and address
{Query: accs[0], WantResult: accs[0]},
// ambiguous address, tie resolved by file
@@ -294,7 +295,7 @@ func TestCacheFind(t *testing.T) {
// no match error
{Query: nomatchAccount, WantError: ErrNoMatch},
{Query: accounts.Account{URL: nomatchAccount.URL}, WantError: ErrNoMatch},
- {Query: accounts.Account{URL: filepath.Base(nomatchAccount.URL)}, WantError: ErrNoMatch},
+ {Query: accounts.Account{URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Base(nomatchAccount.URL.Path)}}, WantError: ErrNoMatch},
{Query: accounts.Account{Address: nomatchAccount.Address}, WantError: ErrNoMatch},
}
for i, test := range tests {
diff --git a/accounts/keystore/key.go b/accounts/keystore/key.go
index 1cf5f9366..e2bdf09fe 100644
--- a/accounts/keystore/key.go
+++ b/accounts/keystore/key.go
@@ -181,8 +181,8 @@ func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Accou
if err != nil {
return nil, accounts.Account{}, err
}
- a := accounts.Account{Address: key.Address, URL: ks.JoinPath(keyFileName(key.Address))}
- if err := ks.StoreKey(a.URL, key, auth); err != nil {
+ a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.JoinPath(keyFileName(key.Address))}}
+ if err := ks.StoreKey(a.URL.Path, key, auth); err != nil {
zeroKey(key.PrivateKey)
return nil, a, err
}
diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go
index ce4e87ce9..a01ff17e3 100644
--- a/accounts/keystore/keystore.go
+++ b/accounts/keystore/keystore.go
@@ -49,6 +49,9 @@ var (
// KeyStoreType is the reflect type of a keystore backend.
var KeyStoreType = reflect.TypeOf(&KeyStore{})
+// KeyStoreScheme is the protocol scheme prefixing account and wallet URLs.
+var KeyStoreScheme = "keystore"
+
// Maximum time between wallet refreshes (if filesystem notifications don't work).
const walletRefreshCycle = 3 * time.Second
@@ -130,22 +133,21 @@ func (ks *KeyStore) Wallets() []accounts.Wallet {
// necessary wallet refreshes.
func (ks *KeyStore) refreshWallets() {
// Retrieve the current list of accounts
+ ks.mu.Lock()
accs := ks.cache.accounts()
// Transform the current list of wallets into the new one
- ks.mu.Lock()
-
wallets := make([]accounts.Wallet, 0, len(accs))
events := []accounts.WalletEvent{}
for _, account := range accs {
// Drop wallets while they were in front of the next account
- for len(ks.wallets) > 0 && ks.wallets[0].URL() < account.URL {
+ for len(ks.wallets) > 0 && ks.wallets[0].URL().Cmp(account.URL) < 0 {
events = append(events, accounts.WalletEvent{Wallet: ks.wallets[0], Arrive: false})
ks.wallets = ks.wallets[1:]
}
// If there are no more wallets or the account is before the next, wrap new wallet
- if len(ks.wallets) == 0 || ks.wallets[0].URL() > account.URL {
+ if len(ks.wallets) == 0 || ks.wallets[0].URL().Cmp(account.URL) > 0 {
wallet := &keystoreWallet{account: account, keystore: ks}
events = append(events, accounts.WalletEvent{Wallet: wallet, Arrive: true})
@@ -242,7 +244,7 @@ func (ks *KeyStore) Delete(a accounts.Account, passphrase string) error {
// The order is crucial here. The key is dropped from the
// cache after the file is gone so that a reload happening in
// between won't insert it into the cache again.
- err = os.Remove(a.URL)
+ err = os.Remove(a.URL.Path)
if err == nil {
ks.cache.delete(a)
ks.refreshWallets()
@@ -377,7 +379,7 @@ func (ks *KeyStore) getDecryptedKey(a accounts.Account, auth string) (accounts.A
if err != nil {
return a, nil, err
}
- key, err := ks.storage.GetKey(a.Address, a.URL, auth)
+ key, err := ks.storage.GetKey(a.Address, a.URL.Path, auth)
return a, key, err
}
@@ -453,8 +455,8 @@ func (ks *KeyStore) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (acco
}
func (ks *KeyStore) importKey(key *Key, passphrase string) (accounts.Account, error) {
- a := accounts.Account{Address: key.Address, URL: ks.storage.JoinPath(keyFileName(key.Address))}
- if err := ks.storage.StoreKey(a.URL, key, passphrase); err != nil {
+ a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.storage.JoinPath(keyFileName(key.Address))}}
+ if err := ks.storage.StoreKey(a.URL.Path, key, passphrase); err != nil {
return accounts.Account{}, err
}
ks.cache.add(a)
@@ -468,7 +470,7 @@ func (ks *KeyStore) Update(a accounts.Account, passphrase, newPassphrase string)
if err != nil {
return err
}
- return ks.storage.StoreKey(a.URL, key, newPassphrase)
+ return ks.storage.StoreKey(a.URL.Path, key, newPassphrase)
}
// ImportPreSaleKey decrypts the given Ethereum presale wallet and stores
diff --git a/accounts/keystore/keystore_plain_test.go b/accounts/keystore/keystore_plain_test.go
index dcb2ab901..8c0eb52ea 100644
--- a/accounts/keystore/keystore_plain_test.go
+++ b/accounts/keystore/keystore_plain_test.go
@@ -52,7 +52,7 @@ func TestKeyStorePlain(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- k2, err := ks.GetKey(k1.Address, account.URL, pass)
+ k2, err := ks.GetKey(k1.Address, account.URL.Path, pass)
if err != nil {
t.Fatal(err)
}
@@ -73,7 +73,7 @@ func TestKeyStorePassphrase(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- k2, err := ks.GetKey(k1.Address, account.URL, pass)
+ k2, err := ks.GetKey(k1.Address, account.URL.Path, pass)
if err != nil {
t.Fatal(err)
}
@@ -94,7 +94,7 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- if _, err = ks.GetKey(k1.Address, account.URL, "bar"); err != ErrDecrypt {
+ if _, err = ks.GetKey(k1.Address, account.URL.Path, "bar"); err != ErrDecrypt {
t.Fatalf("wrong error for invalid passphrase\ngot %q\nwant %q", err, ErrDecrypt)
}
}
@@ -115,7 +115,7 @@ func TestImportPreSaleKey(t *testing.T) {
if account.Address != common.HexToAddress("d4584b5f6229b7be90727b0fc8c6b91bb427821f") {
t.Errorf("imported account has wrong address %x", account.Address)
}
- if !strings.HasPrefix(account.URL, dir) {
+ if !strings.HasPrefix(account.URL.Path, dir) {
t.Errorf("imported account file not in keystore directory: %q", account.URL)
}
}
diff --git a/accounts/keystore/keystore_test.go b/accounts/keystore/keystore_test.go
index 6b7170a2f..1f1935be6 100644
--- a/accounts/keystore/keystore_test.go
+++ b/accounts/keystore/keystore_test.go
@@ -41,10 +41,10 @@ func TestKeyStore(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- if !strings.HasPrefix(a.URL, dir) {
+ if !strings.HasPrefix(a.URL.Path, dir) {
t.Errorf("account file %s doesn't have dir prefix", a.URL)
}
- stat, err := os.Stat(a.URL)
+ stat, err := os.Stat(a.URL.Path)
if err != nil {
t.Fatalf("account file %s doesn't exist (%v)", a.URL, err)
}
@@ -60,7 +60,7 @@ func TestKeyStore(t *testing.T) {
if err := ks.Delete(a, "bar"); err != nil {
t.Errorf("Delete error: %v", err)
}
- if common.FileExist(a.URL) {
+ if common.FileExist(a.URL.Path) {
t.Errorf("account file %s should be gone after Delete", a.URL)
}
if ks.HasAddress(a.Address) {
@@ -286,7 +286,7 @@ func TestWalletNotifications(t *testing.T) {
// Randomly add and remove account and make sure events and wallets are in sync
live := make(map[common.Address]accounts.Account)
- for i := 0; i < 1024; i++ {
+ for i := 0; i < 256; i++ {
// Execute a creation or deletion and ensure event arrival
if create := len(live) == 0 || rand.Int()%4 > 0; create {
// Add a new account and ensure wallet notifications arrives
@@ -349,8 +349,6 @@ func TestWalletNotifications(t *testing.T) {
}
}
}
- // Sleep a bit to avoid same-timestamp keyfiles
- time.Sleep(10 * time.Millisecond)
}
}
diff --git a/accounts/keystore/keystore_wallet.go b/accounts/keystore/keystore_wallet.go
index d92926478..7d5507a4f 100644
--- a/accounts/keystore/keystore_wallet.go
+++ b/accounts/keystore/keystore_wallet.go
@@ -30,20 +30,21 @@ type keystoreWallet struct {
keystore *KeyStore // Keystore where the account originates from
}
-// Type implements accounts.Wallet, returning the textual type of the wallet.
-func (w *keystoreWallet) Type() string {
- return "secret-storage"
-}
-
// URL implements accounts.Wallet, returning the URL of the account within.
-func (w *keystoreWallet) URL() string {
+func (w *keystoreWallet) URL() accounts.URL {
return w.account.URL
}
// Status implements accounts.Wallet, always returning "open", since there is no
// concept of open/close for plain keystore accounts.
func (w *keystoreWallet) Status() string {
- return "Open"
+ w.keystore.mu.RLock()
+ defer w.keystore.mu.RUnlock()
+
+ if _, ok := w.keystore.unlocked[w.account.Address]; ok {
+ return "Unlocked"
+ }
+ return "Locked"
}
// Open implements accounts.Wallet, but is a noop for plain wallets since there
@@ -63,7 +64,7 @@ func (w *keystoreWallet) Accounts() []accounts.Account {
// Contains implements accounts.Wallet, returning whether a particular account is
// or is not wrapped by this wallet instance.
func (w *keystoreWallet) Contains(account accounts.Account) bool {
- return account.Address == w.account.Address && (account.URL == "" || account.URL == w.account.URL)
+ return account.Address == w.account.Address && (account.URL == (accounts.URL{}) || account.URL == w.account.URL)
}
// Derive implements accounts.Wallet, but is a noop for plain wallets since there
@@ -81,7 +82,7 @@ func (w *keystoreWallet) SignHash(account accounts.Account, hash []byte) ([]byte
if account.Address != w.account.Address {
return nil, accounts.ErrUnknownAccount
}
- if account.URL != "" && account.URL != w.account.URL {
+ if account.URL != (accounts.URL{}) && account.URL != w.account.URL {
return nil, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to sign
@@ -97,7 +98,7 @@ func (w *keystoreWallet) SignTx(account accounts.Account, tx *types.Transaction,
if account.Address != w.account.Address {
return nil, accounts.ErrUnknownAccount
}
- if account.URL != "" && account.URL != w.account.URL {
+ if account.URL != (accounts.URL{}) && account.URL != w.account.URL {
return nil, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to sign
@@ -111,7 +112,7 @@ func (w *keystoreWallet) SignHashWithPassphrase(account accounts.Account, passph
if account.Address != w.account.Address {
return nil, accounts.ErrUnknownAccount
}
- if account.URL != "" && account.URL != w.account.URL {
+ if account.URL != (accounts.URL{}) && account.URL != w.account.URL {
return nil, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to sign
@@ -125,7 +126,7 @@ func (w *keystoreWallet) SignTxWithPassphrase(account accounts.Account, passphra
if account.Address != w.account.Address {
return nil, accounts.ErrUnknownAccount
}
- if account.URL != "" && account.URL != w.account.URL {
+ if account.URL != (accounts.URL{}) && account.URL != w.account.URL {
return nil, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to sign
diff --git a/accounts/keystore/presale.go b/accounts/keystore/presale.go
index 948320e0a..5b883c45f 100644
--- a/accounts/keystore/presale.go
+++ b/accounts/keystore/presale.go
@@ -38,8 +38,8 @@ func importPreSaleKey(keyStore keyStore, keyJSON []byte, password string) (accou
return accounts.Account{}, nil, err
}
key.Id = uuid.NewRandom()
- a := accounts.Account{Address: key.Address, URL: keyStore.JoinPath(keyFileName(key.Address))}
- err = keyStore.StoreKey(a.URL, key, password)
+ a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: keyStore.JoinPath(keyFileName(key.Address))}}
+ err = keyStore.StoreKey(a.URL.Path, key, password)
return a, key, err
}