ponder 0.9.2 → 0.9.3
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/dist/bin/ponder.js +1933 -1606
- package/dist/bin/ponder.js.map +1 -1
- package/dist/{chunk-IFTUFVCL.js → chunk-LHCA5XFV.js} +2 -5
- package/dist/chunk-LHCA5XFV.js.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/bin/commands/codegen.ts +8 -10
- package/src/bin/commands/dev.ts +30 -42
- package/src/bin/commands/list.ts +9 -14
- package/src/bin/commands/serve.ts +26 -39
- package/src/bin/commands/start.ts +29 -42
- package/src/bin/utils/{shutdown.ts → exit.ts} +23 -37
- package/src/bin/utils/run.ts +275 -175
- package/src/bin/utils/runServer.ts +1 -5
- package/src/build/index.ts +3 -8
- package/src/build/pre.ts +3 -0
- package/src/config/index.ts +5 -2
- package/src/database/index.ts +72 -72
- package/src/drizzle/kit/index.ts +3 -3
- package/src/indexing/index.ts +0 -4
- package/src/indexing/service.ts +31 -93
- package/src/indexing-store/historical.ts +2 -4
- package/src/internal/common.ts +2 -0
- package/src/internal/errors.ts +9 -9
- package/src/internal/logger.ts +1 -1
- package/src/internal/metrics.ts +75 -103
- package/src/internal/shutdown.ts +25 -0
- package/src/internal/telemetry.ts +16 -18
- package/src/internal/types.ts +9 -1
- package/src/server/index.ts +3 -5
- package/src/sync/events.ts +4 -4
- package/src/sync/filter.ts +1 -0
- package/src/sync/index.ts +1046 -805
- package/src/sync-historical/index.ts +0 -37
- package/src/sync-realtime/index.ts +48 -48
- package/src/sync-store/encoding.ts +5 -5
- package/src/sync-store/index.ts +5 -23
- package/src/ui/index.ts +2 -11
- package/src/utils/checkpoint.ts +17 -3
- package/src/utils/chunk.ts +7 -0
- package/src/utils/generators.ts +66 -0
- package/src/utils/mutex.ts +34 -0
- package/src/utils/partition.ts +41 -0
- package/src/utils/requestQueue.ts +19 -10
- package/src/utils/zipper.ts +80 -0
- package/dist/chunk-IFTUFVCL.js.map +0 -1
|
@@ -61,7 +61,6 @@ export type HistoricalSync = {
|
|
|
61
61
|
* that is synced.
|
|
62
62
|
*/
|
|
63
63
|
sync(interval: Interval): Promise<SyncBlock | undefined>;
|
|
64
|
-
kill(): void;
|
|
65
64
|
};
|
|
66
65
|
|
|
67
66
|
type CreateHistoricalSyncParameters = {
|
|
@@ -76,7 +75,6 @@ type CreateHistoricalSyncParameters = {
|
|
|
76
75
|
export const createHistoricalSync = async (
|
|
77
76
|
args: CreateHistoricalSyncParameters,
|
|
78
77
|
): Promise<HistoricalSync> => {
|
|
79
|
-
let isKilled = false;
|
|
80
78
|
/**
|
|
81
79
|
* Flag to fetch transaction receipts through _eth_getBlockReceipts (true) or _eth_getTransactionReceipt (false)
|
|
82
80
|
*/
|
|
@@ -434,8 +432,6 @@ export const createHistoricalSync = async (
|
|
|
434
432
|
address: filter.address,
|
|
435
433
|
});
|
|
436
434
|
|
|
437
|
-
if (isKilled) return;
|
|
438
|
-
|
|
439
435
|
// Insert `logs` into the sync-store
|
|
440
436
|
await args.syncStore.insertLogs({
|
|
441
437
|
logs: logs.map((log) => ({ log })),
|
|
@@ -478,12 +474,8 @@ export const createHistoricalSync = async (
|
|
|
478
474
|
? await syncAddressFactory(filter.address, interval)
|
|
479
475
|
: filter.address;
|
|
480
476
|
|
|
481
|
-
if (isKilled) return;
|
|
482
|
-
|
|
483
477
|
const logs = await syncLogsDynamic({ filter, interval, address });
|
|
484
478
|
|
|
485
|
-
if (isKilled) return;
|
|
486
|
-
|
|
487
479
|
const blocks = await Promise.all(
|
|
488
480
|
logs.map((log) => syncBlock(hexToNumber(log.blockNumber))),
|
|
489
481
|
);
|
|
@@ -523,16 +515,12 @@ export const createHistoricalSync = async (
|
|
|
523
515
|
transactionsCache.add(hash);
|
|
524
516
|
}
|
|
525
517
|
|
|
526
|
-
if (isKilled) return;
|
|
527
|
-
|
|
528
518
|
await args.syncStore.insertLogs({
|
|
529
519
|
logs: logs.map((log, i) => ({ log, block: blocks[i]! })),
|
|
530
520
|
shouldUpdateCheckpoint: true,
|
|
531
521
|
chainId: args.network.chainId,
|
|
532
522
|
});
|
|
533
523
|
|
|
534
|
-
if (isKilled) return;
|
|
535
|
-
|
|
536
524
|
if (shouldGetTransactionReceipt(filter)) {
|
|
537
525
|
const transactionReceipts = await Promise.all(
|
|
538
526
|
Array.from(requiredBlocks).map((blockHash) => {
|
|
@@ -555,8 +543,6 @@ export const createHistoricalSync = async (
|
|
|
555
543
|
}),
|
|
556
544
|
).then((receipts) => receipts.flat());
|
|
557
545
|
|
|
558
|
-
if (isKilled) return;
|
|
559
|
-
|
|
560
546
|
await args.syncStore.insertTransactionReceipts({
|
|
561
547
|
transactionReceipts,
|
|
562
548
|
chainId: args.network.chainId,
|
|
@@ -595,14 +581,10 @@ export const createHistoricalSync = async (
|
|
|
595
581
|
)
|
|
596
582
|
: undefined;
|
|
597
583
|
|
|
598
|
-
if (isKilled) return;
|
|
599
|
-
|
|
600
584
|
const blocks = await Promise.all(
|
|
601
585
|
intervalRange(interval).map((number) => syncBlock(number)),
|
|
602
586
|
);
|
|
603
587
|
|
|
604
|
-
if (isKilled) return;
|
|
605
|
-
|
|
606
588
|
const transactionHashes: Set<Hash> = new Set();
|
|
607
589
|
const requiredBlocks: Set<SyncBlock> = new Set();
|
|
608
590
|
|
|
@@ -627,8 +609,6 @@ export const createHistoricalSync = async (
|
|
|
627
609
|
transactionsCache.add(hash);
|
|
628
610
|
}
|
|
629
611
|
|
|
630
|
-
if (isKilled) return;
|
|
631
|
-
|
|
632
612
|
const transactionReceipts = await Promise.all(
|
|
633
613
|
Array.from(requiredBlocks).map((block) => {
|
|
634
614
|
const blockTransactionHashes = new Set(
|
|
@@ -640,8 +620,6 @@ export const createHistoricalSync = async (
|
|
|
640
620
|
}),
|
|
641
621
|
).then((receipts) => receipts.flat());
|
|
642
622
|
|
|
643
|
-
if (isKilled) return;
|
|
644
|
-
|
|
645
623
|
await args.syncStore.insertTransactionReceipts({
|
|
646
624
|
transactionReceipts,
|
|
647
625
|
chainId: args.network.chainId,
|
|
@@ -715,15 +693,11 @@ export const createHistoricalSync = async (
|
|
|
715
693
|
}),
|
|
716
694
|
).then((traces) => traces.flat());
|
|
717
695
|
|
|
718
|
-
if (isKilled) return;
|
|
719
|
-
|
|
720
696
|
await args.syncStore.insertTraces({
|
|
721
697
|
traces,
|
|
722
698
|
chainId: args.network.chainId,
|
|
723
699
|
});
|
|
724
700
|
|
|
725
|
-
if (isKilled) return;
|
|
726
|
-
|
|
727
701
|
if (shouldGetTransactionReceipt(filter)) {
|
|
728
702
|
const transactionReceipts = await Promise.all(
|
|
729
703
|
Array.from(requiredBlocks).map((blockHash) => {
|
|
@@ -736,8 +710,6 @@ export const createHistoricalSync = async (
|
|
|
736
710
|
}),
|
|
737
711
|
).then((receipts) => receipts.flat());
|
|
738
712
|
|
|
739
|
-
if (isKilled) return;
|
|
740
|
-
|
|
741
713
|
await args.syncStore.insertTransactionReceipts({
|
|
742
714
|
transactionReceipts,
|
|
743
715
|
chainId: args.network.chainId,
|
|
@@ -858,14 +830,10 @@ export const createHistoricalSync = async (
|
|
|
858
830
|
return;
|
|
859
831
|
}
|
|
860
832
|
|
|
861
|
-
if (isKilled) return;
|
|
862
|
-
|
|
863
833
|
await blockPromise;
|
|
864
834
|
}),
|
|
865
835
|
);
|
|
866
836
|
|
|
867
|
-
if (isKilled) return;
|
|
868
|
-
|
|
869
837
|
const blocks = await Promise.all(blockCache.values());
|
|
870
838
|
|
|
871
839
|
await Promise.all([
|
|
@@ -883,8 +851,6 @@ export const createHistoricalSync = async (
|
|
|
883
851
|
}),
|
|
884
852
|
]);
|
|
885
853
|
|
|
886
|
-
if (isKilled) return;
|
|
887
|
-
|
|
888
854
|
// Add corresponding intervals to the sync-store
|
|
889
855
|
// Note: this should happen after so the database doesn't become corrupted
|
|
890
856
|
if (args.network.disableCache === false) {
|
|
@@ -902,8 +868,5 @@ export const createHistoricalSync = async (
|
|
|
902
868
|
|
|
903
869
|
return latestBlock;
|
|
904
870
|
},
|
|
905
|
-
kill() {
|
|
906
|
-
isKilled = true;
|
|
907
|
-
},
|
|
908
871
|
};
|
|
909
872
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Common } from "@/internal/common.js";
|
|
2
|
+
import { ShutdownError } from "@/internal/errors.js";
|
|
2
3
|
import type {
|
|
3
4
|
BlockFilter,
|
|
4
5
|
Factory,
|
|
@@ -30,6 +31,7 @@ import type {
|
|
|
30
31
|
SyncTransaction,
|
|
31
32
|
SyncTransactionReceipt,
|
|
32
33
|
} from "@/types/sync.js";
|
|
34
|
+
import { mutex } from "@/utils/mutex.js";
|
|
33
35
|
import { range } from "@/utils/range.js";
|
|
34
36
|
import type { RequestQueue } from "@/utils/requestQueue.js";
|
|
35
37
|
import {
|
|
@@ -42,7 +44,7 @@ import {
|
|
|
42
44
|
} from "@/utils/rpc.js";
|
|
43
45
|
import { startClock } from "@/utils/timer.js";
|
|
44
46
|
import { wait } from "@/utils/wait.js";
|
|
45
|
-
import {
|
|
47
|
+
import type { Queue } from "@ponder/common";
|
|
46
48
|
import { type Address, type Hash, hexToNumber, zeroHash } from "viem";
|
|
47
49
|
import { isFilterInBloom, zeroLogsBloom } from "./bloom.js";
|
|
48
50
|
|
|
@@ -51,10 +53,10 @@ export type RealtimeSync = {
|
|
|
51
53
|
syncProgress: Pick<SyncProgress, "finalized">;
|
|
52
54
|
initialChildAddresses: Map<Factory, Set<Address>>;
|
|
53
55
|
}): Promise<Queue<void, BlockWithEventData>>;
|
|
54
|
-
kill(): Promise<void>;
|
|
55
56
|
unfinalizedBlocks: LightBlock[];
|
|
56
57
|
finalizedChildAddresses: Map<Factory, Set<Address>>;
|
|
57
58
|
unfinalizedChildAddresses: Map<Factory, Set<Address>>;
|
|
59
|
+
kill: () => void;
|
|
58
60
|
};
|
|
59
61
|
|
|
60
62
|
type CreateRealtimeSyncParameters = {
|
|
@@ -102,7 +104,6 @@ export const createRealtimeSync = (
|
|
|
102
104
|
////////
|
|
103
105
|
// state
|
|
104
106
|
////////
|
|
105
|
-
let isKilled = false;
|
|
106
107
|
let isBlockReceipts = true;
|
|
107
108
|
let finalizedBlock: LightBlock;
|
|
108
109
|
let finalizedChildAddresses: Map<Factory, Set<Address>>;
|
|
@@ -115,7 +116,7 @@ export const createRealtimeSync = (
|
|
|
115
116
|
* `parentHash` => `hash`.
|
|
116
117
|
*/
|
|
117
118
|
let unfinalizedBlocks: LightBlock[] = [];
|
|
118
|
-
let queue: Queue<void, BlockWithEventData & { endClock?: () => number }>;
|
|
119
|
+
// let queue: Queue<void, BlockWithEventData & { endClock?: () => number }>;
|
|
119
120
|
let consecutiveErrors = 0;
|
|
120
121
|
let interval: NodeJS.Timeout | undefined;
|
|
121
122
|
|
|
@@ -433,7 +434,7 @@ export const createRealtimeSync = (
|
|
|
433
434
|
service: "realtime",
|
|
434
435
|
msg: `Finalized ${hexToNumber(pendingFinalizedBlock.number) - hexToNumber(finalizedBlock.number) + 1} '${
|
|
435
436
|
args.network.name
|
|
436
|
-
}' blocks
|
|
437
|
+
}' blocks [${hexToNumber(finalizedBlock.number) + 1}, ${hexToNumber(pendingFinalizedBlock.number)}]`,
|
|
437
438
|
});
|
|
438
439
|
|
|
439
440
|
const finalizedBlocks = unfinalizedBlocks.filter(
|
|
@@ -490,11 +491,6 @@ export const createRealtimeSync = (
|
|
|
490
491
|
|
|
491
492
|
await args.onEvent({ type: "finalize", block: pendingFinalizedBlock });
|
|
492
493
|
}
|
|
493
|
-
|
|
494
|
-
args.common.logger.debug({
|
|
495
|
-
service: "realtime",
|
|
496
|
-
msg: `Finished syncing '${args.network.name}' block ${hexToNumber(block.number)}`,
|
|
497
|
-
});
|
|
498
494
|
};
|
|
499
495
|
|
|
500
496
|
/**
|
|
@@ -551,9 +547,9 @@ export const createRealtimeSync = (
|
|
|
551
547
|
|
|
552
548
|
args.common.logger.warn({
|
|
553
549
|
service: "realtime",
|
|
554
|
-
msg: `Reconciled ${reorgedBlocks.length}-block
|
|
550
|
+
msg: `Reconciled ${reorgedBlocks.length}-block '${
|
|
555
551
|
args.network.name
|
|
556
|
-
}' with common ancestor block ${hexToNumber(commonAncestor.number)}`,
|
|
552
|
+
}' reorg with common ancestor block ${hexToNumber(commonAncestor.number)}`,
|
|
557
553
|
});
|
|
558
554
|
|
|
559
555
|
// recompute `unfinalizedChildAddresses`
|
|
@@ -691,11 +687,11 @@ export const createRealtimeSync = (
|
|
|
691
687
|
if (log.transactionHash === zeroHash) {
|
|
692
688
|
args.common.logger.warn({
|
|
693
689
|
service: "sync",
|
|
694
|
-
msg: `Detected log with empty transaction hash in block ${block.hash} at log index ${hexToNumber(log.logIndex)}. This is expected for some networks like ZKsync.`,
|
|
690
|
+
msg: `Detected '${args.network.name}' log with empty transaction hash in block ${block.hash} at log index ${hexToNumber(log.logIndex)}. This is expected for some networks like ZKsync.`,
|
|
695
691
|
});
|
|
696
692
|
} else {
|
|
697
693
|
throw new Error(
|
|
698
|
-
`Detected inconsistent RPC responses. 'log.transactionHash' ${log.transactionHash} not found in 'block.transactions' ${block.hash}`,
|
|
694
|
+
`Detected inconsistent '${args.network.name}' RPC responses. 'log.transactionHash' ${log.transactionHash} not found in 'block.transactions' ${block.hash}`,
|
|
699
695
|
);
|
|
700
696
|
}
|
|
701
697
|
}
|
|
@@ -708,7 +704,7 @@ export const createRealtimeSync = (
|
|
|
708
704
|
) {
|
|
709
705
|
args.common.logger.debug({
|
|
710
706
|
service: "realtime",
|
|
711
|
-
msg: `Skipped fetching
|
|
707
|
+
msg: `Skipped fetching '${args.network.name}' logs for block ${hexToNumber(block.number)} due to bloom filter result`,
|
|
712
708
|
});
|
|
713
709
|
}
|
|
714
710
|
|
|
@@ -782,7 +778,7 @@ export const createRealtimeSync = (
|
|
|
782
778
|
if (log.transactionHash === zeroHash) {
|
|
783
779
|
args.common.logger.warn({
|
|
784
780
|
service: "sync",
|
|
785
|
-
msg: `Detected log with empty transaction hash in block ${block.hash} at log index ${hexToNumber(log.logIndex)}. This is expected for some networks like ZKsync.`,
|
|
781
|
+
msg: `Detected '${args.network.name}' log with empty transaction hash in block ${block.hash} at log index ${hexToNumber(log.logIndex)}. This is expected for some networks like ZKsync.`,
|
|
786
782
|
});
|
|
787
783
|
} else {
|
|
788
784
|
requiredTransactions.add(log.transactionHash);
|
|
@@ -908,11 +904,11 @@ export const createRealtimeSync = (
|
|
|
908
904
|
* 4) Block is behind the last processed. This is a sign that
|
|
909
905
|
* a reorg has occurred.
|
|
910
906
|
*/
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
907
|
+
const processBlock = mutex(
|
|
908
|
+
async ({
|
|
909
|
+
block,
|
|
910
|
+
...rest
|
|
911
|
+
}: BlockWithEventData & { endClock?: () => number }) => {
|
|
916
912
|
const latestBlock = getLatestUnfinalizedBlock();
|
|
917
913
|
|
|
918
914
|
// We already saw and handled this block. No-op.
|
|
@@ -931,7 +927,7 @@ export const createRealtimeSync = (
|
|
|
931
927
|
if (hexToNumber(latestBlock.number) >= hexToNumber(block.number)) {
|
|
932
928
|
await handleReorg(block);
|
|
933
929
|
|
|
934
|
-
|
|
930
|
+
processBlock.clear();
|
|
935
931
|
return;
|
|
936
932
|
}
|
|
937
933
|
|
|
@@ -961,24 +957,19 @@ export const createRealtimeSync = (
|
|
|
961
957
|
service: "realtime",
|
|
962
958
|
msg: `Fetched ${missingBlockRange.length} missing '${
|
|
963
959
|
args.network.name
|
|
964
|
-
}' blocks
|
|
960
|
+
}' blocks [${hexToNumber(latestBlock.number) + 1}, ${Math.min(
|
|
965
961
|
hexToNumber(block.number),
|
|
966
962
|
hexToNumber(latestBlock.number) + MAX_QUEUED_BLOCKS,
|
|
967
|
-
)}`,
|
|
963
|
+
)}]`,
|
|
968
964
|
});
|
|
969
965
|
|
|
970
|
-
|
|
971
|
-
// is killed, nothing should be added to the queue, or else `onIdle()`
|
|
972
|
-
// will never resolve.
|
|
973
|
-
if (isKilled) return;
|
|
974
|
-
|
|
975
|
-
queue.clear();
|
|
966
|
+
processBlock.clear();
|
|
976
967
|
|
|
977
968
|
for (const pendingBlock of pendingBlocks) {
|
|
978
|
-
|
|
969
|
+
processBlock(pendingBlock);
|
|
979
970
|
}
|
|
980
971
|
|
|
981
|
-
|
|
972
|
+
processBlock({ block, ...rest });
|
|
982
973
|
|
|
983
974
|
return;
|
|
984
975
|
}
|
|
@@ -986,7 +977,7 @@ export const createRealtimeSync = (
|
|
|
986
977
|
// Check if a reorg occurred by validating the chain of block hashes.
|
|
987
978
|
if (block.parentHash !== latestBlock.hash) {
|
|
988
979
|
await handleReorg(block);
|
|
989
|
-
|
|
980
|
+
processBlock.clear();
|
|
990
981
|
return;
|
|
991
982
|
}
|
|
992
983
|
|
|
@@ -999,10 +990,12 @@ export const createRealtimeSync = (
|
|
|
999
990
|
|
|
1000
991
|
return;
|
|
1001
992
|
} catch (_error) {
|
|
1002
|
-
if (isKilled) return;
|
|
1003
|
-
|
|
1004
993
|
const error = _error as Error;
|
|
1005
994
|
|
|
995
|
+
if (args.common.shutdown.isKilled) {
|
|
996
|
+
throw new ShutdownError();
|
|
997
|
+
}
|
|
998
|
+
|
|
1006
999
|
args.common.logger.warn({
|
|
1007
1000
|
service: "realtime",
|
|
1008
1001
|
msg: `Failed to process '${args.network.name}' block ${hexToNumber(block.number)}`,
|
|
@@ -1022,7 +1015,7 @@ export const createRealtimeSync = (
|
|
|
1022
1015
|
|
|
1023
1016
|
// Remove all blocks from the queue. This protects against an
|
|
1024
1017
|
// erroneous block causing a fatal error.
|
|
1025
|
-
|
|
1018
|
+
processBlock.clear();
|
|
1026
1019
|
|
|
1027
1020
|
// After a certain number of attempts, emit a fatal error.
|
|
1028
1021
|
if (++consecutiveErrors === ERROR_TIMEOUT.length) {
|
|
@@ -1036,7 +1029,7 @@ export const createRealtimeSync = (
|
|
|
1036
1029
|
}
|
|
1037
1030
|
}
|
|
1038
1031
|
},
|
|
1039
|
-
|
|
1032
|
+
);
|
|
1040
1033
|
|
|
1041
1034
|
const enqueue = async () => {
|
|
1042
1035
|
try {
|
|
@@ -1044,6 +1037,11 @@ export const createRealtimeSync = (
|
|
|
1044
1037
|
blockTag: "latest",
|
|
1045
1038
|
});
|
|
1046
1039
|
|
|
1040
|
+
args.common.logger.debug({
|
|
1041
|
+
service: "realtime",
|
|
1042
|
+
msg: `Received latest '${args.network.name}' block ${hexToNumber(block.number)}`,
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1047
1045
|
const latestBlock = getLatestUnfinalizedBlock();
|
|
1048
1046
|
|
|
1049
1047
|
// We already saw and handled this block. No-op.
|
|
@@ -1062,12 +1060,14 @@ export const createRealtimeSync = (
|
|
|
1062
1060
|
|
|
1063
1061
|
consecutiveErrors = 0;
|
|
1064
1062
|
|
|
1065
|
-
return
|
|
1063
|
+
return processBlock({ ...blockWithEventData, endClock });
|
|
1066
1064
|
} catch (_error) {
|
|
1067
|
-
if (isKilled) return;
|
|
1068
|
-
|
|
1069
1065
|
const error = _error as Error;
|
|
1070
1066
|
|
|
1067
|
+
if (args.common.shutdown.isKilled) {
|
|
1068
|
+
throw new ShutdownError();
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
1071
|
args.common.logger.warn({
|
|
1072
1072
|
service: "realtime",
|
|
1073
1073
|
msg: `Failed to fetch latest '${args.network.name}' block`,
|
|
@@ -1089,15 +1089,12 @@ export const createRealtimeSync = (
|
|
|
1089
1089
|
|
|
1090
1090
|
interval = setInterval(enqueue, args.network.pollingInterval);
|
|
1091
1091
|
|
|
1092
|
+
args.common.shutdown.add(() => {
|
|
1093
|
+
clearInterval(interval);
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1092
1096
|
// Note: this is done just for testing.
|
|
1093
|
-
return enqueue().then(() =>
|
|
1094
|
-
},
|
|
1095
|
-
async kill() {
|
|
1096
|
-
clearInterval(interval);
|
|
1097
|
-
isKilled = true;
|
|
1098
|
-
queue?.pause();
|
|
1099
|
-
queue?.clear();
|
|
1100
|
-
await queue?.onIdle();
|
|
1097
|
+
return enqueue().then(() => processBlock);
|
|
1101
1098
|
},
|
|
1102
1099
|
get unfinalizedBlocks() {
|
|
1103
1100
|
return unfinalizedBlocks;
|
|
@@ -1108,5 +1105,8 @@ export const createRealtimeSync = (
|
|
|
1108
1105
|
get unfinalizedChildAddresses() {
|
|
1109
1106
|
return unfinalizedChildAddresses;
|
|
1110
1107
|
},
|
|
1108
|
+
async kill() {
|
|
1109
|
+
clearInterval(interval);
|
|
1110
|
+
},
|
|
1111
1111
|
};
|
|
1112
1112
|
};
|
|
@@ -8,9 +8,9 @@ import type {
|
|
|
8
8
|
} from "@/types/sync.js";
|
|
9
9
|
import {
|
|
10
10
|
EVENT_TYPES,
|
|
11
|
+
MAX_CHECKPOINT,
|
|
12
|
+
ZERO_CHECKPOINT,
|
|
11
13
|
encodeCheckpoint,
|
|
12
|
-
maxCheckpoint,
|
|
13
|
-
zeroCheckpoint,
|
|
14
14
|
} from "@/utils/checkpoint.js";
|
|
15
15
|
import { toLowerCase } from "@/utils/lowercase.js";
|
|
16
16
|
import type { ColumnType, Insertable } from "kysely";
|
|
@@ -55,9 +55,9 @@ export const encodeBlock = ({
|
|
|
55
55
|
blockTimestamp: hexToNumber(block.timestamp),
|
|
56
56
|
chainId: BigInt(chainId),
|
|
57
57
|
blockNumber: hexToBigInt(block.number),
|
|
58
|
-
transactionIndex:
|
|
58
|
+
transactionIndex: MAX_CHECKPOINT.transactionIndex,
|
|
59
59
|
eventType: EVENT_TYPES.blocks,
|
|
60
|
-
eventIndex:
|
|
60
|
+
eventIndex: ZERO_CHECKPOINT.eventIndex,
|
|
61
61
|
}),
|
|
62
62
|
baseFeePerGas: block.baseFeePerGas
|
|
63
63
|
? hexToBigInt(block.baseFeePerGas)
|
|
@@ -183,7 +183,7 @@ export const encodeTransaction = ({
|
|
|
183
183
|
blockNumber: hexToBigInt(transaction.blockNumber),
|
|
184
184
|
transactionIndex: hexToBigInt(transaction.transactionIndex),
|
|
185
185
|
eventType: EVENT_TYPES.transactions,
|
|
186
|
-
eventIndex:
|
|
186
|
+
eventIndex: ZERO_CHECKPOINT.eventIndex,
|
|
187
187
|
}),
|
|
188
188
|
chainId,
|
|
189
189
|
blockHash: transaction.blockHash,
|
package/src/sync-store/index.ts
CHANGED
|
@@ -118,10 +118,7 @@ export type SyncStore = {
|
|
|
118
118
|
blocks: Pick<LightBlock, "number">[];
|
|
119
119
|
chainId: number;
|
|
120
120
|
}): Promise<void>;
|
|
121
|
-
pruneByChain(args: {
|
|
122
|
-
fromBlock: number;
|
|
123
|
-
chainId: number;
|
|
124
|
-
}): Promise<void>;
|
|
121
|
+
pruneByChain(args: { chainId: number }): Promise<void>;
|
|
125
122
|
};
|
|
126
123
|
|
|
127
124
|
const logFactorySQL = (
|
|
@@ -902,38 +899,23 @@ export const createSyncStore = ({
|
|
|
902
899
|
.execute();
|
|
903
900
|
},
|
|
904
901
|
),
|
|
905
|
-
pruneByChain: async ({
|
|
902
|
+
pruneByChain: async ({ chainId }) =>
|
|
906
903
|
database.wrap({ method: "pruneByChain", includeTraceLogs: true }, () =>
|
|
907
904
|
database.qb.sync.transaction().execute(async (tx) => {
|
|
908
|
-
await tx
|
|
909
|
-
|
|
910
|
-
.where("chainId", "=", chainId)
|
|
911
|
-
.where("blockNumber", ">=", fromBlock.toString())
|
|
912
|
-
.execute();
|
|
913
|
-
await tx
|
|
914
|
-
.deleteFrom("blocks")
|
|
915
|
-
.where("chainId", "=", chainId)
|
|
916
|
-
.where("number", ">=", fromBlock.toString())
|
|
917
|
-
.execute();
|
|
905
|
+
await tx.deleteFrom("logs").where("chainId", "=", chainId).execute();
|
|
906
|
+
await tx.deleteFrom("blocks").where("chainId", "=", chainId).execute();
|
|
918
907
|
await tx
|
|
919
908
|
.deleteFrom("rpc_request_results")
|
|
920
909
|
.where("chain_id", "=", chainId)
|
|
921
|
-
.where("block_number", ">=", fromBlock.toString())
|
|
922
|
-
.execute();
|
|
923
|
-
await tx
|
|
924
|
-
.deleteFrom("traces")
|
|
925
|
-
.where("chainId", "=", chainId)
|
|
926
|
-
.where("blockNumber", ">=", fromBlock.toString())
|
|
927
910
|
.execute();
|
|
911
|
+
await tx.deleteFrom("traces").where("chainId", "=", chainId).execute();
|
|
928
912
|
await tx
|
|
929
913
|
.deleteFrom("transactions")
|
|
930
914
|
.where("chainId", "=", chainId)
|
|
931
|
-
.where("blockNumber", ">=", fromBlock.toString())
|
|
932
915
|
.execute();
|
|
933
916
|
await tx
|
|
934
917
|
.deleteFrom("transactionReceipts")
|
|
935
918
|
.where("chainId", "=", chainId)
|
|
936
|
-
.where("blockNumber", ">=", fromBlock.toString())
|
|
937
919
|
.execute();
|
|
938
920
|
}),
|
|
939
921
|
),
|
package/src/ui/index.ts
CHANGED
|
@@ -10,11 +10,7 @@ export function createUi({ common }: { common: Common }) {
|
|
|
10
10
|
const ui = buildUiState();
|
|
11
11
|
const { render, unmount } = setupInkApp(ui);
|
|
12
12
|
|
|
13
|
-
let isKilled = false;
|
|
14
|
-
|
|
15
13
|
const renderInterval = setInterval(async () => {
|
|
16
|
-
if (isKilled) return;
|
|
17
|
-
|
|
18
14
|
ui.sync = await getSyncProgress(common.metrics);
|
|
19
15
|
ui.indexing = await getIndexingProgress(common.metrics);
|
|
20
16
|
ui.app = await getAppProgress(common.metrics);
|
|
@@ -26,13 +22,8 @@ export function createUi({ common }: { common: Common }) {
|
|
|
26
22
|
render(ui);
|
|
27
23
|
}, 100);
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
isKilled = true;
|
|
25
|
+
common.shutdown.add(async () => {
|
|
31
26
|
clearInterval(renderInterval);
|
|
32
27
|
unmount();
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
kill,
|
|
37
|
-
};
|
|
28
|
+
});
|
|
38
29
|
}
|
package/src/utils/checkpoint.ts
CHANGED
|
@@ -105,7 +105,7 @@ export const decodeCheckpoint = (checkpoint: string): Checkpoint => {
|
|
|
105
105
|
};
|
|
106
106
|
};
|
|
107
107
|
|
|
108
|
-
export const
|
|
108
|
+
export const ZERO_CHECKPOINT: Checkpoint = {
|
|
109
109
|
blockTimestamp: 0,
|
|
110
110
|
chainId: 0n,
|
|
111
111
|
blockNumber: 0n,
|
|
@@ -114,7 +114,7 @@ export const zeroCheckpoint: Checkpoint = {
|
|
|
114
114
|
eventIndex: 0n,
|
|
115
115
|
};
|
|
116
116
|
|
|
117
|
-
export const
|
|
117
|
+
export const MAX_CHECKPOINT: Checkpoint = {
|
|
118
118
|
blockTimestamp: 99999_99999,
|
|
119
119
|
chainId: 9999_9999_9999_9999n,
|
|
120
120
|
blockNumber: 9999_9999_9999_9999n,
|
|
@@ -123,6 +123,10 @@ export const maxCheckpoint: Checkpoint = {
|
|
|
123
123
|
eventIndex: 9999_9999_9999_9999n,
|
|
124
124
|
};
|
|
125
125
|
|
|
126
|
+
export const ZERO_CHECKPOINT_STRING = encodeCheckpoint(ZERO_CHECKPOINT);
|
|
127
|
+
export const MAX_CHECKPOINT_STRING = encodeCheckpoint(MAX_CHECKPOINT);
|
|
128
|
+
|
|
129
|
+
/**
|
|
126
130
|
/**
|
|
127
131
|
* Returns true if two checkpoints are equal.
|
|
128
132
|
*/
|
|
@@ -154,4 +158,14 @@ export const checkpointMin = (...checkpoints: Checkpoint[]) =>
|
|
|
154
158
|
return isCheckpointGreaterThan(min, checkpoint) ? checkpoint : min;
|
|
155
159
|
});
|
|
156
160
|
|
|
157
|
-
export const LATEST =
|
|
161
|
+
export const LATEST = MAX_CHECKPOINT_STRING;
|
|
162
|
+
|
|
163
|
+
/** Compute the minimum checkpoint, filtering out undefined */
|
|
164
|
+
export const min = (...checkpoints: (string | undefined)[]) => {
|
|
165
|
+
return checkpoints.reduce((acc, cur) => {
|
|
166
|
+
if (cur === undefined) return acc;
|
|
167
|
+
if (acc === undefined) return cur;
|
|
168
|
+
if (acc < cur) return acc;
|
|
169
|
+
return cur;
|
|
170
|
+
})!;
|
|
171
|
+
};
|
package/src/utils/generators.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { promiseWithResolvers } from "@ponder/common";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Merges multiple async generators into a single async generator.
|
|
5
|
+
*
|
|
6
|
+
* @param generators - The generators to merge.
|
|
7
|
+
* @returns A single async generator that yields results from all input generators.
|
|
8
|
+
*/
|
|
3
9
|
export async function* mergeAsyncGenerators<T>(
|
|
4
10
|
generators: AsyncGenerator<T>[],
|
|
5
11
|
): AsyncGenerator<T> {
|
|
@@ -25,3 +31,63 @@ export async function* mergeAsyncGenerators<T>(
|
|
|
25
31
|
}
|
|
26
32
|
}
|
|
27
33
|
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Buffers the results of an async generator.
|
|
37
|
+
*
|
|
38
|
+
* @param generator - The generator to buffer.
|
|
39
|
+
* @param size - The size of the buffer.
|
|
40
|
+
* @returns An async generator that yields results from the input generator.
|
|
41
|
+
*/
|
|
42
|
+
export async function* bufferAsyncGenerator<T>(
|
|
43
|
+
generator: AsyncGenerator<T>,
|
|
44
|
+
size: number,
|
|
45
|
+
): AsyncGenerator<T> {
|
|
46
|
+
const buffer: T[] = [];
|
|
47
|
+
let done = false;
|
|
48
|
+
|
|
49
|
+
let pwr1 = promiseWithResolvers<void>();
|
|
50
|
+
let pwr2 = promiseWithResolvers<void>();
|
|
51
|
+
|
|
52
|
+
(async () => {
|
|
53
|
+
for await (const result of generator) {
|
|
54
|
+
buffer.push(result);
|
|
55
|
+
|
|
56
|
+
pwr1.resolve();
|
|
57
|
+
|
|
58
|
+
if (buffer.length > size) await pwr2.promise;
|
|
59
|
+
pwr2 = promiseWithResolvers<void>();
|
|
60
|
+
}
|
|
61
|
+
done = true;
|
|
62
|
+
pwr1.resolve();
|
|
63
|
+
})();
|
|
64
|
+
|
|
65
|
+
while (done === false || buffer.length > 0) {
|
|
66
|
+
if (buffer.length > 0) {
|
|
67
|
+
pwr2.resolve();
|
|
68
|
+
|
|
69
|
+
yield buffer.shift()!;
|
|
70
|
+
} else {
|
|
71
|
+
await pwr1.promise;
|
|
72
|
+
pwr1 = promiseWithResolvers<void>();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Drains an async generator into an array.
|
|
79
|
+
*
|
|
80
|
+
* @param asyncGenerator - The async generator to drain.
|
|
81
|
+
* @returns An array of results from the input generator.
|
|
82
|
+
*/
|
|
83
|
+
export async function drainAsyncGenerator<T>(
|
|
84
|
+
asyncGenerator: AsyncGenerator<T>,
|
|
85
|
+
): Promise<T[]> {
|
|
86
|
+
const result: T[] = [];
|
|
87
|
+
|
|
88
|
+
for await (const events of asyncGenerator) {
|
|
89
|
+
result.push(events);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return result;
|
|
93
|
+
}
|