Repository: ponder-sh/ponder
Pull request #1110 (2024-09-19 11:31:27)

retry eth_getLogs for publicnode
I was running into this error when using publicnode service:

![Screenshot-cHr4WfwW@2x](https://github.com/user-attachments/assets/df0ec215-b840-40a8-9bc0-fd13df8f40f4)

Thought it would be helpful to include it as well.

kyscott18: This is great! Thank you

Patch:
diff --git a/.changeset/tricky-tigers-grow.md b/.changeset/tricky-tigers-grow.md
new file mode 100644
index 00000000..ae09fd5e
--- /dev/null
+++ b/.changeset/tricky-tigers-grow.md
@@ -0,0 +1,5 @@
+---
+"@ponder/utils": patch
+---
+
+Added retry mechanism for publicnode.
diff --git a/packages/utils/.env.example b/packages/utils/.env.example
index b04cc012..93f1423f 100644
--- a/packages/utils/.env.example
+++ b/packages/utils/.env.example
@@ -11,4 +11,4 @@ RPC_URL_QUICKNODE_1=...
 RPC_URL_CHAINSTACK_1=...
 
 # Coinbase url
-RPC_URL_COINBASE_8453=...
\ No newline at end of file
+RPC_URL_COINBASE_8453=...
diff --git a/packages/utils/src/getLogsRetryHelper.ts b/packages/utils/src/getLogsRetryHelper.ts
index d0404675..81e2e984 100644
--- a/packages/utils/src/getLogsRetryHelper.ts
+++ b/packages/utils/src/getLogsRetryHelper.ts
@@ -338,6 +338,25 @@ export const getLogsRetryHelper = ({
     } as const;
   }
 
+  // publicnode
+  match = sError.match(/maximum block range: ([\d,.]+)/);
+  if (match !== null) {
+    const ranges = chunk({
+      params,
+      range: BigInt(match[1]!.replace(/[,.]/g, "")),
+    });
+
+    if (isRangeUnchanged(params, ranges)) {
+      return { shouldRetry: false } as const;
+    }
+
+    return {
+      shouldRetry: true,
+      ranges,
+      isSuggestedRange: true,
+    } as const;
+  }
+
   // No match found
   return {
     shouldRetry: false,


Test patch:
diff --git a/packages/utils/src/_test/publicnode.test.ts b/packages/utils/src/_test/publicnode.test.ts
new file mode 100644
index 00000000..5b76be02
--- /dev/null
+++ b/packages/utils/src/_test/publicnode.test.ts
@@ -0,0 +1,58 @@
+import { numberToHex } from "viem";
+import { expect, test } from "vitest";
+import { getLogsRetryHelper } from "../getLogsRetryHelper.js";
+import { type Params, UNI, fromBlock, getRequest } from "./utils.js";
+
+const request = getRequest("https://ethereum-rpc.publicnode.com");
+const maxBlockRange = 50_000n;
+
+test("publicnode success", async () => {
+  const logs = await request({
+    method: "eth_getLogs",
+    params: [
+      {
+        address: UNI,
+        fromBlock: numberToHex(fromBlock),
+        toBlock: numberToHex(fromBlock + maxBlockRange),
+      },
+    ],
+  });
+
+  expect(logs).toHaveLength(203);
+});
+
+test("publicnode block range", async () => {
+  const params: Params = [
+    {
+      fromBlock: numberToHex(fromBlock),
+      toBlock: numberToHex(fromBlock + maxBlockRange + 1n),
+    },
+  ];
+
+  const error = await request({
+    method: "eth_getLogs",
+    params,
+  }).catch((error) => error);
+
+  expect(JSON.stringify(error)).includes("exceed maximum block range: 50000");
+
+  const retry = getLogsRetryHelper({
+    params,
+    error: error,
+  });
+
+  expect(retry).toStrictEqual({
+    isSuggestedRange: true,
+    shouldRetry: true,
+    ranges: [
+      {
+        fromBlock: numberToHex(fromBlock),
+        toBlock: numberToHex(fromBlock + maxBlockRange),
+      },
+      {
+        fromBlock: numberToHex(fromBlock + maxBlockRange + 1n),
+        toBlock: numberToHex(fromBlock + maxBlockRange + 1n),
+      },
+    ],
+  });
+});