Skip to content
Closed
4 changes: 4 additions & 0 deletions lib/circuit_gas_meter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function trackScriptExecutionGas(opCount: number, gasLimit = 100000): boolean {
if (opCount > gasLimit) throw new Error('Gas limit exceeded');
return true;
}
4 changes: 4 additions & 0 deletions lib/gas_meter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function calculateCircuitEvalGas(opCount: number, memoryBytes: number): number {
const baseGas = 100;
return baseGas + opCount * 2 + Math.floor(memoryBytes / 1024);
}
31 changes: 31 additions & 0 deletions lib/macroCycleDetector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* tscircuit/eval - Macro Cycle Detector
*/
export function detectMacroCycles(graph: Record<string, string[]>): { hasCycle: boolean; cyclePath?: string[] } {
const visited = new Set<string>();
const recursionStack = new Set<string>();

function dfs(node: string, path: string[]): boolean {
visited.add(node);
recursionStack.add(node);

for (const neighbor of graph[node] || []) {
if (!visited.has(neighbor)) {
if (dfs(neighbor, [...path, neighbor])) return true;
} else if (recursionStack.has(neighbor)) {
return true;
}
}

recursionStack.delete(node);
return false;
}

for (const node of Object.keys(graph)) {
if (!visited.has(node)) {
if (dfs(node, [node])) return { hasCycle: true };
}
}

return { hasCycle: false };
}
4 changes: 4 additions & 0 deletions lib/rcFilterEval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* tscircuit - rc-time-constant
*/
export function calcRcCutoff(r: number, c: number): number { return 1 / (2 * Math.PI * r * c); }
11 changes: 11 additions & 0 deletions lib/regexExecutionGuard.ts
Original file line number Diff line number Diff line change
@@ -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;
}
5 changes: 5 additions & 0 deletions lib/stack_guard.ts
Original file line number Diff line number Diff line change
@@ -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`);
}
}
7 changes: 7 additions & 0 deletions lib/timeout_guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function enforceEvalTimeout<T>(promise: Promise<T>, timeoutMs: number = 5000): Promise<T> {
let timer: NodeJS.Timeout;
const timeoutPromise = new Promise<T>((_, reject) => {
timer = setTimeout(() => reject(new Error('Circuit eval timeout exceeded')), timeoutMs);
});
return Promise.race([promise, timeoutPromise]).finally(() => clearTimeout(timer));
}
4 changes: 4 additions & 0 deletions lib/voltageDividerEval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* tscircuit - resistor-divider-calc
*/
export function calcDivider(vin: number, r1: number, r2: number): number { return vin * (r2 / (r1 + r2)); }
Loading