diff --git a/.test_patterns.yml b/.test_patterns.yml index fe848d520bf0..1acb5b490070 100644 --- a/.test_patterns.yml +++ b/.test_patterns.yml @@ -238,27 +238,6 @@ tests: owners: - *saleel - # Example http://ci.aztec-labs.com/18db8adf0db50928 - # This seems to be an error in acvm wasm/js - - regex: "run_compose_test [a-z]*-[a-z]* box boxes" - error_regex: "call_indirect to a null table entry" - owners: - - *adam - - # Example http://ci.aztec-labs.com/1752518c2215134c - # This seems to be a flake in how this is set up. TODO redo boxes. - - regex: "run_compose_test [a-z]*-[a-z]* box boxes" - error_regex: "expect.locator..toBeVisible.." - owners: - - *adam - - # Example http://ci.aztec-labs.com/cd76b19670ab613f - # related to wasm proving browser flakes potentially - - regex: "run_compose_test [a-z]*-[a-z]* box boxes" - error_regex: "Out of bounds memory access (evaluating 'this.exports" - owners: - - *adam - - regex: "run_compose_test vite-[a-z]* box boxes" error_regex: "Test timeout of [0-9]+ms exceeded." owners: @@ -330,13 +309,6 @@ tests: owners: - *palla - # http://ci.aztec-labs.com/963635a09039594f - # http://ci.aztec-labs.com/d3b12131764bce18 - - regex: "boxes/scripts/run_test.sh" - error_regex: "sending signal TERM to command" - owners: - - *adam - # http://ci.aztec-labs.com/e8228a36afda93b8 # Test passed but there was an error on stopping - regex: "playground/scripts/run_test.sh" diff --git a/l1-contracts/scripts/forge_broadcast.js b/l1-contracts/scripts/forge_broadcast.js index d8df4462617a..8d0e7e69d11d 100755 --- a/l1-contracts/scripts/forge_broadcast.js +++ b/l1-contracts/scripts/forge_broadcast.js @@ -34,8 +34,6 @@ import { spawn } from "node:child_process"; import { rmSync, writeSync } from "node:fs"; -import { request as httpRequest } from "node:http"; -import { request as httpsRequest } from "node:https"; // Chain IDs for timeout selection. const MAINNET_CHAIN_ID = 1; @@ -53,6 +51,11 @@ const MAX_RETRIES = parseInt( 10, ); +if (!Number.isSafeInteger(MAX_RETRIES)) { + process.stderr.write(`MAX_RETRIES is not a valid integer.\n`); + process.exit(1); +} + // Batch size of 8 prevents forge from hanging during broadcast. // See: https://github.com/foundry-rs/foundry/issues/6796 const BATCH_SIZE = 8; @@ -86,50 +89,29 @@ function extractVerifyFlag(args) { const RPC_TIMEOUT = 10_000; -/** JSON-RPC call using Node.js built-ins. Rejects on JSON-RPC errors and timeouts. */ -function rpcCall(rpcUrl, method, params) { - return new Promise((resolve, reject) => { - const url = new URL(rpcUrl); - const body = JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }); - const reqFn = url.protocol === "https:" ? httpsRequest : httpRequest; - - const timer = setTimeout(() => { - req.destroy(); - reject(new Error(`RPC call ${method} timed out after ${RPC_TIMEOUT}ms`)); - }, RPC_TIMEOUT); - - const req = reqFn( - url, - { method: "POST", headers: { "Content-Type": "application/json" } }, - (res) => { - let data = ""; - res.on("data", (chunk) => (data += chunk)); - res.on("end", () => { - clearTimeout(timer); - try { - const parsed = JSON.parse(data); - if (parsed.error) { - reject( - new Error( - `RPC error for ${method}: ${JSON.stringify(parsed.error)}`, - ), - ); - } else { - resolve(parsed.result); - } - } catch { - reject(new Error(`Bad RPC response: ${data.slice(0, 200)}`)); - } - }); - }, - ); - req.on("error", (err) => { - clearTimeout(timer); - reject(err); - }); - req.write(body); - req.end(); +/** JSON-RPC call using fetch. Rejects on JSON-RPC errors and timeouts. */ +async function rpcCall(rpcUrl, method, params) { + const body = JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }); + const res = await fetch(rpcUrl, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body, + signal: AbortSignal.timeout(RPC_TIMEOUT), }); + if (!res.ok) { + throw new Error(`RPC HTTP ${res.status} for ${method}`); + } + const data = await res.text(); + let parsed; + try { + parsed = JSON.parse(data); + } catch { + throw new Error(`Bad RPC response for ${method}: ${data.slice(0, 200)}`); + } + if (parsed.error) { + throw new Error(`RPC error for ${method}: ${JSON.stringify(parsed.error)}`); + } + return parsed.result; } /** Detect if the RPC endpoint is an anvil dev node via web3_clientVersion. */ @@ -205,6 +187,11 @@ const TIMEOUT = process.env.FORGE_BROADCAST_TIMEOUT ? parseInt(process.env.FORGE_BROADCAST_TIMEOUT, 10) : getDefaultTimeout(chainId); +if (!Number.isSafeInteger(TIMEOUT)) { + process.stderr.write(`FORGE_BROADCAST_TIMEOUT is not a valid integer.\n`); + process.exit(1); +} + log( `chain_id=${chainId ?? "unknown"}, timeout=${TIMEOUT}s, max_retries=${MAX_RETRIES}, batch_size=${BATCH_SIZE}${wantsVerify ? ", verify=true (after broadcast)" : ""}`, ); @@ -301,7 +288,7 @@ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) { // - Forge computes new nonces from on-chain state // - New transactions replace any stuck ones with the same nonce // - The race condition is intermittent (~0.04%), so retries almost always succeed - rmSync("broadcast", { recursive: true, force: true }); + rmSync("broadcast", { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); log( `Attempt ${attempt + 1}/${MAX_RETRIES + 1}: retrying from scratch (anvil)...`,