diff --git a/.changeset/dry-cycles-film.md b/.changeset/dry-cycles-film.md new file mode 100644 index 0000000000..11f2074539 --- /dev/null +++ b/.changeset/dry-cycles-film.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/block-logs-stream": patch +--- + +Added detection and handling for proxyd rate limit and block range errors. diff --git a/packages/block-logs-stream/src/fetchLogs.ts b/packages/block-logs-stream/src/fetchLogs.ts index 57ec401e74..d6de091619 100644 --- a/packages/block-logs-stream/src/fetchLogs.ts +++ b/packages/block-logs-stream/src/fetchLogs.ts @@ -42,6 +42,25 @@ export type FetchLogsResult = { logs: GetLogsReturnType; }; +const RATE_LIMIT_ERRORS = [ + "rate limit exceeded", + // https://github.com/ethereum-optimism/optimism/blob/4fb534ab3d924ac87383e1e70ae4872340d68d9d/proxyd/backend.go#L83 + "over rate limit", + // https://github.com/ethereum-optimism/optimism/blob/4fb534ab3d924ac87383e1e70ae4872340d68d9d/proxyd/backend.go#L88 + "sender is over rate limit", +]; + +const BLOCK_RANGE_TOO_LARGE_ERRORS = [ + "block range exceeded", + // https://github.com/ethereum-optimism/optimism/blob/4fb534ab3d924ac87383e1e70ae4872340d68d9d/proxyd/backend.go#L110 + "backend response too large", + // https://github.com/ethereum-optimism/optimism/blob/4fb534ab3d924ac87383e1e70ae4872340d68d9d/proxyd/rewriter.go#L36 + "block range is too large", + // https://github.com/ethereum-optimism/optimism/blob/4fb534ab3d924ac87383e1e70ae4872340d68d9d/proxyd/backend.go#L98 + // https://github.com/ethereum-optimism/optimism/blob/4fb534ab3d924ac87383e1e70ae4872340d68d9d/proxyd/rewriter.go#L35 + "block is out of range", +]; + /** * An asynchronous generator function that fetches logs from the blockchain in a range of blocks. * @@ -79,8 +98,7 @@ export async function* fetchLogs({ debug("error getting logs:", String(error)); if (!(error instanceof Error)) throw error; - // TODO: figure out actual rate limit message for RPCs - if (error.message.includes("rate limit exceeded") && retryCount < maxRetryCount) { + if (retryCount < maxRetryCount && RATE_LIMIT_ERRORS.some((e) => error.message.includes(e))) { const seconds = 2 * retryCount; debug(`too many requests, retrying in ${seconds}s`, error); await wait(1000 * seconds); @@ -88,13 +106,12 @@ export async function* fetchLogs({ continue; } - // TODO: figure out actual block range exceeded message for RPCs - if (error.message.includes("block range exceeded")) { + if (BLOCK_RANGE_TOO_LARGE_ERRORS.some((e) => error.message.includes(e))) { blockRange /= 2n; if (blockRange <= 0n) { throw new Error("can't reduce block range any further"); } - debug("block range exceeded, trying a smaller block range", error); + debug("block range exceeded or too many logs in range, trying a smaller block range", error); // TODO: adjust maxBlockRange down if we consistently hit this for a given block range size continue; }