Skip to content

Commit e15bdc3

Browse files
committed
Add mutex to getSnapState to prevent concurrent decryption
1 parent 2ad12d1 commit e15bdc3

File tree

1 file changed

+28
-20
lines changed

1 file changed

+28
-20
lines changed

packages/snaps-controllers/src/snaps/SnapController.ts

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ export type SnapRuntimeData = {
286286
* A mutex to prevent concurrent state updates.
287287
*/
288288
stateMutex: Mutex;
289+
290+
/**
291+
* A mutex to prevent concurrent state decryption.
292+
*/
293+
getStateMutex: Mutex;
289294
};
290295

291296
export type SnapError = {
@@ -2046,33 +2051,35 @@ export class SnapController extends BaseController<
20462051
*/
20472052
async getSnapState(snapId: SnapId, encrypted: boolean): Promise<Json> {
20482053
const runtime = this.#getRuntimeExpect(snapId);
2049-
const cachedState = encrypted ? runtime.state : runtime.unencryptedState;
2054+
return await runtime.getStateMutex.runExclusive(() => {
2055+
const cachedState = encrypted ? runtime.state : runtime.unencryptedState;
20502056

2051-
if (cachedState !== undefined) {
2052-
return cachedState;
2053-
}
2057+
if (cachedState !== undefined) {
2058+
return cachedState;
2059+
}
20542060

2055-
const state = encrypted
2056-
? this.state.snapStates[snapId]
2057-
: this.state.unencryptedSnapStates[snapId];
2061+
const state = encrypted
2062+
? this.state.snapStates[snapId]
2063+
: this.state.unencryptedSnapStates[snapId];
20582064

2059-
if (state === null || state === undefined) {
2060-
return null;
2061-
}
2065+
if (state === null || state === undefined) {
2066+
return null;
2067+
}
20622068

2063-
if (!encrypted) {
2064-
// For performance reasons, we do not validate that the state is JSON,
2065-
// since we control serialization.
2066-
const json = JSON.parse(state);
2067-
runtime.unencryptedState = json;
2069+
if (!encrypted) {
2070+
// For performance reasons, we do not validate that the state is JSON,
2071+
// since we control serialization.
2072+
const json = JSON.parse(state);
2073+
runtime.unencryptedState = json;
20682074

2069-
return json;
2070-
}
2075+
return json;
2076+
}
20712077

2072-
const decrypted = await this.#decryptSnapState(snapId, state);
2073-
runtime.state = decrypted;
2078+
const decrypted = await this.#decryptSnapState(snapId, state);
2079+
runtime.state = decrypted;
20742080

2075-
return decrypted;
2081+
return decrypted;
2082+
});
20762083
}
20772084

20782085
/**
@@ -3968,6 +3975,7 @@ export class SnapController extends BaseController<
39683975
interpreter,
39693976
stopping: false,
39703977
stateMutex: new Mutex(),
3978+
getStateMutex: new Mutex(),
39713979
});
39723980
}
39733981

0 commit comments

Comments
 (0)