From 91fe0cdd4f678bb8d2c6edd3af8b9f8a00dcd7f4 Mon Sep 17 00:00:00 2001 From: Work Date: Wed, 9 Oct 2024 15:51:41 -0400 Subject: [PATCH 1/9] sync-realtime fix: checks if filtered logs/callTraces point to tx in current block --- packages/core/src/sync-realtime/index.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/core/src/sync-realtime/index.ts b/packages/core/src/sync-realtime/index.ts index 7c986f8a0..ab06e60d8 100644 --- a/packages/core/src/sync-realtime/index.ts +++ b/packages/core/src/sync-realtime/index.ts @@ -497,6 +497,13 @@ export const createRealtimeSync = ( requiredTransactions.has(hash), ); + // Validate that filtered logs/callTraces point to valid transaction in the block + if (transactions.length === requiredTransactions.size) { + throw new Error( + `Received callTrace/log in the block referencing transaction that is not in current head block '${block.hash}'`, + ); + } + //////// // Transaction Receipts //////// From 5cb87f5f7dbd5c143cb12c819954026c8aa29cbc Mon Sep 17 00:00:00 2001 From: Work Date: Wed, 9 Oct 2024 16:00:40 -0400 Subject: [PATCH 2/9] minor fix --- packages/core/src/sync-realtime/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/sync-realtime/index.ts b/packages/core/src/sync-realtime/index.ts index ab06e60d8..df0c4bf83 100644 --- a/packages/core/src/sync-realtime/index.ts +++ b/packages/core/src/sync-realtime/index.ts @@ -498,7 +498,7 @@ export const createRealtimeSync = ( ); // Validate that filtered logs/callTraces point to valid transaction in the block - if (transactions.length === requiredTransactions.size) { + if (transactions.length !== requiredTransactions.size) { throw new Error( `Received callTrace/log in the block referencing transaction that is not in current head block '${block.hash}'`, ); From e20f6bde95d98ea78a6747668f3d3acffe417973 Mon Sep 17 00:00:00 2001 From: Work Date: Wed, 9 Oct 2024 17:14:04 -0400 Subject: [PATCH 3/9] added invalid tx hashes into error for debugging --- packages/core/src/sync-realtime/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/core/src/sync-realtime/index.ts b/packages/core/src/sync-realtime/index.ts index df0c4bf83..8a983b7e2 100644 --- a/packages/core/src/sync-realtime/index.ts +++ b/packages/core/src/sync-realtime/index.ts @@ -499,8 +499,11 @@ export const createRealtimeSync = ( // Validate that filtered logs/callTraces point to valid transaction in the block if (transactions.length !== requiredTransactions.size) { + const invalidTransactionHashes = [...requiredTransactions].filter( + (hash) => !transactions.some((t) => t.hash === hash), + ); throw new Error( - `Received callTrace/log in the block referencing transaction that is not in current head block '${block.hash}'`, + `Received callTraces/logs with transaction hash(es): '${invalidTransactionHashes.join(", ")}' that is/are not in current head block '${block.hash}'`, ); } From 9093a347314117555a1d576ac9e106bcc5efbca9 Mon Sep 17 00:00:00 2001 From: Work Date: Wed, 9 Oct 2024 18:18:19 -0400 Subject: [PATCH 4/9] checks logs' blockhash, more precise tx hash validation --- packages/core/src/sync-realtime/index.ts | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/core/src/sync-realtime/index.ts b/packages/core/src/sync-realtime/index.ts index 8a983b7e2..ac9b85349 100644 --- a/packages/core/src/sync-realtime/index.ts +++ b/packages/core/src/sync-realtime/index.ts @@ -393,6 +393,14 @@ export const createRealtimeSync = ( `Detected invalid '${args.network.name}' eth_getLogs response.`, ); } + + for (const log of logs) { + if (log.blockHash !== block.hash) { + throw new Error( + `Received log with block hash '${log.blockHash}' that does not match current head block '${block.hash}'`, + ); + } + } } if ( @@ -498,10 +506,18 @@ export const createRealtimeSync = ( ); // Validate that filtered logs/callTraces point to valid transaction in the block - if (transactions.length !== requiredTransactions.size) { - const invalidTransactionHashes = [...requiredTransactions].filter( - (hash) => !transactions.some((t) => t.hash === hash), - ); + const blockTransactionsHashes = new Set( + block.transactions.map((t) => t.hash), + ); + + const invalidTransactionHashes: Hash[] = []; + for (const hash of requiredTransactions) { + if (blockTransactionsHashes.has(hash) === false) { + invalidTransactionHashes.push(hash); + } + } + + if (invalidTransactionHashes.length > 0) { throw new Error( `Received callTraces/logs with transaction hash(es): '${invalidTransactionHashes.join(", ")}' that is/are not in current head block '${block.hash}'`, ); From 244960802d0ec897e9560d3e7445ef5f7763bc4d Mon Sep 17 00:00:00 2001 From: Work Date: Wed, 9 Oct 2024 21:56:10 -0400 Subject: [PATCH 5/9] added validation for trace and log tx hashes in sync-historical --- packages/core/src/sync-historical/index.ts | 43 +++++++++++++++++++--- packages/core/src/sync-realtime/index.ts | 1 + 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/packages/core/src/sync-historical/index.ts b/packages/core/src/sync-historical/index.ts index 46c0d2685..2ead25027 100644 --- a/packages/core/src/sync-historical/index.ts +++ b/packages/core/src/sync-historical/index.ts @@ -226,7 +226,23 @@ export const createHistoricalSync = async ( logs.map((log) => syncBlock(hexToBigInt(log.blockNumber))), ); - const transactionHashes = new Set(logs.map((l) => l.transactionHash)); + // Validate that logs point to the valid transaction hash in the block + const transactionHashes = new Set( + logs.map((log, i) => { + const transactionHash = log.transactionHash; + const block = blocks[i]!; + const isValid = block.transactions.some( + (t) => t.hash === transactionHash, + ); + if (!isValid) { + throw new Error( + `Received log with transaction hash: '${transactionHash}' that is not in the block '${block.hash}'`, + ); + } + return transactionHash; + }), + ); + for (const hash of transactionHashes) { transactionsCache.add(hash); } @@ -303,9 +319,28 @@ export const createHistoricalSync = async ( if (isKilled) return; + const blocks = await Promise.all( + callTraces.map((trace) => syncBlock(hexToBigInt(trace.blockNumber))), + ); + + // Validate that traces point to the valid transaction hash in the block + const transactionHashes = callTraces.map((trace, i) => { + const transactionHash = trace.transactionHash; + const block = blocks[i]!; + const isValid = block.transactions.some( + (t) => t.hash === transactionHash, + ); + if (!isValid) { + throw new Error( + `Received trace with transaction hash: '${transactionHash}' that is not in the block '${block.hash}'`, + ); + } + return transactionHash; + }); + // Request transactionReceipts to check for reverted transactions. const transactionReceipts = await Promise.all( - dedupe(callTraces.map((t) => t.transactionHash)).map((hash) => + dedupe(transactionHashes).map((hash) => _eth_getTransactionReceipt(args.requestQueue, { hash, }), @@ -325,10 +360,6 @@ export const createHistoricalSync = async ( if (isKilled) return; - const blocks = await Promise.all( - callTraces.map((trace) => syncBlock(hexToBigInt(trace.blockNumber))), - ); - for (const { transactionHash } of callTraces) { transactionsCache.add(transactionHash); } diff --git a/packages/core/src/sync-realtime/index.ts b/packages/core/src/sync-realtime/index.ts index ac9b85349..2485971db 100644 --- a/packages/core/src/sync-realtime/index.ts +++ b/packages/core/src/sync-realtime/index.ts @@ -394,6 +394,7 @@ export const createRealtimeSync = ( ); } + // Check that logs refer to the correct block for (const log of logs) { if (log.blockHash !== block.hash) { throw new Error( From e44b7e58447f947f7d31835a426c98e9c3d1e381 Mon Sep 17 00:00:00 2001 From: Work Date: Thu, 10 Oct 2024 14:17:00 -0400 Subject: [PATCH 6/9] added validation for log and trace blockhash in sync-historical --- packages/core/src/sync-historical/index.ts | 54 ++++++++++++++-------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/packages/core/src/sync-historical/index.ts b/packages/core/src/sync-historical/index.ts index 2ead25027..c8756a3a1 100644 --- a/packages/core/src/sync-historical/index.ts +++ b/packages/core/src/sync-historical/index.ts @@ -25,7 +25,6 @@ import { _eth_getTransactionReceipt, _trace_filter, } from "@/utils/rpc.js"; -import { dedupe } from "@ponder/common"; import { getLogsRetryHelper } from "@ponder/utils"; import { type Address, @@ -226,15 +225,23 @@ export const createHistoricalSync = async ( logs.map((log) => syncBlock(hexToBigInt(log.blockNumber))), ); - // Validate that logs point to the valid transaction hash in the block + // Validate that logs point to the valid transaction hash in the block and collect them const transactionHashes = new Set( logs.map((log, i) => { const transactionHash = log.transactionHash; const block = blocks[i]!; - const isValid = block.transactions.some( + + // Validate that fetched block and trace have the same blockHash + if (block.hash !== log.blockHash) { + throw new Error( + `Received log with block hash '${log.blockHash}' that does not match fetched block '${block.hash}'`, + ); + } + + const isTransactionValid = block.transactions.some( (t) => t.hash === transactionHash, ); - if (!isValid) { + if (!isTransactionValid) { throw new Error( `Received log with transaction hash: '${transactionHash}' that is not in the block '${block.hash}'`, ); @@ -323,24 +330,35 @@ export const createHistoricalSync = async ( callTraces.map((trace) => syncBlock(hexToBigInt(trace.blockNumber))), ); - // Validate that traces point to the valid transaction hash in the block - const transactionHashes = callTraces.map((trace, i) => { - const transactionHash = trace.transactionHash; - const block = blocks[i]!; - const isValid = block.transactions.some( - (t) => t.hash === transactionHash, - ); - if (!isValid) { - throw new Error( - `Received trace with transaction hash: '${transactionHash}' that is not in the block '${block.hash}'`, + // Validate that traces point to the valid transaction hash in the block and collect them + const transactionHashes = new Set( + callTraces.map((trace, i) => { + const transactionHash = trace.transactionHash; + const block = blocks[i]!; + + // Validate that fetched block and trace have the same blockHash + if (block.hash !== trace.blockHash) { + throw new Error( + `Received trace with block hash '${trace.blockHash}' that does not match fetched block '${block.hash}'`, + ); + } + + const isTransactionValid = block.transactions.some( + (t) => t.hash === transactionHash, ); - } - return transactionHash; - }); + + if (!isTransactionValid) { + throw new Error( + `Received trace with transaction hash: '${transactionHash}' that is not in the block '${block.hash}'`, + ); + } + return transactionHash; + }), + ); // Request transactionReceipts to check for reverted transactions. const transactionReceipts = await Promise.all( - dedupe(transactionHashes).map((hash) => + [...transactionHashes].map((hash) => _eth_getTransactionReceipt(args.requestQueue, { hash, }), From 35688df8558fe422e0a2946c0dd9a5d31fd3501e Mon Sep 17 00:00:00 2001 From: Kyle Scott Date: Fri, 11 Oct 2024 11:11:29 -0400 Subject: [PATCH 7/9] nits --- .../core/src/sync-historical/index.test.ts | 11 ++ packages/core/src/sync-historical/index.ts | 155 +++++++++--------- packages/core/src/sync-realtime/index.ts | 22 +-- packages/core/src/sync/index.ts | 1 + 4 files changed, 102 insertions(+), 87 deletions(-) diff --git a/packages/core/src/sync-historical/index.test.ts b/packages/core/src/sync-historical/index.test.ts index 13411088e..e4d559be2 100644 --- a/packages/core/src/sync-historical/index.test.ts +++ b/packages/core/src/sync-historical/index.test.ts @@ -61,6 +61,7 @@ test("createHistoricalSync()", async (context) => { sources: [context.sources[0]], syncStore, requestQueue: await getRequestQueue(context.requestQueues[0]), + onFatalError: () => {}, }); expect(historicalSync).toBeDefined(); @@ -77,6 +78,7 @@ test("sync() with log filter", async (context) => { sources: [context.sources[0]], syncStore, requestQueue: await getRequestQueue(context.requestQueues[0]), + onFatalError: () => {}, }); await historicalSync.sync([0, 5]); @@ -106,6 +108,7 @@ test("sync() with log filter and transaction receipts", async (context) => { sources: [context.sources[0]], syncStore, requestQueue: await getRequestQueue(context.requestQueues[0]), + onFatalError: () => {}, }); await historicalSync.sync([0, 5]); @@ -140,6 +143,7 @@ test("sync() with block filter", async (context) => { sources: [context.sources[4]], syncStore, requestQueue: await getRequestQueue(context.requestQueues[0]), + onFatalError: () => {}, }); await historicalSync.sync([0, 5]); @@ -170,6 +174,7 @@ test("sync() with log factory", async (context) => { sources: [context.sources[1]], syncStore, requestQueue: await getRequestQueue(context.requestQueues[0]), + onFatalError: () => {}, }); await historicalSync.sync([0, 5]); @@ -197,6 +202,7 @@ test("sync() with trace filter", async (context) => { sources: [context.sources[3]], syncStore, requestQueue: await getRequestQueue(context.requestQueues[0]), + onFatalError: () => {}, }); await historicalSync.sync([0, 5]); @@ -227,6 +233,7 @@ test("sync() with many filters", async (context) => { sources: context.sources, syncStore, requestQueue: await getRequestQueue(context.requestQueues[0]), + onFatalError: () => {}, }); await historicalSync.sync([0, 5]); @@ -252,6 +259,7 @@ test("sync() with cache hit", async (context) => { sources: [context.sources[0]], syncStore, requestQueue: await getRequestQueue(context.requestQueues[0]), + onFatalError: () => {}, }); await historicalSync.sync([0, 5]); @@ -265,6 +273,7 @@ test("sync() with cache hit", async (context) => { sources: [context.sources[0]], syncStore, requestQueue: await getRequestQueue(context.requestQueues[0]), + onFatalError: () => {}, }); await historicalSync.sync([0, 5]); @@ -289,6 +298,7 @@ test("syncBlock() with cache", async (context) => { ], syncStore, requestQueue: await getRequestQueue(context.requestQueues[0]), + onFatalError: () => {}, }); const spy = vi.spyOn(context.requestQueues[0], "request"); @@ -320,6 +330,7 @@ test("syncAddress() handles many addresses", async (context) => { sources: [context.sources[1]], syncStore, requestQueue: await getRequestQueue(context.requestQueues[0]), + onFatalError: () => {}, }); await historicalSync.sync([0, 10 + 5 + 2]); diff --git a/packages/core/src/sync-historical/index.ts b/packages/core/src/sync-historical/index.ts index c8756a3a1..a04f1912a 100644 --- a/packages/core/src/sync-historical/index.ts +++ b/packages/core/src/sync-historical/index.ts @@ -51,6 +51,7 @@ type CreateHistoricalSyncParameters = { syncStore: SyncStore; network: Network; requestQueue: RequestQueue; + onFatalError: (error: Error) => void; }; export const createHistoricalSync = async ( @@ -225,31 +226,28 @@ export const createHistoricalSync = async ( logs.map((log) => syncBlock(hexToBigInt(log.blockNumber))), ); - // Validate that logs point to the valid transaction hash in the block and collect them - const transactionHashes = new Set( - logs.map((log, i) => { - const transactionHash = log.transactionHash; - const block = blocks[i]!; + // Validate that logs point to the valid transaction hash in the block + for (let i = 0; i < logs.length; i++) { + const log = logs[i]!; + const block = blocks[i]!; - // Validate that fetched block and trace have the same blockHash - if (block.hash !== log.blockHash) { - throw new Error( - `Received log with block hash '${log.blockHash}' that does not match fetched block '${block.hash}'`, - ); - } + if (block.hash !== log.blockHash) { + throw new Error( + `Detected inconsistent RPC responses. Log with block hash ${log.blockHash} does not match block ${block.hash}.`, + ); + } - const isTransactionValid = block.transactions.some( - (t) => t.hash === transactionHash, + if ( + block.transactions.find((t) => t.hash === log.transactionHash) === + undefined + ) { + throw new Error( + `Detected inconsistent RPC responses. Log with transaction hash ${log.transactionHash} not found in block ${block.hash}.`, ); - if (!isTransactionValid) { - throw new Error( - `Received log with transaction hash: '${transactionHash}' that is not in the block '${block.hash}'`, - ); - } - return transactionHash; - }), - ); + } + } + const transactionHashes = new Set(logs.map((l) => l.transactionHash)); for (const hash of transactionHashes) { transactionsCache.add(hash); } @@ -266,7 +264,7 @@ export const createHistoricalSync = async ( if (filter.includeTransactionReceipts) { const transactionReceipts = await Promise.all( - [...transactionHashes].map((hash) => + Array.from(transactionHashes).map((hash) => _eth_getTransactionReceipt(args.requestQueue, { hash }), ), ); @@ -330,35 +328,32 @@ export const createHistoricalSync = async ( callTraces.map((trace) => syncBlock(hexToBigInt(trace.blockNumber))), ); - // Validate that traces point to the valid transaction hash in the block and collect them - const transactionHashes = new Set( - callTraces.map((trace, i) => { - const transactionHash = trace.transactionHash; - const block = blocks[i]!; + const transactionHashes = new Set(callTraces.map((t) => t.transactionHash)); - // Validate that fetched block and trace have the same blockHash - if (block.hash !== trace.blockHash) { - throw new Error( - `Received trace with block hash '${trace.blockHash}' that does not match fetched block '${block.hash}'`, - ); - } + // Validate that traces point to the valid transaction hash in the block + for (let i = 0; i < callTraces.length; i++) { + const callTrace = callTraces[i]!; + const block = blocks[i]!; - const isTransactionValid = block.transactions.some( - (t) => t.hash === transactionHash, + if (block.hash !== callTrace.blockHash) { + throw new Error( + `Detected inconsistent RPC responses. Call trace with block hash ${callTrace.blockHash} does not match block ${block.hash}.`, ); + } - if (!isTransactionValid) { - throw new Error( - `Received trace with transaction hash: '${transactionHash}' that is not in the block '${block.hash}'`, - ); - } - return transactionHash; - }), - ); + if ( + block.transactions.find((t) => t.hash === callTrace.transactionHash) === + undefined + ) { + throw new Error( + `Detected inconsistent RPC responses. Call trace with transaction hash ${callTrace.transactionHash} not found in block ${block.hash}.`, + ); + } + } // Request transactionReceipts to check for reverted transactions. const transactionReceipts = await Promise.all( - [...transactionHashes].map((hash) => + Array.from(transactionHashes).map((hash) => _eth_getTransactionReceipt(args.requestQueue, { hash, }), @@ -378,8 +373,10 @@ export const createHistoricalSync = async ( if (isKilled) return; - for (const { transactionHash } of callTraces) { - transactionsCache.add(transactionHash); + for (const hash of transactionHashes) { + if (revertedTransactions.has(hash) === false) { + transactionsCache.add(hash); + } } if (isKilled) return; @@ -502,35 +499,47 @@ export const createHistoricalSync = async ( // Request last block of interval const blockPromise = syncBlock(BigInt(interval[1])); - // sync required intervals, account for chunk sizes - await Promise.all( - requiredIntervals.map(async (interval) => { - if (source.type === "contract") { - const filter = source.filter; - switch (filter.type) { - case "log": { - await syncLogFilter(filter, interval); - break; + try { + // sync required intervals, account for chunk sizes + await Promise.all( + requiredIntervals.map(async (interval) => { + if (source.type === "contract") { + const filter = source.filter; + switch (filter.type) { + case "log": { + await syncLogFilter(filter, interval); + break; + } + + case "callTrace": + await Promise.all( + getChunks({ interval, maxChunkSize: 10 }).map( + async (interval) => { + await syncTraceFilter(filter, interval); + }, + ), + ); + break; + + default: + never(filter); } - - case "callTrace": - await Promise.all( - getChunks({ interval, maxChunkSize: 10 }).map( - async (interval) => { - await syncTraceFilter(filter, interval); - }, - ), - ); - break; - - default: - never(filter); + } else { + await syncBlockFilter(source.filter, interval); } - } else { - await syncBlockFilter(source.filter, interval); - } - }), - ); + }), + ); + } catch (_error) { + const error = _error as Error; + + args.common.logger.error({ + service: "sync", + msg: `Fatal error: Unable to sync '${args.network.name}' from ${interval[0]} to ${interval[1]}.`, + error, + }); + + args.onFatalError(error); + } if (isKilled) return; diff --git a/packages/core/src/sync-realtime/index.ts b/packages/core/src/sync-realtime/index.ts index 2485971db..74c4fde37 100644 --- a/packages/core/src/sync-realtime/index.ts +++ b/packages/core/src/sync-realtime/index.ts @@ -390,7 +390,7 @@ export const createRealtimeSync = ( // Protect against RPCs returning empty logs. Known to happen near chain tip. if (block.logsBloom !== zeroLogsBloom && logs.length === 0) { throw new Error( - `Detected invalid '${args.network.name}' eth_getLogs response.`, + "Detected invalid eth_getLogs response. `block.logsBloom` is not empty but zero logs were returned.", ); } @@ -398,7 +398,7 @@ export const createRealtimeSync = ( for (const log of logs) { if (log.blockHash !== block.hash) { throw new Error( - `Received log with block hash '${log.blockHash}' that does not match current head block '${block.hash}'`, + "Detected invalid eth_getLogs response. `log.blockHash` does not match requested block hash.", ); } } @@ -430,7 +430,7 @@ export const createRealtimeSync = ( // Use the fact that any transaction produces a trace. if (block.transactions.length !== 0 && traces.length === 0) { throw new Error( - `Detected invalid '${args.network.name}' trace_block response.`, + "Detected invalid trace_block response. `block.transactions` is not empty but zero traces were returned.", ); } @@ -443,7 +443,7 @@ export const createRealtimeSync = ( for (const trace of callTraces) { if (trace.blockHash !== block.hash) { throw new Error( - `Received call trace with block hash '${trace.blockHash}' that does not match current head block '${block.hash}'`, + "Detected invalid trace_block response. `trace.blockHash` does not match requested block hash.", ); } } @@ -510,20 +510,14 @@ export const createRealtimeSync = ( const blockTransactionsHashes = new Set( block.transactions.map((t) => t.hash), ); - - const invalidTransactionHashes: Hash[] = []; - for (const hash of requiredTransactions) { + for (const hash of Array.from(requiredTransactions)) { if (blockTransactionsHashes.has(hash) === false) { - invalidTransactionHashes.push(hash); + throw new Error( + `Detected inconsistent RPC responses. Transaction with hash ${hash} is missing in \`block.transactions\`.`, + ); } } - if (invalidTransactionHashes.length > 0) { - throw new Error( - `Received callTraces/logs with transaction hash(es): '${invalidTransactionHashes.join(", ")}' that is/are not in current head block '${block.hash}'`, - ); - } - //////// // Transaction Receipts //////// diff --git a/packages/core/src/sync/index.ts b/packages/core/src/sync/index.ts index 5b9c36ad3..903e0fb81 100644 --- a/packages/core/src/sync/index.ts +++ b/packages/core/src/sync/index.ts @@ -198,6 +198,7 @@ export const createSync = async (args: CreateSyncParameters): Promise => { syncStore: args.syncStore, requestQueue, network, + onFatalError: args.onFatalError, }); const realtimeSync = createRealtimeSync({ common: args.common, From e5e295d8a7896b99d64bd0fc930a2dc2d501c102 Mon Sep 17 00:00:00 2001 From: Kyle Scott Date: Fri, 11 Oct 2024 11:12:26 -0400 Subject: [PATCH 8/9] return from historical sync error --- packages/core/src/sync-historical/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/core/src/sync-historical/index.ts b/packages/core/src/sync-historical/index.ts index a04f1912a..b5caaef76 100644 --- a/packages/core/src/sync-historical/index.ts +++ b/packages/core/src/sync-historical/index.ts @@ -539,6 +539,8 @@ export const createHistoricalSync = async ( }); args.onFatalError(error); + + return; } if (isKilled) return; From 51b8db2c5a371a2b9b2438a4d4e26591fd9fd41a Mon Sep 17 00:00:00 2001 From: Kyle Scott Date: Fri, 11 Oct 2024 13:59:08 -0400 Subject: [PATCH 9/9] chore: changeset --- .changeset/strong-bags-yawn.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/strong-bags-yawn.md diff --git a/.changeset/strong-bags-yawn.md b/.changeset/strong-bags-yawn.md new file mode 100644 index 000000000..354247bfb --- /dev/null +++ b/.changeset/strong-bags-yawn.md @@ -0,0 +1,5 @@ +--- +"@ponder/core": patch +--- + +Added validations for inconsistent RPC responses.