Skip to content

Commit 0660d0c

Browse files
authored
Fix memory leak on raw rpc call (#4505)
* Fix memory leak on raw rpc call While processing a raw rpc call an observable is removed from the wrong cache. It causes a memory leak. * Fix memory leak on raw rpc subscription, fix types Fixed similar memory leak on raw rpc subscription. Also added proper type declaration for the return value of the _memomize function to address build error.
1 parent fa1a331 commit 0660d0c

File tree

1 file changed

+19
-6
lines changed

1 file changed

+19
-6
lines changed

packages/rpc-core/src/bundle.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ interface StorageChangeSetJSON {
2424
changes: [string, string | null][];
2525
}
2626

27+
type MemoizedRpcInterfaceMethod = Memoized<RpcInterfaceMethod> & {
28+
raw: Memoized<RpcInterfaceMethod>;
29+
meta: DefinitionRpc;
30+
}
31+
2732
const l = logger('rpc-core');
2833

2934
const EMPTY_META = {
@@ -174,14 +179,14 @@ export class RpcCore {
174179
}
175180
}
176181

177-
private _memomize (creator: <T> (isScale: boolean) => (...values: unknown[]) => Observable<T>, def: DefinitionRpc): Memoized<RpcInterfaceMethod> {
182+
private _memomize (creator: <T> (isScale: boolean) => (...values: unknown[]) => Observable<T>, def: DefinitionRpc): MemoizedRpcInterfaceMethod {
178183
const memoOpts = { getInstanceId: () => this.#instanceId };
179184
const memoized = memoize(creator(true) as RpcInterfaceMethod, memoOpts);
180185

181186
memoized.raw = memoize(creator(false), memoOpts);
182187
memoized.meta = def;
183188

184-
return memoized;
189+
return memoized as MemoizedRpcInterfaceMethod;
185190
}
186191

187192
private _formatResult <T> (isScale: boolean, registry: Registry, blockHash: string | Uint8Array | null | undefined, method: string, def: DefinitionRpc, params: Codec[], result: unknown): T {
@@ -193,7 +198,7 @@ export class RpcCore {
193198
private _createMethodSend (section: string, method: string, def: DefinitionRpc): RpcInterfaceMethod {
194199
const rpcName = def.endpoint || `${section}_${method}`;
195200
const hashIndex = def.params.findIndex(({ isHistoric }) => isHistoric);
196-
let memoized: null | Memoized<RpcInterfaceMethod> = null;
201+
let memoized: null | MemoizedRpcInterfaceMethod = null;
197202

198203
// execute the RPC call, doing a registry swap for historic as applicable
199204
const callWithRegistry = async <T> (isScale: boolean, values: unknown[]): Promise<T> => {
@@ -229,7 +234,11 @@ export class RpcCore {
229234

230235
return (): void => {
231236
// delete old results from cache
232-
memoized?.unmemoize(...values);
237+
if (isScale) {
238+
memoized?.unmemoize(...values);
239+
} else {
240+
memoized?.raw.unmemoize(...values);
241+
}
233242
};
234243
}).pipe(
235244
publishReplay(1), // create a Replay(1)
@@ -262,7 +271,7 @@ export class RpcCore {
262271
const subName = `${section}_${subMethod}`;
263272
const unsubName = `${section}_${unsubMethod}`;
264273
const subType = `${section}_${updateType}`;
265-
let memoized: null | Memoized<RpcInterfaceMethod> = null;
274+
let memoized: null | MemoizedRpcInterfaceMethod = null;
266275

267276
const creator = <T> (isScale: boolean) => (...values: unknown[]): Observable<T> => {
268277
return new Observable((observer: Observer<T>): () => void => {
@@ -302,7 +311,11 @@ export class RpcCore {
302311
// Teardown logic
303312
return (): void => {
304313
// Delete from cache, so old results don't hang around
305-
memoized?.unmemoize(...values);
314+
if (isScale) {
315+
memoized?.unmemoize(...values);
316+
} else {
317+
memoized?.raw.unmemoize(...values);
318+
}
306319

307320
// Unsubscribe from provider
308321
subscriptionPromise

0 commit comments

Comments
 (0)