Commit 5300158
perf(multichain-account-service)!: avoid excessive state syncing (#6654)
## Explanation
### `MultichainAccountService`
- Unified wallet creation into one flow
(`createMultichainAccountWallet`) that handles import/restore/new vault.
- Builds a single `ServiceState` index in one pass and passes state
slices to wallets/groups (cuts repeated controller scans/calls).
- Simplified `init` path and removed dead `accountIdToContext` mapping.
### `MultichainAccountWallet`
- `init` now consumes a pre-sliced wallet state (entropySource → groups
→ providerName → ids) instead of querying providers.
- Emits clear events on group creation/updates; alignment orchestration
uses provider state instead of full scans.
### `MultichainAccountGroup`
- `init` registers account IDs per provider and fills reverse maps;
calls `provider.addAccounts(ids)` to keep providers in sync.
- Added `getAccountIds()` for direct access to underlying IDs.
- Improved partial‑failure reporting (aggregates provider errors by
name).
### `BaseBip44AccountProvider`
- Added `addAccounts(ids: string[])`, enabling providers to track their
own account ID lists.
- `getAccounts()` paths rely on known IDs (plural lookups) rather than
scanning the full controller list.
### `EvmAccountProvider`
- Switched from address‑based scans to ID‑based fetches
(`getAccount(s)`) for create/discover (removes $O(n)$ scans).
### Performance Analysis
```
n = total BIP-44 accounts in the AccountsController
p = number of providers (currently 4)
w = number of wallets (entropy sources)
g = total number of groups
e = number of created EVM accounts
```
When fully aligned $g = n / p$.
When accounts are not fully aligned then $g = max(f(p))$, where $f(p)$
is the number of accounts associated with a provider.
Consider two scenarios:
1. State 1 -> State 2 transition, the user has unaligned groups after
the transition.
2. Already transitioned to State 2, the service is initialized after
onboarding and every time the client is unlocked.
<ins>General formulas</ins>
For **Scenario 2**, the formulas are as follows:
_Before_ this refactor, the number of loops can be represented $n * p *
(1 + w + g)$, which with $p = 4$, becomes $n^2 + 4n(1 + w)$.
_Before_ this refactor, the number of controller calls can be
represented as $1 + w + g$, which with $p = 4$, becomes $1 + w + n/4$.
_After_ this refactor, the number of loops can be represented by $n *
p$, which with $p = 4$, becomes $4n$.
_After_ this refactor, the number of calls is just $1$.
For **Scenario 1**, the formulas are entirely dependent on the breakdown
of the number of accounts each provider has amongst the $n$ accounts,
let's consider a scenario where Solana has $n/2$, Ethereum has $n/8$,
Bitcoin has $n/4$ and Tron has $n/8$, the formulas would be as follows:
_Before_ this refactor, the number of loops in the alignment process can
be represented as $(p * g) + (n * e)$, which with $p=4$ and $g = n/2$,
becomes $2n + 3n^2/8$. Therefore the number of loops for initialization
+ alignment in this scenario with $p = 4$ and $g = n/2$, becomes
$(19/8)n^2 + (4w + 6)n$.
_Before_ this refactor, the number of controller calls in the alignment
process can be represented as $e$, which becomes $3n/8$. Therefore the
number of controller calls for initialization + alignment in this
scenario with $p = 4$, becomes $1 + w + 5n/8$.
_After_ this refactor, the number of loops in the alignment process can
be represented as $p * g$, which becomes $2n$. Therefore, the number of
loops for initialization + alignment in this scenario with $p = 4$ and
$g = n/2$, becomes $6n$.
_After_ this refactor, the number of controller calls in the alignment
process can be represented as $e$ which becomes $3n/8$. Therefore, the
number of controller calls for initialization + alignment in this
scenario with $p = 4$ and $g = n/2$, becomes $1 + 3n/8$.
In short, previous `init` performance for loops and controller calls was
quadratic and linear, respectively. After, it is linear and constant.
### Performance Charts
Below are charts that show performance (loops and controller calls) $n =
0$ -> $n = 256$ for Scenario 1 and 2 with $w = 2$, respectively:
<img width="678" height="401" alt="MisalignedLoops"
src="https://github.com/user-attachments/assets/52009899-9d8b-4c66-8db3-b76b13fffc86"
/>
<img width="678" height="401" alt="MisalignedCalls"
src="https://github.com/user-attachments/assets/b07222c7-ac86-4854-a29e-a364166bcc8f"
/>
<img width="678" height="401" alt="AlignedLoops"
src="https://github.com/user-attachments/assets/92de8ae2-fae3-4071-b3bf-9575fb9a0f1a"
/>
<img width="678" height="401" alt="AlignedCalls"
src="https://github.com/user-attachments/assets/bfe39332-edb8-4b7d-9623-ffe8e97cddf9"
/>
## References
- MetaMask/metamask-extension#38265
- MetaMask/metamask-mobile#25040
## Checklist
- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/contributing.md#updating-changelogs),
highlighting breaking changes as necessary
- [x] I've prepared draft pull requests for clients and consumer
packages to resolve any breaking changes
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Introduces a centralized `ServiceState` and ID-based provider model to
remove repeated controller scans and ad‑hoc syncing.
>
> - MultichainAccountService: builds `ServiceState` in one pass; `init`
passes state slices to wallets/groups; unified
`createMultichainAccountWallet` (import/create/restore); added
`removeMultichainAccountWallet` action; removed reverse
`accountIdToContext` and legacy sync handlers
> - MultichainAccountWallet/Group: new `init`/`update` APIs; groups
store provider→IDs, expose `getAccountIds`; alignment uses provider
`alignAccounts`, aggregates per‑provider errors; background non‑EVM
creation supported
> - Providers: new `init(ids)` and `alignAccounts` on
`BaseBip44AccountProvider`; providers track account IDs and fetch via
`AccountsController:getAccount(s)`; `AccountProviderWrapper` forwards
`init`, adds enable/disable handling
> - EVM provider: derives deterministic account IDs, fetches via
`getAccount`, reduces address scanning; discovery uses retry/timeout
helpers
> - Tests and changelog updated; BREAKING changes to provider interfaces
and service init/creation flows
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
cd0d095. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Charly Chevalier <charly.chevalier@consensys.net>1 parent cb7e817 commit 5300158
File tree
22 files changed
+1432
-1019
lines changed- packages/multichain-account-service
- src
- providers
- tests
22 files changed
+1432
-1019
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1092 | 1092 | | |
1093 | 1093 | | |
1094 | 1094 | | |
1095 | | - | |
1096 | | - | |
1097 | | - | |
1098 | 1095 | | |
1099 | 1096 | | |
1100 | 1097 | | |
1101 | 1098 | | |
1102 | | - | |
1103 | | - | |
1104 | | - | |
1105 | | - | |
1106 | | - | |
1107 | | - | |
1108 | | - | |
| 1099 | + | |
1109 | 1100 | | |
1110 | 1101 | | |
1111 | 1102 | | |
| |||
1126 | 1117 | | |
1127 | 1118 | | |
1128 | 1119 | | |
1129 | | - | |
1130 | | - | |
1131 | | - | |
1132 | | - | |
1133 | | - | |
1134 | 1120 | | |
1135 | 1121 | | |
1136 | 1122 | | |
| |||
1166 | 1152 | | |
1167 | 1153 | | |
1168 | 1154 | | |
1169 | | - | |
| 1155 | + | |
1170 | 1156 | | |
1171 | 1157 | | |
1172 | 1158 | | |
1173 | 1159 | | |
1174 | | - | |
1175 | | - | |
1176 | | - | |
1177 | 1160 | | |
1178 | 1161 | | |
1179 | | - | |
| 1162 | + | |
1180 | 1163 | | |
1181 | 1164 | | |
1182 | 1165 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
10 | 17 | | |
11 | 18 | | |
12 | 19 | | |
| |||
123 | 130 | | |
124 | 131 | | |
125 | 132 | | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
126 | 140 | | |
127 | 141 | | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
128 | 149 | | |
129 | 150 | | |
130 | 151 | | |
| |||
Lines changed: 98 additions & 20 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
4 | 5 | | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
| 11 | + | |
10 | 12 | | |
11 | 13 | | |
| 14 | + | |
12 | 15 | | |
13 | 16 | | |
14 | 17 | | |
15 | 18 | | |
16 | 19 | | |
17 | 20 | | |
18 | 21 | | |
19 | | - | |
| 22 | + | |
20 | 23 | | |
21 | 24 | | |
| 25 | + | |
22 | 26 | | |
23 | | - | |
24 | 27 | | |
25 | 28 | | |
26 | 29 | | |
| |||
45 | 48 | | |
46 | 49 | | |
47 | 50 | | |
48 | | - | |
49 | | - | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
50 | 56 | | |
51 | 57 | | |
52 | 58 | | |
| |||
64 | 70 | | |
65 | 71 | | |
66 | 72 | | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
67 | 85 | | |
68 | 86 | | |
69 | 87 | | |
| |||
88 | 106 | | |
89 | 107 | | |
90 | 108 | | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
91 | 113 | | |
92 | 114 | | |
93 | 115 | | |
| |||
160 | 182 | | |
161 | 183 | | |
162 | 184 | | |
163 | | - | |
| 185 | + | |
164 | 186 | | |
165 | 187 | | |
166 | 188 | | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
| 189 | + | |
171 | 190 | | |
172 | 191 | | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
173 | 195 | | |
174 | 196 | | |
175 | | - | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
176 | 201 | | |
177 | 202 | | |
178 | 203 | | |
179 | 204 | | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
180 | 211 | | |
181 | 212 | | |
182 | | - | |
| 213 | + | |
183 | 214 | | |
184 | | - | |
| 215 | + | |
185 | 216 | | |
186 | | - | |
| 217 | + | |
187 | 218 | | |
188 | 219 | | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
189 | 225 | | |
190 | 226 | | |
191 | | - | |
192 | | - | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
193 | 234 | | |
194 | 235 | | |
195 | | - | |
| 236 | + | |
196 | 237 | | |
197 | 238 | | |
198 | 239 | | |
199 | | - | |
| 240 | + | |
200 | 241 | | |
201 | 242 | | |
202 | 243 | | |
203 | 244 | | |
204 | 245 | | |
205 | 246 | | |
206 | 247 | | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
207 | 252 | | |
208 | 253 | | |
209 | | - | |
210 | 254 | | |
211 | 255 | | |
212 | 256 | | |
213 | 257 | | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
214 | 262 | | |
215 | | - | |
| 263 | + | |
216 | 264 | | |
217 | 265 | | |
218 | 266 | | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
219 | 297 | | |
220 | 298 | | |
221 | 299 | | |
| |||
227 | 305 | | |
228 | 306 | | |
229 | 307 | | |
230 | | - | |
| 308 | + | |
231 | 309 | | |
232 | 310 | | |
233 | 311 | | |
| |||
0 commit comments