ponder 0.17.12 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/esm/bin/commands/codegen.js +3 -3
- package/dist/esm/bin/commands/codegen.js.map +1 -1
- package/dist/esm/bin/commands/dev.js +3 -3
- package/dist/esm/bin/commands/dev.js.map +1 -1
- package/dist/esm/bin/commands/serve.js +3 -3
- package/dist/esm/bin/commands/serve.js.map +1 -1
- package/dist/esm/bin/commands/start.js +3 -3
- package/dist/esm/bin/commands/start.js.map +1 -1
- package/dist/esm/build/config.js +19 -20
- package/dist/esm/build/config.js.map +1 -1
- package/dist/esm/build/index.js +79 -65
- package/dist/esm/build/index.js.map +1 -1
- package/dist/esm/build/plugin.js +9 -0
- package/dist/esm/build/plugin.js.map +1 -1
- package/dist/esm/build/stacktrace.js +25 -68
- package/dist/esm/build/stacktrace.js.map +1 -1
- package/dist/esm/database/index.js +83 -67
- package/dist/esm/database/index.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/indexing/client.js +35 -23
- package/dist/esm/indexing/client.js.map +1 -1
- package/dist/esm/indexing/index.js +3 -1
- package/dist/esm/indexing/index.js.map +1 -1
- package/dist/esm/rpc/actions.js +143 -67
- package/dist/esm/rpc/actions.js.map +1 -1
- package/dist/esm/runtime/events.js +33 -19
- package/dist/esm/runtime/events.js.map +1 -1
- package/dist/esm/runtime/filter.js +10 -9
- package/dist/esm/runtime/filter.js.map +1 -1
- package/dist/esm/runtime/fragments.js +50 -24
- package/dist/esm/runtime/fragments.js.map +1 -1
- package/dist/esm/runtime/historical.js +212 -68
- package/dist/esm/runtime/historical.js.map +1 -1
- package/dist/esm/runtime/index.js +11 -15
- package/dist/esm/runtime/index.js.map +1 -1
- package/dist/esm/runtime/isolated.js +1 -0
- package/dist/esm/runtime/isolated.js.map +1 -1
- package/dist/esm/runtime/multichain.js +1 -0
- package/dist/esm/runtime/multichain.js.map +1 -1
- package/dist/esm/runtime/omnichain.js +1 -0
- package/dist/esm/runtime/omnichain.js.map +1 -1
- package/dist/esm/runtime/realtime.js +17 -16
- package/dist/esm/runtime/realtime.js.map +1 -1
- package/dist/esm/server/index.js +8 -6
- package/dist/esm/server/index.js.map +1 -1
- package/dist/esm/sync-historical/in-memory.js +539 -0
- package/dist/esm/sync-historical/in-memory.js.map +1 -0
- package/dist/esm/sync-historical/index.js +46 -63
- package/dist/esm/sync-historical/index.js.map +1 -1
- package/dist/esm/sync-realtime/index.js +56 -83
- package/dist/esm/sync-realtime/index.js.map +1 -1
- package/dist/esm/sync-store/encode.js +1 -6
- package/dist/esm/sync-store/encode.js.map +1 -1
- package/dist/esm/sync-store/index.js +58 -62
- package/dist/esm/sync-store/index.js.map +1 -1
- package/dist/esm/sync-store/schema.js +23 -15
- package/dist/esm/sync-store/schema.js.map +1 -1
- package/dist/esm/sync-store/sql/ponder_rpc_cache_1/copy.sql +23 -0
- package/dist/esm/sync-store/sql/ponder_rpc_cache_1/create.sql +130 -0
- package/dist/esm/utils/finality.js +41 -32
- package/dist/esm/utils/finality.js.map +1 -1
- package/dist/esm/utils/pglite.js +0 -65
- package/dist/esm/utils/pglite.js.map +1 -1
- package/dist/types/bin/commands/codegen.d.ts.map +1 -1
- package/dist/types/bin/commands/dev.d.ts.map +1 -1
- package/dist/types/bin/commands/serve.d.ts.map +1 -1
- package/dist/types/bin/commands/start.d.ts.map +1 -1
- package/dist/types/build/config.d.ts.map +1 -1
- package/dist/types/build/index.d.ts.map +1 -1
- package/dist/types/build/plugin.d.ts.map +1 -1
- package/dist/types/build/stacktrace.d.ts +1 -12
- package/dist/types/build/stacktrace.d.ts.map +1 -1
- package/dist/types/config/index.d.ts +12 -2
- package/dist/types/config/index.d.ts.map +1 -1
- package/dist/types/database/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/indexing/client.d.ts.map +1 -1
- package/dist/types/internal/types.d.ts +8 -13
- package/dist/types/internal/types.d.ts.map +1 -1
- package/dist/types/rpc/actions.d.ts +30 -0
- package/dist/types/rpc/actions.d.ts.map +1 -1
- package/dist/types/runtime/events.d.ts.map +1 -1
- package/dist/types/runtime/filter.d.ts.map +1 -1
- package/dist/types/runtime/fragments.d.ts +9 -1
- package/dist/types/runtime/fragments.d.ts.map +1 -1
- package/dist/types/runtime/historical.d.ts +18 -1
- package/dist/types/runtime/historical.d.ts.map +1 -1
- package/dist/types/runtime/index.d.ts +1 -0
- package/dist/types/runtime/index.d.ts.map +1 -1
- package/dist/types/runtime/isolated.d.ts.map +1 -1
- package/dist/types/runtime/multichain.d.ts.map +1 -1
- package/dist/types/runtime/omnichain.d.ts.map +1 -1
- package/dist/types/runtime/realtime.d.ts.map +1 -1
- package/dist/types/server/index.d.ts.map +1 -1
- package/dist/types/sync-historical/in-memory.d.ts +24 -0
- package/dist/types/sync-historical/in-memory.d.ts.map +1 -0
- package/dist/types/sync-historical/index.d.ts.map +1 -1
- package/dist/types/sync-realtime/index.d.ts +3 -2
- package/dist/types/sync-realtime/index.d.ts.map +1 -1
- package/dist/types/sync-store/encode.d.ts.map +1 -1
- package/dist/types/sync-store/index.d.ts +3 -3
- package/dist/types/sync-store/index.d.ts.map +1 -1
- package/dist/types/sync-store/schema.d.ts +63 -98
- package/dist/types/sync-store/schema.d.ts.map +1 -1
- package/dist/types/types/eth.d.ts +2 -8
- package/dist/types/types/eth.d.ts.map +1 -1
- package/dist/types/utils/finality.d.ts +12 -9
- package/dist/types/utils/finality.d.ts.map +1 -1
- package/dist/types/utils/pglite.d.ts +0 -18
- package/dist/types/utils/pglite.d.ts.map +1 -1
- package/package.json +5 -11
- package/src/bin/commands/codegen.ts +3 -3
- package/src/bin/commands/dev.ts +3 -3
- package/src/bin/commands/serve.ts +3 -3
- package/src/bin/commands/start.ts +3 -3
- package/src/build/config.ts +29 -28
- package/src/build/index.ts +88 -71
- package/src/build/plugin.ts +6 -0
- package/src/build/stacktrace.ts +38 -65
- package/src/config/index.ts +12 -2
- package/src/database/index.ts +132 -89
- package/src/index.ts +5 -0
- package/src/indexing/client.ts +56 -40
- package/src/indexing/index.ts +4 -1
- package/src/internal/types.ts +10 -13
- package/src/rpc/actions.ts +211 -77
- package/src/runtime/events.ts +40 -19
- package/src/runtime/filter.ts +11 -11
- package/src/runtime/fragments.ts +70 -26
- package/src/runtime/historical.ts +314 -97
- package/src/runtime/index.ts +27 -14
- package/src/runtime/isolated.ts +1 -0
- package/src/runtime/multichain.ts +1 -0
- package/src/runtime/omnichain.ts +1 -0
- package/src/runtime/realtime.ts +24 -25
- package/src/server/index.ts +14 -7
- package/src/sync-historical/in-memory.ts +834 -0
- package/src/sync-historical/index.ts +76 -120
- package/src/sync-realtime/index.ts +73 -133
- package/src/sync-store/encode.ts +1 -6
- package/src/sync-store/index.ts +90 -95
- package/src/sync-store/schema.ts +24 -27
- package/src/types/eth.ts +2 -8
- package/src/utils/finality.ts +67 -34
- package/src/utils/pglite.ts +0 -79
- package/dist/esm/sync-store/migrations.js +0 -1595
- package/dist/esm/sync-store/migrations.js.map +0 -1
- package/dist/types/sync-store/migrations.d.ts +0 -8
- package/dist/types/sync-store/migrations.d.ts.map +0 -1
- package/src/sync-store/migrations.ts +0 -1801
|
@@ -14,13 +14,13 @@ import type {
|
|
|
14
14
|
BlockFilter,
|
|
15
15
|
Chain,
|
|
16
16
|
Factory,
|
|
17
|
+
FactoryFragmentId,
|
|
17
18
|
FactoryId,
|
|
18
19
|
LogFilter,
|
|
19
20
|
SyncBlock,
|
|
20
21
|
SyncLog,
|
|
21
22
|
SyncTrace,
|
|
22
23
|
SyncTransaction,
|
|
23
|
-
SyncTransactionReceipt,
|
|
24
24
|
TraceFilter,
|
|
25
25
|
TransactionFilter,
|
|
26
26
|
TransferFilter,
|
|
@@ -28,9 +28,8 @@ import type {
|
|
|
28
28
|
import {
|
|
29
29
|
debug_traceBlockByNumber,
|
|
30
30
|
eth_getBlockByNumber,
|
|
31
|
-
eth_getBlockReceipts,
|
|
32
31
|
eth_getLogs,
|
|
33
|
-
|
|
32
|
+
eth_getTransactionReceipts,
|
|
34
33
|
validateLogsAndBlock,
|
|
35
34
|
validateReceiptsAndBlock,
|
|
36
35
|
validateTracesAndBlock,
|
|
@@ -50,8 +49,8 @@ import {
|
|
|
50
49
|
isTransferFilterMatched,
|
|
51
50
|
mergeLogFiltersToRequests,
|
|
52
51
|
} from "@/runtime/filter.js";
|
|
52
|
+
import { getFactoryFragmentId } from "@/runtime/fragments.js";
|
|
53
53
|
import type {
|
|
54
|
-
ChildAddresses,
|
|
55
54
|
IntervalWithFactory,
|
|
56
55
|
IntervalWithFilter,
|
|
57
56
|
} from "@/runtime/index.js";
|
|
@@ -100,11 +99,6 @@ type CreateHistoricalSyncParameters = {
|
|
|
100
99
|
export const createHistoricalSync = (
|
|
101
100
|
args: CreateHistoricalSyncParameters,
|
|
102
101
|
): HistoricalSync => {
|
|
103
|
-
/**
|
|
104
|
-
* Flag to fetch transaction receipts through eth_getBlockReceipts (true) or eth_getTransactionReceipt (false)
|
|
105
|
-
*/
|
|
106
|
-
let isBlockReceipts = true;
|
|
107
|
-
|
|
108
102
|
/**
|
|
109
103
|
* Data about the range passed to "eth_getLogs" share among all log
|
|
110
104
|
* filters and log factories.
|
|
@@ -222,95 +216,16 @@ export const createHistoricalSync = (
|
|
|
222
216
|
return logs;
|
|
223
217
|
};
|
|
224
218
|
|
|
225
|
-
const syncTransactionReceipts = async (
|
|
226
|
-
block: SyncBlock,
|
|
227
|
-
transactionHashes: Set<Hash>,
|
|
228
|
-
context?: Parameters<Rpc["request"]>[1],
|
|
229
|
-
): Promise<SyncTransactionReceipt[]> => {
|
|
230
|
-
if (transactionHashes.size === 0) {
|
|
231
|
-
return [];
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (isBlockReceipts === false) {
|
|
235
|
-
const transactionReceipts = await Promise.all(
|
|
236
|
-
Array.from(transactionHashes).map(async (hash) => {
|
|
237
|
-
const receipt = await eth_getTransactionReceipt(
|
|
238
|
-
args.rpc,
|
|
239
|
-
[hash],
|
|
240
|
-
context,
|
|
241
|
-
);
|
|
242
|
-
|
|
243
|
-
validateReceiptsAndBlock(
|
|
244
|
-
[receipt],
|
|
245
|
-
block,
|
|
246
|
-
{
|
|
247
|
-
method: "eth_getTransactionReceipt",
|
|
248
|
-
params: [hash],
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
method: "eth_getBlockByNumber",
|
|
252
|
-
params: [block.number, true],
|
|
253
|
-
},
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
return receipt;
|
|
257
|
-
}),
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
return transactionReceipts;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
let blockReceipts: SyncTransactionReceipt[];
|
|
264
|
-
try {
|
|
265
|
-
blockReceipts = await eth_getBlockReceipts(
|
|
266
|
-
args.rpc,
|
|
267
|
-
[block.hash],
|
|
268
|
-
context,
|
|
269
|
-
);
|
|
270
|
-
} catch (_error) {
|
|
271
|
-
const error = _error as Error;
|
|
272
|
-
args.common.logger.warn({
|
|
273
|
-
msg: "Caught eth_getBlockReceipts error, switching to eth_getTransactionReceipt method",
|
|
274
|
-
action: "fetch_block_data",
|
|
275
|
-
chain: args.chain.name,
|
|
276
|
-
chain_id: args.chain.id,
|
|
277
|
-
error,
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
isBlockReceipts = false;
|
|
281
|
-
return syncTransactionReceipts(block, transactionHashes, context);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
validateReceiptsAndBlock(
|
|
285
|
-
blockReceipts,
|
|
286
|
-
block,
|
|
287
|
-
{
|
|
288
|
-
method: "eth_getBlockReceipts",
|
|
289
|
-
params: [block.hash],
|
|
290
|
-
},
|
|
291
|
-
{
|
|
292
|
-
method: "eth_getBlockByNumber",
|
|
293
|
-
params: [block.number, true],
|
|
294
|
-
},
|
|
295
|
-
);
|
|
296
|
-
|
|
297
|
-
const transactionReceipts = blockReceipts.filter((receipt) =>
|
|
298
|
-
transactionHashes.has(receipt.transactionHash),
|
|
299
|
-
);
|
|
300
|
-
|
|
301
|
-
return transactionReceipts;
|
|
302
|
-
};
|
|
303
|
-
|
|
304
219
|
/**
|
|
305
220
|
* Fetch child addresses for `factory` within `interval`
|
|
306
221
|
*
|
|
307
|
-
* @dev
|
|
222
|
+
* @dev Fetched child addresses are added into `args.childAddresses`
|
|
308
223
|
*/
|
|
309
224
|
const syncAddressFactory = async (
|
|
310
225
|
factory: Factory,
|
|
311
226
|
interval: Interval,
|
|
312
227
|
context?: Parameters<Rpc["request"]>[1],
|
|
313
|
-
): Promise<Map<Address, number
|
|
228
|
+
): Promise<Map<FactoryFragmentId, Map<Address, number>>> => {
|
|
314
229
|
const logs = await syncLogsDynamic(
|
|
315
230
|
{
|
|
316
231
|
address: factory.address,
|
|
@@ -321,7 +236,7 @@ export const createHistoricalSync = (
|
|
|
321
236
|
context,
|
|
322
237
|
);
|
|
323
238
|
|
|
324
|
-
const childAddresses = new Map<Address, number
|
|
239
|
+
const childAddresses = new Map<FactoryFragmentId, Map<Address, number>>();
|
|
325
240
|
const factoryChildAddresses = args.childAddresses.get(factory.id)!;
|
|
326
241
|
|
|
327
242
|
const childAddressDecodeFailureIds = new Set<string>();
|
|
@@ -355,15 +270,31 @@ export const createHistoricalSync = (
|
|
|
355
270
|
throw error;
|
|
356
271
|
}
|
|
357
272
|
}
|
|
358
|
-
const
|
|
359
|
-
|
|
273
|
+
const blockNumber = hexToNumber(log.blockNumber);
|
|
274
|
+
|
|
275
|
+
// Note: Child addresses are stored per parent, so a child address that is
|
|
276
|
+
// already known from a different parent must also be stored for this parent.
|
|
277
|
+
|
|
278
|
+
const fragmentId = getFactoryFragmentId(factory, log.address);
|
|
279
|
+
if (childAddresses.has(fragmentId) === false) {
|
|
280
|
+
childAddresses.set(fragmentId, new Map());
|
|
281
|
+
}
|
|
282
|
+
const fragmentChildAddresses = childAddresses.get(fragmentId)!;
|
|
283
|
+
|
|
284
|
+
const fragmentBlockNumber = fragmentChildAddresses.get(address);
|
|
285
|
+
if (
|
|
286
|
+
fragmentBlockNumber === undefined ||
|
|
287
|
+
fragmentBlockNumber > blockNumber
|
|
288
|
+
) {
|
|
289
|
+
fragmentChildAddresses.set(address, blockNumber);
|
|
290
|
+
}
|
|
360
291
|
|
|
292
|
+
const existingBlockNumber = factoryChildAddresses.get(address);
|
|
361
293
|
if (
|
|
362
294
|
existingBlockNumber === undefined ||
|
|
363
|
-
existingBlockNumber >
|
|
295
|
+
existingBlockNumber > blockNumber
|
|
364
296
|
) {
|
|
365
|
-
|
|
366
|
-
factoryChildAddresses.set(address, newBlockNumber);
|
|
297
|
+
factoryChildAddresses.set(address, blockNumber);
|
|
367
298
|
}
|
|
368
299
|
}
|
|
369
300
|
}
|
|
@@ -390,7 +321,7 @@ export const createHistoricalSync = (
|
|
|
390
321
|
logger: args.common.logger.child({ action: "fetch_block_data" }),
|
|
391
322
|
};
|
|
392
323
|
const endClock = startClock();
|
|
393
|
-
const childAddresses
|
|
324
|
+
const childAddresses = new Map<FactoryFragmentId, Map<Address, number>>();
|
|
394
325
|
|
|
395
326
|
// Dedupe factory intervals by factory id
|
|
396
327
|
|
|
@@ -418,10 +349,33 @@ export const createHistoricalSync = (
|
|
|
418
349
|
|
|
419
350
|
await Promise.all(
|
|
420
351
|
requiredFactoryIntervals.map(async ({ factory, interval }) => {
|
|
421
|
-
|
|
422
|
-
factory
|
|
423
|
-
|
|
352
|
+
const factoryChildAddresses = await syncAddressFactory(
|
|
353
|
+
factory,
|
|
354
|
+
interval,
|
|
355
|
+
context,
|
|
424
356
|
);
|
|
357
|
+
|
|
358
|
+
// Note: Factories can share a `factory_log` fragment.
|
|
359
|
+
|
|
360
|
+
for (const [
|
|
361
|
+
fragmentId,
|
|
362
|
+
fragmentChildAddresses,
|
|
363
|
+
] of factoryChildAddresses) {
|
|
364
|
+
if (childAddresses.has(fragmentId) === false) {
|
|
365
|
+
childAddresses.set(fragmentId, fragmentChildAddresses);
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const existing = childAddresses.get(fragmentId)!;
|
|
370
|
+
for (const [address, blockNumber] of fragmentChildAddresses) {
|
|
371
|
+
if (
|
|
372
|
+
existing.has(address) === false ||
|
|
373
|
+
existing.get(address)! > blockNumber
|
|
374
|
+
) {
|
|
375
|
+
existing.set(address, blockNumber);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
425
379
|
}),
|
|
426
380
|
);
|
|
427
381
|
|
|
@@ -478,18 +432,9 @@ export const createHistoricalSync = (
|
|
|
478
432
|
["chain", "block_range"],
|
|
479
433
|
);
|
|
480
434
|
|
|
481
|
-
await
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
syncStore.insertChildAddresses(
|
|
485
|
-
{
|
|
486
|
-
factory: factoryIntervalsById.get(factoryId)!.factory,
|
|
487
|
-
childAddresses,
|
|
488
|
-
chainId: args.chain.id,
|
|
489
|
-
},
|
|
490
|
-
context,
|
|
491
|
-
),
|
|
492
|
-
),
|
|
435
|
+
await syncStore.insertChildAddresses(
|
|
436
|
+
{ childAddresses, chainId: args.chain.id },
|
|
437
|
+
context,
|
|
493
438
|
);
|
|
494
439
|
|
|
495
440
|
return logs;
|
|
@@ -839,9 +784,24 @@ export const createHistoricalSync = (
|
|
|
839
784
|
// Transaction Receipts
|
|
840
785
|
////////
|
|
841
786
|
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
|
|
787
|
+
const receiptResponses = await eth_getTransactionReceipts(
|
|
788
|
+
args.rpc,
|
|
789
|
+
{
|
|
790
|
+
blockHash: block.hash,
|
|
791
|
+
transactionHashes: requiredTransactionReceipts,
|
|
792
|
+
},
|
|
793
|
+
context,
|
|
794
|
+
);
|
|
795
|
+
const transactionReceipts = receiptResponses.flatMap(
|
|
796
|
+
({ receipts, request }) => {
|
|
797
|
+
validateReceiptsAndBlock(receipts, block, request, {
|
|
798
|
+
method: "eth_getBlockByNumber",
|
|
799
|
+
params: [block.number, true],
|
|
800
|
+
});
|
|
801
|
+
return receipts.filter((receipt) =>
|
|
802
|
+
requiredTransactionReceipts.has(receipt.transactionHash),
|
|
803
|
+
);
|
|
804
|
+
},
|
|
845
805
|
);
|
|
846
806
|
|
|
847
807
|
blockCount += 1;
|
|
@@ -879,11 +839,7 @@ export const createHistoricalSync = (
|
|
|
879
839
|
let receiptCount = 0;
|
|
880
840
|
let traceCount = 0;
|
|
881
841
|
|
|
882
|
-
|
|
883
|
-
const MAX_BLOCKS_IN_MEM = Math.max(
|
|
884
|
-
args.chain.finalityBlockCount * 2,
|
|
885
|
-
100,
|
|
886
|
-
);
|
|
842
|
+
const MAX_BLOCKS_IN_MEM = 100;
|
|
887
843
|
|
|
888
844
|
if (requiredIntervals.length > 0) {
|
|
889
845
|
const queue = createQueue({
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
Chain,
|
|
13
13
|
EventCallback,
|
|
14
14
|
Factory,
|
|
15
|
+
FactoryFragmentId,
|
|
15
16
|
FactoryId,
|
|
16
17
|
Filter,
|
|
17
18
|
LightBlock,
|
|
@@ -30,9 +31,8 @@ import {
|
|
|
30
31
|
debug_traceBlockByHash,
|
|
31
32
|
eth_getBlockByHash,
|
|
32
33
|
eth_getBlockByNumber,
|
|
33
|
-
eth_getBlockReceipts,
|
|
34
34
|
eth_getLogs,
|
|
35
|
-
|
|
35
|
+
eth_getTransactionReceipts,
|
|
36
36
|
validateLogsAndBlock,
|
|
37
37
|
validateReceiptsAndBlock,
|
|
38
38
|
validateTracesAndBlock,
|
|
@@ -51,6 +51,10 @@ import {
|
|
|
51
51
|
isTransactionFilterMatched,
|
|
52
52
|
isTransferFilterMatched,
|
|
53
53
|
} from "@/runtime/filter.js";
|
|
54
|
+
import {
|
|
55
|
+
getFactoryFragmentId,
|
|
56
|
+
getFactoryFragmentIds,
|
|
57
|
+
} from "@/runtime/fragments.js";
|
|
54
58
|
import type { SyncProgress } from "@/runtime/index.js";
|
|
55
59
|
import { isAsyncExecutionChain } from "@/utils/finality.js";
|
|
56
60
|
import { createLock } from "@/utils/mutex.js";
|
|
@@ -79,7 +83,8 @@ export type BlockWithEventData = {
|
|
|
79
83
|
transactionReceipts: SyncTransactionReceipt[];
|
|
80
84
|
logs: SyncLog[];
|
|
81
85
|
traces: SyncTrace[];
|
|
82
|
-
|
|
86
|
+
/** Child addresses found in the block per `factory_log` fragment ID. */
|
|
87
|
+
childAddresses: Map<FactoryFragmentId, Set<Address>>;
|
|
83
88
|
};
|
|
84
89
|
|
|
85
90
|
export type RealtimeSyncEvent =
|
|
@@ -106,7 +111,6 @@ const MAX_QUEUED_BLOCKS = 50;
|
|
|
106
111
|
export const createRealtimeSync = (
|
|
107
112
|
args: CreateRealtimeSyncParameters,
|
|
108
113
|
): RealtimeSync => {
|
|
109
|
-
let isBlockReceipts = true;
|
|
110
114
|
let finalizedBlock: LightBlock = args.syncProgress.finalized;
|
|
111
115
|
const childAddresses = args.childAddresses;
|
|
112
116
|
/** Annotates `childAddresses` for efficient lookup by block number */
|
|
@@ -129,6 +133,7 @@ export const createRealtimeSync = (
|
|
|
129
133
|
|
|
130
134
|
const factories: Factory[] = [];
|
|
131
135
|
const factoryIds = new Set<FactoryId>();
|
|
136
|
+
const factoryFragmentIds = new Map<Factory, FactoryFragmentId[]>();
|
|
132
137
|
const logFilters: LogFilter[] = [];
|
|
133
138
|
const traceFilters: TraceFilter[] = [];
|
|
134
139
|
const transactionFilters: TransactionFilter[] = [];
|
|
@@ -167,104 +172,10 @@ export const createRealtimeSync = (
|
|
|
167
172
|
if (factoryIds.has(factory.id)) continue;
|
|
168
173
|
factoryIds.add(factory.id);
|
|
169
174
|
factories.push(factory);
|
|
175
|
+
factoryFragmentIds.set(factory, getFactoryFragmentIds(factory));
|
|
170
176
|
}
|
|
171
177
|
}
|
|
172
178
|
|
|
173
|
-
const syncTransactionReceipts = async (
|
|
174
|
-
block: SyncBlock,
|
|
175
|
-
transactionHashes: Set<Hash>,
|
|
176
|
-
ethGetBlockMethod: "eth_getBlockByHash" | "eth_getBlockByNumber",
|
|
177
|
-
context?: Parameters<Rpc["request"]>[1],
|
|
178
|
-
): Promise<SyncTransactionReceipt[]> => {
|
|
179
|
-
if (transactionHashes.size === 0) {
|
|
180
|
-
return [];
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (isBlockReceipts === false) {
|
|
184
|
-
const transactionReceipts = await Promise.all(
|
|
185
|
-
Array.from(transactionHashes).map(async (hash) => {
|
|
186
|
-
const receipt = await eth_getTransactionReceipt(
|
|
187
|
-
args.rpc,
|
|
188
|
-
[hash],
|
|
189
|
-
context,
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
validateReceiptsAndBlock(
|
|
193
|
-
[receipt],
|
|
194
|
-
block,
|
|
195
|
-
{
|
|
196
|
-
method: "eth_getTransactionReceipt",
|
|
197
|
-
params: [hash],
|
|
198
|
-
},
|
|
199
|
-
ethGetBlockMethod === "eth_getBlockByNumber"
|
|
200
|
-
? {
|
|
201
|
-
method: "eth_getBlockByNumber",
|
|
202
|
-
params: [block.number, true],
|
|
203
|
-
}
|
|
204
|
-
: {
|
|
205
|
-
method: "eth_getBlockByHash",
|
|
206
|
-
params: [block.hash, true],
|
|
207
|
-
},
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
return receipt;
|
|
211
|
-
}),
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
return transactionReceipts;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
let blockReceipts: SyncTransactionReceipt[];
|
|
218
|
-
try {
|
|
219
|
-
blockReceipts = await eth_getBlockReceipts(
|
|
220
|
-
args.rpc,
|
|
221
|
-
[block.hash],
|
|
222
|
-
context,
|
|
223
|
-
);
|
|
224
|
-
} catch (_error) {
|
|
225
|
-
const error = _error as Error;
|
|
226
|
-
args.common.logger.warn({
|
|
227
|
-
msg: "Caught eth_getBlockReceipts error, switching to eth_getTransactionReceipt method",
|
|
228
|
-
action: "fetch block data",
|
|
229
|
-
chain: args.chain.name,
|
|
230
|
-
chain_id: args.chain.id,
|
|
231
|
-
error,
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
isBlockReceipts = false;
|
|
235
|
-
return syncTransactionReceipts(
|
|
236
|
-
block,
|
|
237
|
-
transactionHashes,
|
|
238
|
-
ethGetBlockMethod,
|
|
239
|
-
context,
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
validateReceiptsAndBlock(
|
|
244
|
-
blockReceipts,
|
|
245
|
-
block,
|
|
246
|
-
{
|
|
247
|
-
method: "eth_getBlockReceipts",
|
|
248
|
-
params: [block.hash],
|
|
249
|
-
},
|
|
250
|
-
ethGetBlockMethod === "eth_getBlockByNumber"
|
|
251
|
-
? {
|
|
252
|
-
method: "eth_getBlockByNumber",
|
|
253
|
-
params: [block.number, true],
|
|
254
|
-
}
|
|
255
|
-
: {
|
|
256
|
-
method: "eth_getBlockByHash",
|
|
257
|
-
params: [block.hash, true],
|
|
258
|
-
},
|
|
259
|
-
);
|
|
260
|
-
|
|
261
|
-
const transactionReceipts = blockReceipts.filter((receipt) =>
|
|
262
|
-
transactionHashes.has(receipt.transactionHash),
|
|
263
|
-
);
|
|
264
|
-
|
|
265
|
-
return transactionReceipts;
|
|
266
|
-
};
|
|
267
|
-
|
|
268
179
|
const getLatestUnfinalizedBlock = () => {
|
|
269
180
|
if (unfinalizedBlocks.length === 0) {
|
|
270
181
|
return finalizedBlock;
|
|
@@ -475,14 +386,13 @@ export const createRealtimeSync = (
|
|
|
475
386
|
////////
|
|
476
387
|
|
|
477
388
|
// Record `blockChildAddresses` that contain factory child addresses
|
|
478
|
-
const blockChildAddresses = new Map
|
|
389
|
+
const blockChildAddresses: BlockWithEventData["childAddresses"] = new Map();
|
|
479
390
|
|
|
480
391
|
const childAddressDecodeFailureIds = new Set<string>();
|
|
481
392
|
let childAddressDecodeFailureCount = 0;
|
|
482
393
|
let childAddressDecodeSuccessCount = 0;
|
|
483
394
|
|
|
484
395
|
for (const factory of factories) {
|
|
485
|
-
blockChildAddresses.set(factory, new Set<Address>());
|
|
486
396
|
for (const log of logs) {
|
|
487
397
|
if (isLogFactoryMatched({ factory, log })) {
|
|
488
398
|
let address: Address;
|
|
@@ -510,7 +420,11 @@ export const createRealtimeSync = (
|
|
|
510
420
|
throw error;
|
|
511
421
|
}
|
|
512
422
|
}
|
|
513
|
-
|
|
423
|
+
const fragmentId = getFactoryFragmentId(factory, log.address);
|
|
424
|
+
if (blockChildAddresses.has(fragmentId) === false) {
|
|
425
|
+
blockChildAddresses.set(fragmentId, new Set());
|
|
426
|
+
}
|
|
427
|
+
blockChildAddresses.get(fragmentId)!.add(address);
|
|
514
428
|
}
|
|
515
429
|
}
|
|
516
430
|
}
|
|
@@ -659,12 +573,26 @@ export const createRealtimeSync = (
|
|
|
659
573
|
// Transaction Receipts
|
|
660
574
|
////////
|
|
661
575
|
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
requiredTransactionReceipts,
|
|
665
|
-
ethGetBlockMethod,
|
|
576
|
+
const receiptResponses = await eth_getTransactionReceipts(
|
|
577
|
+
args.rpc,
|
|
578
|
+
{ blockHash: block.hash, transactionHashes: requiredTransactionReceipts },
|
|
666
579
|
context,
|
|
667
580
|
);
|
|
581
|
+
const transactionReceipts = receiptResponses.flatMap(
|
|
582
|
+
({ receipts, request }) => {
|
|
583
|
+
validateReceiptsAndBlock(
|
|
584
|
+
receipts,
|
|
585
|
+
block,
|
|
586
|
+
request,
|
|
587
|
+
ethGetBlockMethod === "eth_getBlockByNumber"
|
|
588
|
+
? { method: "eth_getBlockByNumber", params: [block.number, true] }
|
|
589
|
+
: { method: "eth_getBlockByHash", params: [block.hash, true] },
|
|
590
|
+
);
|
|
591
|
+
return receipts.filter((receipt) =>
|
|
592
|
+
requiredTransactionReceipts.has(receipt.transactionHash),
|
|
593
|
+
);
|
|
594
|
+
},
|
|
595
|
+
);
|
|
668
596
|
|
|
669
597
|
let childAddressCount = 0;
|
|
670
598
|
for (const childAddresses of blockChildAddresses.values()) {
|
|
@@ -712,15 +640,17 @@ export const createRealtimeSync = (
|
|
|
712
640
|
matchedFilters: Set<Filter>;
|
|
713
641
|
} => {
|
|
714
642
|
// Update `childAddresses`
|
|
715
|
-
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
643
|
+
if (blockChildAddresses.size > 0) {
|
|
644
|
+
for (const factory of factories) {
|
|
645
|
+
const knownAddresses = childAddresses.get(factory.id)!;
|
|
646
|
+
for (const fragmentId of factoryFragmentIds.get(factory)!) {
|
|
647
|
+
const blockAddresses = blockChildAddresses.get(fragmentId);
|
|
648
|
+
if (blockAddresses === undefined) continue;
|
|
649
|
+
for (const address of blockAddresses) {
|
|
650
|
+
if (knownAddresses.has(address) === false) {
|
|
651
|
+
knownAddresses.set(address, hexToNumber(block.number));
|
|
652
|
+
}
|
|
653
|
+
}
|
|
724
654
|
}
|
|
725
655
|
}
|
|
726
656
|
}
|
|
@@ -964,15 +894,21 @@ export const createRealtimeSync = (
|
|
|
964
894
|
|
|
965
895
|
// remove reorged blocks from `childAddresses`
|
|
966
896
|
for (const block of reorgedBlocks) {
|
|
897
|
+
const blockNumber = hexToNumber(block.number);
|
|
898
|
+
const blockChildAddresses = childAddressesPerBlock.get(blockNumber)!;
|
|
967
899
|
for (const factory of factories) {
|
|
968
|
-
const
|
|
969
|
-
|
|
970
|
-
.get(
|
|
971
|
-
|
|
972
|
-
|
|
900
|
+
const knownAddresses = childAddresses.get(factory.id)!;
|
|
901
|
+
for (const fragmentId of factoryFragmentIds.get(factory)!) {
|
|
902
|
+
const blockAddresses = blockChildAddresses.get(fragmentId);
|
|
903
|
+
if (blockAddresses === undefined) continue;
|
|
904
|
+
for (const address of blockAddresses) {
|
|
905
|
+
if (knownAddresses.get(address) === blockNumber) {
|
|
906
|
+
knownAddresses.delete(address);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
973
909
|
}
|
|
974
910
|
}
|
|
975
|
-
childAddressesPerBlock.delete(
|
|
911
|
+
childAddressesPerBlock.delete(blockNumber);
|
|
976
912
|
}
|
|
977
913
|
|
|
978
914
|
return {
|
|
@@ -1156,20 +1092,24 @@ export const createRealtimeSync = (
|
|
|
1156
1092
|
blockCallback,
|
|
1157
1093
|
};
|
|
1158
1094
|
|
|
1159
|
-
//
|
|
1160
|
-
//
|
|
1161
|
-
// Essentially, there is a range the width of finalityBlockCount that is entirely
|
|
1162
|
-
// finalized.
|
|
1163
|
-
|
|
1095
|
+
// Finalize the oldest contiguous blocks that are outside the timestamp
|
|
1096
|
+
// based reorg window.
|
|
1164
1097
|
const blockMovesFinality =
|
|
1165
|
-
hexToNumber(block.
|
|
1166
|
-
|
|
1098
|
+
hexToNumber(block.timestamp) -
|
|
1099
|
+
hexToNumber(unfinalizedBlocks[0]!.timestamp) >=
|
|
1100
|
+
args.chain.reorgWindow;
|
|
1167
1101
|
if (blockMovesFinality) {
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
hexToNumber(block.
|
|
1172
|
-
|
|
1102
|
+
let pendingFinalizedBlock = unfinalizedBlocks[0]!;
|
|
1103
|
+
for (const candidate of unfinalizedBlocks) {
|
|
1104
|
+
if (
|
|
1105
|
+
hexToNumber(block.timestamp) - hexToNumber(candidate.timestamp) >=
|
|
1106
|
+
args.chain.reorgWindow
|
|
1107
|
+
) {
|
|
1108
|
+
pendingFinalizedBlock = candidate;
|
|
1109
|
+
} else {
|
|
1110
|
+
break;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1173
1113
|
|
|
1174
1114
|
args.common.logger.debug({
|
|
1175
1115
|
msg: "Removed finalized blocks from local chain",
|
package/src/sync-store/encode.ts
CHANGED
|
@@ -136,7 +136,7 @@ export const encodeTrace = ({
|
|
|
136
136
|
chainId: BigInt(chainId),
|
|
137
137
|
blockNumber: hexToBigInt(block.number),
|
|
138
138
|
transactionIndex: hexToNumber(transaction.transactionIndex),
|
|
139
|
-
|
|
139
|
+
traceAddress: trace.trace.traceAddress,
|
|
140
140
|
from: toLowerCase(trace.trace.from),
|
|
141
141
|
to: trace.trace.to ? toLowerCase(trace.trace.to) : null,
|
|
142
142
|
input: trace.trace.input,
|
|
@@ -145,9 +145,4 @@ export const encodeTrace = ({
|
|
|
145
145
|
type: trace.trace.type,
|
|
146
146
|
gas: hexToBigInt(trace.trace.gas),
|
|
147
147
|
gasUsed: hexToBigInt(trace.trace.gasUsed),
|
|
148
|
-
error: trace.trace.error ? trace.trace.error.replace(/\0/g, "") : null,
|
|
149
|
-
revertReason: trace.trace.revertReason
|
|
150
|
-
? trace.trace.revertReason.replace(/\0/g, "")
|
|
151
|
-
: null,
|
|
152
|
-
subcalls: trace.trace.subcalls,
|
|
153
148
|
});
|