diff --git a/lib/circuit_gas_meter.ts b/lib/circuit_gas_meter.ts new file mode 100644 index 00000000..6fb3d122 --- /dev/null +++ b/lib/circuit_gas_meter.ts @@ -0,0 +1,4 @@ +export function trackScriptExecutionGas(opCount: number, gasLimit = 100000): boolean { + if (opCount > gasLimit) throw new Error('Gas limit exceeded'); + return true; +} diff --git a/lib/gas_meter.ts b/lib/gas_meter.ts new file mode 100644 index 00000000..4f6b25c7 --- /dev/null +++ b/lib/gas_meter.ts @@ -0,0 +1,4 @@ +export function calculateCircuitEvalGas(opCount: number, memoryBytes: number): number { + const baseGas = 100; + return baseGas + opCount * 2 + Math.floor(memoryBytes / 1024); +} diff --git a/lib/regexExecutionGuard.ts b/lib/regexExecutionGuard.ts new file mode 100644 index 00000000..a0c25d9c --- /dev/null +++ b/lib/regexExecutionGuard.ts @@ -0,0 +1,11 @@ +/** + * tscircuit/eval - Safe Regex Execution Guard + */ +export function safeRegexTest(pattern: RegExp, input: string, timeoutMs: number = 50): boolean { + const start = Date.now(); + const res = pattern.test(input); + if (Date.now() - start > timeoutMs) { + throw new Error('Regex execution exceeded execution time budget'); + } + return res; +} diff --git a/lib/stack_guard.ts b/lib/stack_guard.ts new file mode 100644 index 00000000..5cbab06a --- /dev/null +++ b/lib/stack_guard.ts @@ -0,0 +1,5 @@ +export function checkCallStackDepth(currentDepth: number, maxDepth: number = 250): void { + if (currentDepth > maxDepth) { + throw new Error(`Maximum schematic expansion depth of ${maxDepth} exceeded`); + } +} diff --git a/lib/timeout_guard.ts b/lib/timeout_guard.ts new file mode 100644 index 00000000..a5d16cd9 --- /dev/null +++ b/lib/timeout_guard.ts @@ -0,0 +1,7 @@ +export function enforceEvalTimeout(promise: Promise, timeoutMs: number = 5000): Promise { + let timer: NodeJS.Timeout; + const timeoutPromise = new Promise((_, reject) => { + timer = setTimeout(() => reject(new Error('Circuit eval timeout exceeded')), timeoutMs); + }); + return Promise.race([promise, timeoutPromise]).finally(() => clearTimeout(timer)); +}