@@ -66,7 +66,7 @@ type accountCache struct {
66
66
keydir string
67
67
watcher * watcher
68
68
mu sync.Mutex
69
- all []accounts.Account
69
+ byURL map [accounts. URL ] []accounts.Account
70
70
byAddr map [common.Address ][]accounts.Account
71
71
throttle * time.Timer
72
72
notify chan struct {}
@@ -76,6 +76,7 @@ type accountCache struct {
76
76
func newAccountCache (keydir string ) (* accountCache , chan struct {}) {
77
77
ac := & accountCache {
78
78
keydir : keydir ,
79
+ byURL : make (map [accounts.URL ][]accounts.Account ),
79
80
byAddr : make (map [common.Address ][]accounts.Account ),
80
81
notify : make (chan struct {}, 1 ),
81
82
fileC : fileCache {all : mapset .NewThreadUnsafeSet [string ]()},
@@ -88,8 +89,11 @@ func (ac *accountCache) accounts() []accounts.Account {
88
89
ac .maybeReload ()
89
90
ac .mu .Lock ()
90
91
defer ac .mu .Unlock ()
91
- cpy := make ([]accounts.Account , len (ac .all ))
92
- copy (cpy , ac .all )
92
+ cpy := make ([]accounts.Account , 0 , len (ac .byURL ))
93
+ for _ , accs := range ac .byURL {
94
+ cpy = append (cpy , accs ... )
95
+ }
96
+ sort .SliceStable (cpy , func (i , j int ) bool { return cpy [i ].URL .Cmp (cpy [j ].URL ) < 0 })
93
97
return cpy
94
98
}
95
99
@@ -104,14 +108,11 @@ func (ac *accountCache) add(newAccount accounts.Account) {
104
108
ac .mu .Lock ()
105
109
defer ac .mu .Unlock ()
106
110
107
- i := sort .Search (len (ac .all ), func (i int ) bool { return ac .all [i ].URL .Cmp (newAccount .URL ) >= 0 })
108
- if i < len (ac .all ) && ac .all [i ] == newAccount {
111
+ if accs , ok := ac .byURL [newAccount .URL ]; ok && slices .Contains (accs , newAccount ) {
109
112
return
110
113
}
111
114
// newAccount is not in the cache.
112
- ac .all = append (ac .all , accounts.Account {})
113
- copy (ac .all [i + 1 :], ac .all [i :])
114
- ac .all [i ] = newAccount
115
+ ac .byURL [newAccount .URL ] = append (ac .byURL [newAccount .URL ], newAccount )
115
116
ac .byAddr [newAccount .Address ] = append (ac .byAddr [newAccount .Address ], newAccount )
116
117
}
117
118
@@ -120,7 +121,12 @@ func (ac *accountCache) delete(removed accounts.Account) {
120
121
ac .mu .Lock ()
121
122
defer ac .mu .Unlock ()
122
123
123
- ac .all = removeAccount (ac .all , removed )
124
+ if bu := removeAccount (ac .byURL [removed .URL ], removed ); len (bu ) == 0 {
125
+ delete (ac .byURL , removed .URL )
126
+ } else {
127
+ ac .byURL [removed .URL ] = bu
128
+ }
129
+
124
130
if ba := removeAccount (ac .byAddr [removed .Address ], removed ); len (ba ) == 0 {
125
131
delete (ac .byAddr , removed .Address )
126
132
} else {
@@ -132,11 +138,14 @@ func (ac *accountCache) delete(removed accounts.Account) {
132
138
func (ac * accountCache ) deleteByFile (path string ) {
133
139
ac .mu .Lock ()
134
140
defer ac .mu .Unlock ()
135
- i := sort .Search (len (ac .all ), func (i int ) bool { return ac .all [i ].URL .Path >= path })
136
-
137
- if i < len (ac .all ) && ac .all [i ].URL .Path == path {
138
- removed := ac .all [i ]
139
- ac .all = append (ac .all [:i ], ac .all [i + 1 :]... )
141
+ url := accounts.URL {Scheme : KeyStoreScheme , Path : path }
142
+ if accs , ok := ac .byURL [url ]; ok {
143
+ removed := accs [0 ]
144
+ if len (accs ) == 1 {
145
+ delete (ac .byURL , url )
146
+ } else {
147
+ ac .byURL [url ] = accs [1 :]
148
+ }
140
149
if ba := removeAccount (ac .byAddr [removed .Address ], removed ); len (ba ) == 0 {
141
150
delete (ac .byAddr , removed .Address )
142
151
} else {
@@ -166,24 +175,34 @@ func removeAccount(slice []accounts.Account, elem accounts.Account) []accounts.A
166
175
// The exact matching rules are explained by the documentation of accounts.Account.
167
176
// Callers must hold ac.mu.
168
177
func (ac * accountCache ) find (a accounts.Account ) (accounts.Account , error ) {
169
- // Limit search to address candidates if possible.
170
- matches := ac .all
171
- if (a .Address != common.Address {}) {
172
- matches = ac .byAddr [a .Address ]
173
- }
174
178
if a .URL .Path != "" {
175
179
// If only the basename is specified, complete the path.
176
180
if ! strings .ContainsRune (a .URL .Path , filepath .Separator ) {
177
181
a .URL .Path = filepath .Join (ac .keydir , a .URL .Path )
178
182
}
179
- for i := range matches {
180
- if matches [i ].URL == a .URL {
181
- return matches [i ], nil
183
+ }
184
+ // Limit search to address candidates if possible.
185
+ var matches []accounts.Account
186
+ if (a .Address != common.Address {}) {
187
+ matches = ac .byAddr [a .Address ]
188
+ if a .URL .Path != "" {
189
+ for i := range matches {
190
+ if matches [i ].URL == a .URL {
191
+ return matches [i ], nil
192
+ }
182
193
}
183
194
}
184
- if (a .Address == common.Address {}) {
195
+ } else {
196
+ if a .URL .Path != "" {
197
+ if accs , ok := ac .byURL [a .URL ]; ok {
198
+ return accs [0 ], nil
199
+ }
185
200
return accounts.Account {}, ErrNoMatch
186
201
}
202
+ matches = make ([]accounts.Account , 0 , len (ac .byURL ))
203
+ for _ , accs := range ac .byURL {
204
+ matches = append (matches , accs ... )
205
+ }
187
206
}
188
207
switch len (matches ) {
189
208
case 1 :
@@ -193,7 +212,7 @@ func (ac *accountCache) find(a accounts.Account) (accounts.Account, error) {
193
212
default :
194
213
err := & AmbiguousAddrError {Addr : a .Address , Matches : make ([]accounts.Account , len (matches ))}
195
214
copy (err .Matches , matches )
196
- slices .SortFunc (err .Matches , byURL )
215
+ slices .SortStableFunc (err .Matches , byURL )
197
216
return accounts.Account {}, err
198
217
}
199
218
}
0 commit comments