@aztec/native 3.0.3 → 3.9.9-nightly.20260312

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { type LogLevel } from '@aztec/foundation/log';
1
+ import { type LogLevel, type Logger } from '@aztec/foundation/log';
2
2
  import type { MessageReceiver } from './msgpack_channel.js';
3
3
  interface NativeClassCtor {
4
4
  new (...args: unknown[]): MessageReceiver;
@@ -58,24 +58,58 @@ export interface ContractProvider {
58
58
  */
59
59
  revertCheckpoint(): Promise<void>;
60
60
  }
61
+ /**
62
+ * Cancellation token handle used to cancel C++ AVM simulation.
63
+ * The token is created via createCancellationToken() and can be cancelled via cancelSimulation().
64
+ * Pass it to avmSimulate to enable cancellation support.
65
+ */
66
+ export type CancellationToken = any;
67
+ /**
68
+ * Create a new cancellation token for C++ simulation.
69
+ * This token can be passed to avmSimulate and later cancelled via cancelSimulation().
70
+ * @returns A handle to a cancellation token
71
+ */
72
+ export declare function createCancellationToken(): CancellationToken;
73
+ /**
74
+ * Signal cancellation to a C++ simulation.
75
+ * The simulation will stop at the next opcode or before the next WorldState write.
76
+ * @param token - The cancellation token previously passed to avmSimulate
77
+ */
78
+ export declare function cancelSimulation(token: CancellationToken): void;
79
+ /**
80
+ * Maximum number of concurrent AVM simulations. Each simulation spawns a dedicated OS thread,
81
+ * so this controls resource usage. Defaults to 4. Set to 0 for unlimited.
82
+ */
83
+ export declare const AVM_MAX_CONCURRENT_SIMULATIONS: number;
61
84
  /**
62
85
  * AVM simulation function that takes serialized inputs and a contract provider.
63
86
  * The contract provider enables C++ to callback to TypeScript for contract data during simulation.
87
+ *
88
+ * Simulations run on dedicated std::threads (not the libuv thread pool), so there is no risk
89
+ * of libuv thread pool exhaustion or deadlock from C++ BlockingCall callbacks.
90
+ * Concurrency is limited by AVM_MAX_CONCURRENT_SIMULATIONS (default 4, 0 = unlimited).
91
+ *
64
92
  * @param inputs - Msgpack-serialized AvmFastSimulationInputs buffer
65
93
  * @param contractProvider - Object with callbacks for fetching contract instances and classes
66
94
  * @param worldStateHandle - Native handle to WorldState instance
67
- * @param logLevel - Log level to control C++ verbosity
95
+ * @param logLevel - Optional log level to control C++ verbosity (only used if loggerFunction is provided)
96
+ * @param logger - Optional logger object for C++ logging callbacks
97
+ * @param cancellationToken - Optional token to enable cancellation support
68
98
  * @returns Promise resolving to msgpack-serialized AvmCircuitPublicInputs buffer
69
99
  */
70
- export declare function avmSimulate(inputs: Buffer, contractProvider: ContractProvider, worldStateHandle: any, logLevel?: LogLevel): Promise<Buffer>;
100
+ export declare function avmSimulate(inputs: Buffer, contractProvider: ContractProvider, worldStateHandle: any, logLevel?: LogLevel, logger?: Logger, cancellationToken?: CancellationToken): Promise<Buffer>;
71
101
  /**
72
102
  * AVM simulation function that uses pre-collected hints from TypeScript simulation.
73
103
  * All contract data and merkle tree hints are included in the AvmCircuitInputs, so no runtime
74
104
  * callbacks to TS or WS pointer are needed.
105
+ *
106
+ * Simulations run on dedicated std::threads (not the libuv thread pool).
107
+ * Concurrency is limited by AVM_MAX_CONCURRENT_SIMULATIONS (default 4, 0 = unlimited).
108
+ *
75
109
  * @param inputs - Msgpack-serialized AvmCircuitInputs (AvmProvingInputs in C++) buffer
76
110
  * @param logLevel - Log level to control C++ verbosity
77
111
  * @returns Promise resolving to msgpack-serialized simulation results buffer
78
112
  */
79
113
  export declare function avmSimulateWithHintedDbs(inputs: Buffer, logLevel?: LogLevel): Promise<Buffer>;
80
114
  export {};
81
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF0aXZlX21vZHVsZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL25hdGl2ZV9tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLEtBQUssUUFBUSxFQUFhLE1BQU0sdUJBQXVCLENBQUM7QUFLakUsT0FBTyxLQUFLLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFNUQsVUFBVSxlQUFlO0lBQ3ZCLEtBQUssR0FBRyxJQUFJLEVBQUUsT0FBTyxFQUFFLEdBQUcsZUFBZSxDQUFDO0NBQzNDO0FBYUQsZUFBTyxNQUFNLGdCQUFnQixFQUFFLGVBQTRELENBQUM7QUFDNUYsZUFBTyxNQUFNLGVBQWUsRUFBRSxlQUEyRCxDQUFDO0FBRTFGOzs7R0FHRztBQUNILE1BQU0sV0FBVyxnQkFBZ0I7SUFDL0I7Ozs7T0FJRztJQUNILG1CQUFtQixDQUFDLE9BQU8sRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUMsQ0FBQztJQUNsRTs7OztPQUlHO0lBQ0gsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBRS9EOzs7O09BSUc7SUFDSCxZQUFZLENBQUMsc0JBQXNCLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUU1RDs7OztPQUlHO0lBQ0gscUJBQXFCLENBQUMsT0FBTyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBRXBFOzs7OztPQUtHO0lBQ0gsb0JBQW9CLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDLENBQUM7SUFFckY7Ozs7T0FJRztJQUNILGdCQUFnQixJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUVsQzs7O09BR0c7SUFDSCxnQkFBZ0IsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFbEM7OztPQUdHO0lBQ0gsZ0JBQWdCLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0NBQ25DO0FBOEJEOzs7Ozs7OztHQVFHO0FBQ0gsd0JBQXNCLFdBQVcsQ0FDL0IsTUFBTSxFQUFFLE1BQU0sRUFDZCxnQkFBZ0IsRUFBRSxnQkFBZ0IsRUFDbEMsZ0JBQWdCLEVBQUUsR0FBRyxFQUNyQixRQUFRLEdBQUUsUUFBaUIsR0FDMUIsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQU9qQjtBQUVEOzs7Ozs7O0dBT0c7QUFDSCx3QkFBc0Isd0JBQXdCLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxRQUFRLEdBQUUsUUFBaUIsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLENBTzNHIn0=
115
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF0aXZlX21vZHVsZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL25hdGl2ZV9tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLEtBQUssUUFBUSxFQUFhLEtBQUssTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFLOUUsT0FBTyxLQUFLLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFNUQsVUFBVSxlQUFlO0lBQ3ZCLEtBQUssR0FBRyxJQUFJLEVBQUUsT0FBTyxFQUFFLEdBQUcsZUFBZSxDQUFDO0NBQzNDO0FBYUQsZUFBTyxNQUFNLGdCQUFnQixFQUFFLGVBQTRELENBQUM7QUFDNUYsZUFBTyxNQUFNLGVBQWUsRUFBRSxlQUEyRCxDQUFDO0FBRTFGOzs7R0FHRztBQUNILE1BQU0sV0FBVyxnQkFBZ0I7SUFDL0I7Ozs7T0FJRztJQUNILG1CQUFtQixDQUFDLE9BQU8sRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUMsQ0FBQztJQUNsRTs7OztPQUlHO0lBQ0gsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBRS9EOzs7O09BSUc7SUFDSCxZQUFZLENBQUMsc0JBQXNCLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUU1RDs7OztPQUlHO0lBQ0gscUJBQXFCLENBQUMsT0FBTyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBRXBFOzs7OztPQUtHO0lBQ0gsb0JBQW9CLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDLENBQUM7SUFFckY7Ozs7T0FJRztJQUNILGdCQUFnQixJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUVsQzs7O09BR0c7SUFDSCxnQkFBZ0IsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFbEM7OztPQUdHO0lBQ0gsZ0JBQWdCLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0NBQ25DO0FBb0JEOzs7O0dBSUc7QUFDSCxNQUFNLE1BQU0saUJBQWlCLEdBQUcsR0FBRyxDQUFDO0FBRXBDOzs7O0dBSUc7QUFDSCx3QkFBZ0IsdUJBQXVCLElBQUksaUJBQWlCLENBRTNEO0FBRUQ7Ozs7R0FJRztBQUNILHdCQUFnQixnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsaUJBQWlCLEdBQUcsSUFBSSxDQUUvRDtBQUVEOzs7R0FHRztBQUNILGVBQU8sTUFBTSw4QkFBOEIsUUFBa0UsQ0FBQztBQWdCOUc7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBQ0gsd0JBQWdCLFdBQVcsQ0FDekIsTUFBTSxFQUFFLE1BQU0sRUFDZCxnQkFBZ0IsRUFBRSxnQkFBZ0IsRUFDbEMsZ0JBQWdCLEVBQUUsR0FBRyxFQUNyQixRQUFRLEdBQUUsUUFBaUIsRUFDM0IsTUFBTSxDQUFDLEVBQUUsTUFBTSxFQUNmLGlCQUFpQixDQUFDLEVBQUUsaUJBQWlCLEdBQ3BDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FXakI7QUFFRDs7Ozs7Ozs7Ozs7R0FXRztBQUNILHdCQUFnQix3QkFBd0IsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLFFBQVEsR0FBRSxRQUFpQixHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FFckcifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"native_module.d.ts","sourceRoot":"","sources":["../src/native_module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAAa,MAAM,uBAAuB,CAAC;AAKjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,UAAU,eAAe;IACvB,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC;CAC3C;AAaD,eAAO,MAAM,gBAAgB,EAAE,eAA4D,CAAC;AAC5F,eAAO,MAAM,eAAe,EAAE,eAA2D,CAAC;AAE1F;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClE;;;;OAIG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAE/D;;;;OAIG;IACH,YAAY,CAAC,sBAAsB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5D;;;;OAIG;IACH,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAEpE;;;;;OAKG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAErF;;;;OAIG;IACH,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAElC;;;OAGG;IACH,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAElC;;;OAGG;IACH,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC;AA8BD;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,gBAAgB,EAClC,gBAAgB,EAAE,GAAG,EACrB,QAAQ,GAAE,QAAiB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,QAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAO3G"}
1
+ {"version":3,"file":"native_module.d.ts","sourceRoot":"","sources":["../src/native_module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAAa,KAAK,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAK9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,UAAU,eAAe;IACvB,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC;CAC3C;AAaD,eAAO,MAAM,gBAAgB,EAAE,eAA4D,CAAC;AAC5F,eAAO,MAAM,eAAe,EAAE,eAA2D,CAAC;AAE1F;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClE;;;;OAIG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAE/D;;;;OAIG;IACH,YAAY,CAAC,sBAAsB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5D;;;;OAIG;IACH,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAEpE;;;;;OAKG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAErF;;;;OAIG;IACH,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAElC;;;OAGG;IACH,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAElC;;;OAGG;IACH,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC;AAoBD;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAEpC;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAE/D;AAED;;;GAGG;AACH,eAAO,MAAM,8BAA8B,QAAkE,CAAC;AAgB9G;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,gBAAgB,EAClC,gBAAgB,EAAE,GAAG,EACrB,QAAQ,GAAE,QAAiB,EAC3B,MAAM,CAAC,EAAE,MAAM,EACf,iBAAiB,CAAC,EAAE,iBAAiB,GACpC,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,QAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAErG"}
@@ -16,47 +16,67 @@ export const NativeLMDBStore = nativeModule.LMDBStore;
16
16
  // Internal native functions with numeric log level
17
17
  const nativeAvmSimulate = nativeModule.avmSimulate;
18
18
  const nativeAvmSimulateWithHintedDbs = nativeModule.avmSimulateWithHintedDbs;
19
+ const nativeCreateCancellationToken = nativeModule.createCancellationToken;
20
+ const nativeCancelSimulation = nativeModule.cancelSimulation;
19
21
  /**
20
- * Concurrency limiting for C++ AVM simulation to prevent libuv thread pool exhaustion.
21
- *
22
- * The C++ simulator uses NAPI BlockingCall to callback to TypeScript for contract data.
23
- * This blocks the libuv thread while waiting for the callback to complete. If all libuv
24
- * threads are blocked waiting for callbacks, no threads remain to service those callbacks,
25
- * causing deadlock.
26
- *
27
- * We limit concurrent simulations to UV_THREADPOOL_SIZE / 2 to ensure threads remain
28
- * available for callback processing.
29
- */ const UV_THREADPOOL_SIZE = parseInt(process.env.UV_THREADPOOL_SIZE ?? '4', 10);
30
- const MAX_CONCURRENT_AVM_SIMULATIONS = Math.max(1, Math.floor(UV_THREADPOOL_SIZE / 2));
31
- const avmSimulationSemaphore = new Semaphore(MAX_CONCURRENT_AVM_SIMULATIONS);
22
+ * Create a new cancellation token for C++ simulation.
23
+ * This token can be passed to avmSimulate and later cancelled via cancelSimulation().
24
+ * @returns A handle to a cancellation token
25
+ */ export function createCancellationToken() {
26
+ return nativeCreateCancellationToken();
27
+ }
28
+ /**
29
+ * Signal cancellation to a C++ simulation.
30
+ * The simulation will stop at the next opcode or before the next WorldState write.
31
+ * @param token - The cancellation token previously passed to avmSimulate
32
+ */ export function cancelSimulation(token) {
33
+ nativeCancelSimulation(token);
34
+ }
35
+ /**
36
+ * Maximum number of concurrent AVM simulations. Each simulation spawns a dedicated OS thread,
37
+ * so this controls resource usage. Defaults to 4. Set to 0 for unlimited.
38
+ */ export const AVM_MAX_CONCURRENT_SIMULATIONS = parseInt(process.env.AVM_MAX_CONCURRENT_SIMULATIONS ?? '4', 10);
39
+ const avmSimulationSemaphore = AVM_MAX_CONCURRENT_SIMULATIONS > 0 ? new Semaphore(AVM_MAX_CONCURRENT_SIMULATIONS) : null;
40
+ async function withAvmConcurrencyLimit(fn) {
41
+ if (!avmSimulationSemaphore) {
42
+ return fn();
43
+ }
44
+ await avmSimulationSemaphore.acquire();
45
+ try {
46
+ return await fn();
47
+ } finally{
48
+ avmSimulationSemaphore.release();
49
+ }
50
+ }
32
51
  /**
33
52
  * AVM simulation function that takes serialized inputs and a contract provider.
34
53
  * The contract provider enables C++ to callback to TypeScript for contract data during simulation.
54
+ *
55
+ * Simulations run on dedicated std::threads (not the libuv thread pool), so there is no risk
56
+ * of libuv thread pool exhaustion or deadlock from C++ BlockingCall callbacks.
57
+ * Concurrency is limited by AVM_MAX_CONCURRENT_SIMULATIONS (default 4, 0 = unlimited).
58
+ *
35
59
  * @param inputs - Msgpack-serialized AvmFastSimulationInputs buffer
36
60
  * @param contractProvider - Object with callbacks for fetching contract instances and classes
37
61
  * @param worldStateHandle - Native handle to WorldState instance
38
- * @param logLevel - Log level to control C++ verbosity
62
+ * @param logLevel - Optional log level to control C++ verbosity (only used if loggerFunction is provided)
63
+ * @param logger - Optional logger object for C++ logging callbacks
64
+ * @param cancellationToken - Optional token to enable cancellation support
39
65
  * @returns Promise resolving to msgpack-serialized AvmCircuitPublicInputs buffer
40
- */ export async function avmSimulate(inputs, contractProvider, worldStateHandle, logLevel = 'info') {
41
- await avmSimulationSemaphore.acquire();
42
- try {
43
- return await nativeAvmSimulate(inputs, contractProvider, worldStateHandle, LogLevels.indexOf(logLevel));
44
- } finally{
45
- avmSimulationSemaphore.release();
46
- }
66
+ */ export function avmSimulate(inputs, contractProvider, worldStateHandle, logLevel = 'info', logger, cancellationToken) {
67
+ return withAvmConcurrencyLimit(()=>nativeAvmSimulate(inputs, contractProvider, worldStateHandle, LogLevels.indexOf(logLevel), logger ? (level, msg)=>logger[level](msg) : null, cancellationToken));
47
68
  }
48
69
  /**
49
70
  * AVM simulation function that uses pre-collected hints from TypeScript simulation.
50
71
  * All contract data and merkle tree hints are included in the AvmCircuitInputs, so no runtime
51
72
  * callbacks to TS or WS pointer are needed.
73
+ *
74
+ * Simulations run on dedicated std::threads (not the libuv thread pool).
75
+ * Concurrency is limited by AVM_MAX_CONCURRENT_SIMULATIONS (default 4, 0 = unlimited).
76
+ *
52
77
  * @param inputs - Msgpack-serialized AvmCircuitInputs (AvmProvingInputs in C++) buffer
53
78
  * @param logLevel - Log level to control C++ verbosity
54
79
  * @returns Promise resolving to msgpack-serialized simulation results buffer
55
- */ export async function avmSimulateWithHintedDbs(inputs, logLevel = 'info') {
56
- await avmSimulationSemaphore.acquire();
57
- try {
58
- return await nativeAvmSimulateWithHintedDbs(inputs, LogLevels.indexOf(logLevel));
59
- } finally{
60
- avmSimulationSemaphore.release();
61
- }
80
+ */ export function avmSimulateWithHintedDbs(inputs, logLevel = 'info') {
81
+ return withAvmConcurrencyLimit(()=>nativeAvmSimulateWithHintedDbs(inputs, LogLevels.indexOf(logLevel)));
62
82
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/native",
3
- "version": "3.0.3",
3
+ "version": "3.9.9-nightly.20260312",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js"
@@ -15,15 +15,15 @@
15
15
  "../package.common.json"
16
16
  ],
17
17
  "dependencies": {
18
- "@aztec/bb.js": "3.0.3",
19
- "@aztec/foundation": "3.0.3",
18
+ "@aztec/bb.js": "3.9.9-nightly.20260312",
19
+ "@aztec/foundation": "3.9.9-nightly.20260312",
20
20
  "msgpackr": "^1.11.2"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@jest/globals": "^30.0.0",
24
24
  "@types/jest": "^30.0.0",
25
25
  "@types/node": "^22.15.17",
26
- "@typescript/native-preview": "7.0.0-dev.20251126.1",
26
+ "@typescript/native-preview": "7.0.0-dev.20260113.1",
27
27
  "jest": "^30.0.0",
28
28
  "ts-node": "^10.9.1",
29
29
  "typescript": "^5.3.3"
@@ -1,5 +1,5 @@
1
1
  import { findNapiBinary } from '@aztec/bb.js';
2
- import { type LogLevel, LogLevels } from '@aztec/foundation/log';
2
+ import { type LogLevel, LogLevels, type Logger } from '@aztec/foundation/log';
3
3
  import { Semaphore } from '@aztec/foundation/queue';
4
4
 
5
5
  import { createRequire } from 'module';
@@ -90,6 +90,8 @@ const nativeAvmSimulate = nativeModule.avmSimulate as (
90
90
  contractProvider: ContractProvider,
91
91
  worldStateHandle: any,
92
92
  logLevel: number,
93
+ logFunction?: any,
94
+ cancellationToken?: any,
93
95
  ) => Promise<Buffer>;
94
96
 
95
97
  const nativeAvmSimulateWithHintedDbs = nativeModule.avmSimulateWithHintedDbs as (
@@ -97,57 +99,102 @@ const nativeAvmSimulateWithHintedDbs = nativeModule.avmSimulateWithHintedDbs as
97
99
  logLevel: number,
98
100
  ) => Promise<Buffer>;
99
101
 
102
+ const nativeCreateCancellationToken = nativeModule.createCancellationToken as () => any;
103
+ const nativeCancelSimulation = nativeModule.cancelSimulation as (token: any) => void;
104
+
100
105
  /**
101
- * Concurrency limiting for C++ AVM simulation to prevent libuv thread pool exhaustion.
102
- *
103
- * The C++ simulator uses NAPI BlockingCall to callback to TypeScript for contract data.
104
- * This blocks the libuv thread while waiting for the callback to complete. If all libuv
105
- * threads are blocked waiting for callbacks, no threads remain to service those callbacks,
106
- * causing deadlock.
107
- *
108
- * We limit concurrent simulations to UV_THREADPOOL_SIZE / 2 to ensure threads remain
109
- * available for callback processing.
106
+ * Cancellation token handle used to cancel C++ AVM simulation.
107
+ * The token is created via createCancellationToken() and can be cancelled via cancelSimulation().
108
+ * Pass it to avmSimulate to enable cancellation support.
109
+ */
110
+ export type CancellationToken = any;
111
+
112
+ /**
113
+ * Create a new cancellation token for C++ simulation.
114
+ * This token can be passed to avmSimulate and later cancelled via cancelSimulation().
115
+ * @returns A handle to a cancellation token
110
116
  */
111
- const UV_THREADPOOL_SIZE = parseInt(process.env.UV_THREADPOOL_SIZE ?? '4', 10);
112
- const MAX_CONCURRENT_AVM_SIMULATIONS = Math.max(1, Math.floor(UV_THREADPOOL_SIZE / 2));
113
- const avmSimulationSemaphore = new Semaphore(MAX_CONCURRENT_AVM_SIMULATIONS);
117
+ export function createCancellationToken(): CancellationToken {
118
+ return nativeCreateCancellationToken();
119
+ }
120
+
121
+ /**
122
+ * Signal cancellation to a C++ simulation.
123
+ * The simulation will stop at the next opcode or before the next WorldState write.
124
+ * @param token - The cancellation token previously passed to avmSimulate
125
+ */
126
+ export function cancelSimulation(token: CancellationToken): void {
127
+ nativeCancelSimulation(token);
128
+ }
129
+
130
+ /**
131
+ * Maximum number of concurrent AVM simulations. Each simulation spawns a dedicated OS thread,
132
+ * so this controls resource usage. Defaults to 4. Set to 0 for unlimited.
133
+ */
134
+ export const AVM_MAX_CONCURRENT_SIMULATIONS = parseInt(process.env.AVM_MAX_CONCURRENT_SIMULATIONS ?? '4', 10);
135
+ const avmSimulationSemaphore =
136
+ AVM_MAX_CONCURRENT_SIMULATIONS > 0 ? new Semaphore(AVM_MAX_CONCURRENT_SIMULATIONS) : null;
137
+
138
+ async function withAvmConcurrencyLimit<T>(fn: () => Promise<T>): Promise<T> {
139
+ if (!avmSimulationSemaphore) {
140
+ return fn();
141
+ }
142
+ await avmSimulationSemaphore.acquire();
143
+ try {
144
+ return await fn();
145
+ } finally {
146
+ avmSimulationSemaphore.release();
147
+ }
148
+ }
114
149
 
115
150
  /**
116
151
  * AVM simulation function that takes serialized inputs and a contract provider.
117
152
  * The contract provider enables C++ to callback to TypeScript for contract data during simulation.
153
+ *
154
+ * Simulations run on dedicated std::threads (not the libuv thread pool), so there is no risk
155
+ * of libuv thread pool exhaustion or deadlock from C++ BlockingCall callbacks.
156
+ * Concurrency is limited by AVM_MAX_CONCURRENT_SIMULATIONS (default 4, 0 = unlimited).
157
+ *
118
158
  * @param inputs - Msgpack-serialized AvmFastSimulationInputs buffer
119
159
  * @param contractProvider - Object with callbacks for fetching contract instances and classes
120
160
  * @param worldStateHandle - Native handle to WorldState instance
121
- * @param logLevel - Log level to control C++ verbosity
161
+ * @param logLevel - Optional log level to control C++ verbosity (only used if loggerFunction is provided)
162
+ * @param logger - Optional logger object for C++ logging callbacks
163
+ * @param cancellationToken - Optional token to enable cancellation support
122
164
  * @returns Promise resolving to msgpack-serialized AvmCircuitPublicInputs buffer
123
165
  */
124
- export async function avmSimulate(
166
+ export function avmSimulate(
125
167
  inputs: Buffer,
126
168
  contractProvider: ContractProvider,
127
169
  worldStateHandle: any,
128
170
  logLevel: LogLevel = 'info',
171
+ logger?: Logger,
172
+ cancellationToken?: CancellationToken,
129
173
  ): Promise<Buffer> {
130
- await avmSimulationSemaphore.acquire();
131
- try {
132
- return await nativeAvmSimulate(inputs, contractProvider, worldStateHandle, LogLevels.indexOf(logLevel));
133
- } finally {
134
- avmSimulationSemaphore.release();
135
- }
174
+ return withAvmConcurrencyLimit(() =>
175
+ nativeAvmSimulate(
176
+ inputs,
177
+ contractProvider,
178
+ worldStateHandle,
179
+ LogLevels.indexOf(logLevel),
180
+ logger ? (level: LogLevel, msg: string) => logger[level](msg) : null,
181
+ cancellationToken,
182
+ ),
183
+ );
136
184
  }
137
185
 
138
186
  /**
139
187
  * AVM simulation function that uses pre-collected hints from TypeScript simulation.
140
188
  * All contract data and merkle tree hints are included in the AvmCircuitInputs, so no runtime
141
189
  * callbacks to TS or WS pointer are needed.
190
+ *
191
+ * Simulations run on dedicated std::threads (not the libuv thread pool).
192
+ * Concurrency is limited by AVM_MAX_CONCURRENT_SIMULATIONS (default 4, 0 = unlimited).
193
+ *
142
194
  * @param inputs - Msgpack-serialized AvmCircuitInputs (AvmProvingInputs in C++) buffer
143
195
  * @param logLevel - Log level to control C++ verbosity
144
196
  * @returns Promise resolving to msgpack-serialized simulation results buffer
145
197
  */
146
- export async function avmSimulateWithHintedDbs(inputs: Buffer, logLevel: LogLevel = 'info'): Promise<Buffer> {
147
- await avmSimulationSemaphore.acquire();
148
- try {
149
- return await nativeAvmSimulateWithHintedDbs(inputs, LogLevels.indexOf(logLevel));
150
- } finally {
151
- avmSimulationSemaphore.release();
152
- }
198
+ export function avmSimulateWithHintedDbs(inputs: Buffer, logLevel: LogLevel = 'info'): Promise<Buffer> {
199
+ return withAvmConcurrencyLimit(() => nativeAvmSimulateWithHintedDbs(inputs, LogLevels.indexOf(logLevel)));
153
200
  }