ponder 0.14.13 → 0.15.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 +16 -0
- package/dist/esm/bin/commands/createViews.js +28 -11
- package/dist/esm/bin/commands/createViews.js.map +1 -1
- package/dist/esm/bin/commands/dev.js +42 -22
- package/dist/esm/bin/commands/dev.js.map +1 -1
- package/dist/esm/bin/commands/prune.js +3 -0
- package/dist/esm/bin/commands/prune.js.map +1 -1
- package/dist/esm/bin/commands/serve.js +4 -1
- package/dist/esm/bin/commands/serve.js.map +1 -1
- package/dist/esm/bin/commands/start.js +18 -6
- package/dist/esm/bin/commands/start.js.map +1 -1
- package/dist/esm/bin/isolatedController.js +200 -0
- package/dist/esm/bin/isolatedController.js.map +1 -0
- package/dist/esm/bin/isolatedWorker.js +146 -0
- package/dist/esm/bin/isolatedWorker.js.map +1 -0
- package/dist/esm/build/config.js +322 -402
- package/dist/esm/build/config.js.map +1 -1
- package/dist/esm/build/index.js +8 -11
- package/dist/esm/build/index.js.map +1 -1
- package/dist/esm/build/pre.js +1 -4
- package/dist/esm/build/pre.js.map +1 -1
- package/dist/esm/build/schema.js +25 -3
- package/dist/esm/build/schema.js.map +1 -1
- package/dist/esm/client/index.js +306 -42
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/database/actions.js +264 -104
- package/dist/esm/database/actions.js.map +1 -1
- package/dist/esm/database/index.js +39 -33
- package/dist/esm/database/index.js.map +1 -1
- package/dist/esm/database/queryBuilder.js +1 -0
- package/dist/esm/database/queryBuilder.js.map +1 -1
- package/dist/esm/drizzle/index.js +11 -7
- package/dist/esm/drizzle/index.js.map +1 -1
- package/dist/esm/drizzle/onchain.js +18 -0
- package/dist/esm/drizzle/onchain.js.map +1 -1
- package/dist/esm/indexing/client.js +32 -25
- package/dist/esm/indexing/client.js.map +1 -1
- package/dist/esm/indexing/index.js +110 -178
- package/dist/esm/indexing/index.js.map +1 -1
- package/dist/esm/indexing/profile.js +1 -1
- package/dist/esm/indexing/profile.js.map +1 -1
- package/dist/esm/indexing-store/cache.js +196 -274
- package/dist/esm/indexing-store/cache.js.map +1 -1
- package/dist/esm/indexing-store/historical.js +17 -13
- package/dist/esm/indexing-store/historical.js.map +1 -1
- package/dist/esm/indexing-store/index.js +10 -1
- package/dist/esm/indexing-store/index.js.map +1 -1
- package/dist/esm/indexing-store/profile.js +3 -3
- package/dist/esm/indexing-store/profile.js.map +1 -1
- package/dist/esm/indexing-store/realtime.js +27 -2
- package/dist/esm/indexing-store/realtime.js.map +1 -1
- package/dist/esm/internal/errors.js +28 -0
- package/dist/esm/internal/errors.js.map +1 -1
- package/dist/esm/internal/metrics.js +279 -82
- package/dist/esm/internal/metrics.js.map +1 -1
- package/dist/esm/internal/options.js +1 -0
- package/dist/esm/internal/options.js.map +1 -1
- package/dist/esm/internal/telemetry.js +1 -1
- package/dist/esm/internal/telemetry.js.map +1 -1
- package/dist/esm/rpc/http.js +130 -0
- package/dist/esm/rpc/http.js.map +1 -0
- package/dist/esm/rpc/index.js +38 -7
- package/dist/esm/rpc/index.js.map +1 -1
- package/dist/esm/runtime/events.js +179 -212
- package/dist/esm/runtime/events.js.map +1 -1
- package/dist/esm/runtime/filter.js +71 -0
- package/dist/esm/runtime/filter.js.map +1 -1
- package/dist/esm/runtime/fragments.js +78 -73
- package/dist/esm/runtime/fragments.js.map +1 -1
- package/dist/esm/runtime/historical.js +306 -130
- package/dist/esm/runtime/historical.js.map +1 -1
- package/dist/esm/runtime/index.js +183 -58
- package/dist/esm/runtime/index.js.map +1 -1
- package/dist/esm/runtime/isolated.js +462 -0
- package/dist/esm/runtime/isolated.js.map +1 -0
- package/dist/esm/runtime/multichain.js +80 -73
- package/dist/esm/runtime/multichain.js.map +1 -1
- package/dist/esm/runtime/omnichain.js +82 -75
- package/dist/esm/runtime/omnichain.js.map +1 -1
- package/dist/esm/runtime/realtime.js +198 -66
- package/dist/esm/runtime/realtime.js.map +1 -1
- package/dist/esm/sync-historical/index.js +416 -457
- package/dist/esm/sync-historical/index.js.map +1 -1
- package/dist/esm/sync-realtime/bloom.js +3 -3
- package/dist/esm/sync-realtime/bloom.js.map +1 -1
- package/dist/esm/sync-realtime/index.js +27 -46
- package/dist/esm/sync-realtime/index.js.map +1 -1
- package/dist/esm/sync-store/index.js +112 -63
- package/dist/esm/sync-store/index.js.map +1 -1
- package/dist/esm/utils/abi.js +20 -32
- package/dist/esm/utils/abi.js.map +1 -1
- package/dist/esm/utils/chunk.js +8 -0
- package/dist/esm/utils/chunk.js.map +1 -0
- package/dist/esm/utils/promiseAllSettledWithThrow.js +19 -0
- package/dist/esm/utils/promiseAllSettledWithThrow.js.map +1 -0
- package/dist/esm/{client/parse.js → utils/sql-parse.js} +94 -80
- package/dist/esm/utils/sql-parse.js.map +1 -0
- package/dist/types/bin/commands/createViews.d.ts.map +1 -1
- package/dist/types/bin/commands/dev.d.ts.map +1 -1
- package/dist/types/bin/commands/prune.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/bin/isolatedController.d.ts +13 -0
- package/dist/types/bin/isolatedController.d.ts.map +1 -0
- package/dist/types/bin/isolatedWorker.d.ts +9 -0
- package/dist/types/bin/isolatedWorker.d.ts.map +1 -0
- package/dist/types/build/config.d.ts +29 -11
- package/dist/types/build/config.d.ts.map +1 -1
- package/dist/types/build/index.d.ts +3 -2
- package/dist/types/build/index.d.ts.map +1 -1
- package/dist/types/build/pre.d.ts +1 -1
- package/dist/types/build/pre.d.ts.map +1 -1
- package/dist/types/build/schema.d.ts +5 -3
- package/dist/types/build/schema.d.ts.map +1 -1
- package/dist/types/client/index.d.ts +1 -1
- package/dist/types/client/index.d.ts.map +1 -1
- package/dist/types/config/index.d.ts +3 -3
- package/dist/types/config/index.d.ts.map +1 -1
- package/dist/types/database/actions.d.ts +53 -7
- package/dist/types/database/actions.d.ts.map +1 -1
- package/dist/types/database/index.d.ts +21 -21
- package/dist/types/database/index.d.ts.map +1 -1
- package/dist/types/database/queryBuilder.d.ts.map +1 -1
- package/dist/types/drizzle/index.d.ts +4 -5
- package/dist/types/drizzle/index.d.ts.map +1 -1
- package/dist/types/drizzle/onchain.d.ts +6 -0
- package/dist/types/drizzle/onchain.d.ts.map +1 -1
- package/dist/types/indexing/client.d.ts.map +1 -1
- package/dist/types/indexing/index.d.ts +2 -5
- package/dist/types/indexing/index.d.ts.map +1 -1
- package/dist/types/indexing-store/cache.d.ts +3 -2
- package/dist/types/indexing-store/cache.d.ts.map +1 -1
- package/dist/types/indexing-store/historical.d.ts +2 -1
- package/dist/types/indexing-store/historical.d.ts.map +1 -1
- package/dist/types/indexing-store/index.d.ts +1 -0
- package/dist/types/indexing-store/index.d.ts.map +1 -1
- package/dist/types/indexing-store/realtime.d.ts +2 -1
- package/dist/types/indexing-store/realtime.d.ts.map +1 -1
- package/dist/types/internal/errors.d.ts +5 -0
- package/dist/types/internal/errors.d.ts.map +1 -1
- package/dist/types/internal/metrics.d.ts +21 -0
- package/dist/types/internal/metrics.d.ts.map +1 -1
- package/dist/types/internal/options.d.ts +2 -0
- package/dist/types/internal/options.d.ts.map +1 -1
- package/dist/types/internal/types.d.ts +66 -58
- package/dist/types/internal/types.d.ts.map +1 -1
- package/dist/types/rpc/http.d.ts +17 -0
- package/dist/types/rpc/http.d.ts.map +1 -0
- package/dist/types/rpc/index.d.ts.map +1 -1
- package/dist/types/runtime/events.d.ts +4 -4
- package/dist/types/runtime/events.d.ts.map +1 -1
- package/dist/types/runtime/filter.d.ts +5 -1
- package/dist/types/runtime/filter.d.ts.map +1 -1
- package/dist/types/runtime/fragments.d.ts +4 -3
- package/dist/types/runtime/fragments.d.ts.map +1 -1
- package/dist/types/runtime/historical.d.ts +29 -13
- package/dist/types/runtime/historical.d.ts.map +1 -1
- package/dist/types/runtime/index.d.ts +49 -6
- package/dist/types/runtime/index.d.ts.map +1 -1
- package/dist/types/runtime/init.d.ts +5 -5
- package/dist/types/runtime/init.d.ts.map +1 -1
- package/dist/types/runtime/isolated.d.ts +14 -0
- package/dist/types/runtime/isolated.d.ts.map +1 -0
- 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 +21 -10
- package/dist/types/runtime/realtime.d.ts.map +1 -1
- package/dist/types/sync-historical/index.d.ts +18 -8
- package/dist/types/sync-historical/index.d.ts.map +1 -1
- package/dist/types/sync-realtime/bloom.d.ts.map +1 -1
- package/dist/types/sync-realtime/index.d.ts +2 -2
- package/dist/types/sync-realtime/index.d.ts.map +1 -1
- package/dist/types/sync-store/index.d.ts +9 -9
- package/dist/types/sync-store/index.d.ts.map +1 -1
- package/dist/types/utils/abi.d.ts +3 -34
- package/dist/types/utils/abi.d.ts.map +1 -1
- package/dist/types/utils/chunk.d.ts +2 -0
- package/dist/types/utils/chunk.d.ts.map +1 -0
- package/dist/types/utils/promiseAllSettledWithThrow.d.ts +8 -0
- package/dist/types/utils/promiseAllSettledWithThrow.d.ts.map +1 -0
- package/dist/types/utils/sql-parse.d.ts +21 -0
- package/dist/types/utils/sql-parse.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/bin/commands/createViews.ts +35 -15
- package/src/bin/commands/dev.ts +43 -21
- package/src/bin/commands/prune.ts +6 -0
- package/src/bin/commands/serve.ts +4 -1
- package/src/bin/commands/start.ts +20 -5
- package/src/bin/isolatedController.ts +300 -0
- package/src/bin/isolatedWorker.ts +192 -0
- package/src/build/config.ts +570 -632
- package/src/build/index.ts +14 -14
- package/src/build/pre.ts +1 -4
- package/src/build/schema.ts +49 -4
- package/src/client/index.ts +386 -48
- package/src/config/index.ts +3 -3
- package/src/database/actions.ts +469 -120
- package/src/database/index.ts +85 -58
- package/src/database/queryBuilder.ts +1 -0
- package/src/drizzle/index.ts +15 -7
- package/src/drizzle/onchain.ts +19 -0
- package/src/indexing/client.ts +38 -25
- package/src/indexing/index.ts +137 -230
- package/src/indexing/profile.ts +1 -1
- package/src/indexing-store/cache.ts +285 -414
- package/src/indexing-store/historical.ts +20 -10
- package/src/indexing-store/index.ts +16 -0
- package/src/indexing-store/profile.ts +3 -3
- package/src/indexing-store/realtime.ts +28 -0
- package/src/internal/errors.ts +26 -0
- package/src/internal/metrics.ts +341 -111
- package/src/internal/options.ts +4 -0
- package/src/internal/telemetry.ts +1 -1
- package/src/internal/types.ts +70 -87
- package/src/rpc/http.ts +164 -0
- package/src/rpc/index.ts +39 -7
- package/src/runtime/events.ts +195 -240
- package/src/runtime/filter.ts +85 -1
- package/src/runtime/fragments.ts +109 -113
- package/src/runtime/historical.ts +467 -189
- package/src/runtime/index.ts +337 -69
- package/src/runtime/init.ts +5 -5
- package/src/runtime/isolated.ts +768 -0
- package/src/runtime/multichain.ts +137 -102
- package/src/runtime/omnichain.ts +138 -106
- package/src/runtime/realtime.ts +322 -123
- package/src/sync-historical/index.ts +556 -692
- package/src/sync-realtime/bloom.ts +7 -3
- package/src/sync-realtime/index.ts +31 -46
- package/src/sync-store/index.ts +189 -95
- package/src/utils/abi.ts +33 -90
- package/src/utils/chunk.ts +7 -0
- package/src/utils/promiseAllSettledWithThrow.ts +27 -0
- package/src/{client/parse.ts → utils/sql-parse.ts} +100 -90
- package/dist/esm/client/parse.js.map +0 -1
- package/dist/types/client/parse.d.ts +0 -14
- package/dist/types/client/parse.d.ts.map +0 -1
|
@@ -4,11 +4,7 @@ import type {
|
|
|
4
4
|
Chain,
|
|
5
5
|
Factory,
|
|
6
6
|
FactoryId,
|
|
7
|
-
FilterWithoutBlocks,
|
|
8
|
-
Fragment,
|
|
9
|
-
LogFactory,
|
|
10
7
|
LogFilter,
|
|
11
|
-
Source,
|
|
12
8
|
SyncBlock,
|
|
13
9
|
SyncLog,
|
|
14
10
|
SyncTrace,
|
|
@@ -34,29 +30,36 @@ import {
|
|
|
34
30
|
getChildAddress,
|
|
35
31
|
isAddressFactory,
|
|
36
32
|
isAddressMatched,
|
|
33
|
+
isBlockFilterMatched,
|
|
34
|
+
isBlockInFilter,
|
|
37
35
|
isLogFactoryMatched,
|
|
36
|
+
isLogFilterMatched,
|
|
38
37
|
isTraceFilterMatched,
|
|
39
38
|
isTransactionFilterMatched,
|
|
40
39
|
isTransferFilterMatched,
|
|
41
40
|
} from "@/runtime/filter.js";
|
|
42
|
-
import {
|
|
43
|
-
|
|
41
|
+
import type {
|
|
42
|
+
ChildAddresses,
|
|
43
|
+
IntervalWithFactory,
|
|
44
|
+
IntervalWithFilter,
|
|
45
|
+
} from "@/runtime/index.js";
|
|
44
46
|
import type { SyncStore } from "@/sync-store/index.js";
|
|
45
47
|
import {
|
|
46
48
|
type Interval,
|
|
47
49
|
getChunks,
|
|
48
50
|
intervalBounds,
|
|
49
|
-
intervalDifference,
|
|
50
51
|
intervalRange,
|
|
51
|
-
intervalUnion,
|
|
52
52
|
} from "@/utils/interval.js";
|
|
53
|
+
import { promiseAllSettledWithThrow } from "@/utils/promiseAllSettledWithThrow.js";
|
|
54
|
+
import { createQueue } from "@/utils/queue.js";
|
|
53
55
|
import { startClock } from "@/utils/timer.js";
|
|
54
56
|
import { getLogsRetryHelper } from "@ponder/utils";
|
|
55
57
|
import {
|
|
56
58
|
type Address,
|
|
57
59
|
type Hash,
|
|
60
|
+
type Hex,
|
|
61
|
+
type LogTopic,
|
|
58
62
|
type RpcError,
|
|
59
|
-
hexToBigInt,
|
|
60
63
|
hexToNumber,
|
|
61
64
|
toHex,
|
|
62
65
|
zeroHash,
|
|
@@ -64,20 +67,30 @@ import {
|
|
|
64
67
|
|
|
65
68
|
export type HistoricalSync = {
|
|
66
69
|
/**
|
|
67
|
-
*
|
|
68
|
-
|
|
70
|
+
* Sync block data that can be queried for a range of blocks (logs).
|
|
71
|
+
*/
|
|
72
|
+
syncBlockRangeData(params: {
|
|
73
|
+
interval: Interval;
|
|
74
|
+
requiredIntervals: IntervalWithFilter[];
|
|
75
|
+
requiredFactoryIntervals: IntervalWithFactory[];
|
|
76
|
+
syncStore: SyncStore;
|
|
77
|
+
}): Promise<SyncLog[]>;
|
|
78
|
+
/**
|
|
79
|
+
* Sync block data that must be queried for a single block (block, transactions, receipts, traces).
|
|
69
80
|
*/
|
|
70
|
-
|
|
81
|
+
syncBlockData(params: {
|
|
82
|
+
interval: Interval;
|
|
83
|
+
requiredIntervals: IntervalWithFilter[];
|
|
84
|
+
logs: SyncLog[];
|
|
85
|
+
syncStore: SyncStore;
|
|
86
|
+
}): Promise<SyncBlock | undefined>;
|
|
71
87
|
};
|
|
72
88
|
|
|
73
89
|
type CreateHistoricalSyncParameters = {
|
|
74
90
|
common: Common;
|
|
75
91
|
chain: Chain;
|
|
76
92
|
rpc: Rpc;
|
|
77
|
-
sources: Source[];
|
|
78
93
|
childAddresses: Map<FactoryId, Map<Address, number>>;
|
|
79
|
-
cachedIntervals: CachedIntervals;
|
|
80
|
-
syncStore: SyncStore;
|
|
81
94
|
};
|
|
82
95
|
|
|
83
96
|
export const createHistoricalSync = (
|
|
@@ -87,36 +100,6 @@ export const createHistoricalSync = (
|
|
|
87
100
|
* Flag to fetch transaction receipts through _eth_getBlockReceipts (true) or _eth_getTransactionReceipt (false)
|
|
88
101
|
*/
|
|
89
102
|
let isBlockReceipts = true;
|
|
90
|
-
/**
|
|
91
|
-
* Blocks that have already been extracted.
|
|
92
|
-
* Note: All entries are deleted at the end of each call to `sync()`.
|
|
93
|
-
*/
|
|
94
|
-
const blockCache = new Map<number, Promise<SyncBlock>>();
|
|
95
|
-
/**
|
|
96
|
-
* Traces that have already been fetched.
|
|
97
|
-
* Note: All entries are deleted at the end of each call to `sync()`.
|
|
98
|
-
*/
|
|
99
|
-
const traceCache = new Map<number, Promise<SyncTrace[]>>();
|
|
100
|
-
/**
|
|
101
|
-
* Transactions that should be saved to the sync-store.
|
|
102
|
-
* Note: All entries are deleted at the end of each call to `sync()`.
|
|
103
|
-
*/
|
|
104
|
-
const transactionsCache = new Set<Hash>();
|
|
105
|
-
/**
|
|
106
|
-
* Block transaction receipts that have already been fetched.
|
|
107
|
-
* Note: All entries are deleted at the end of each call to `sync()`.
|
|
108
|
-
*/
|
|
109
|
-
const blockReceiptsCache = new Map<Hash, Promise<SyncTransactionReceipt[]>>();
|
|
110
|
-
/**
|
|
111
|
-
* Transaction receipts that have already been fetched.
|
|
112
|
-
* Note: All entries are deleted at the end of each call to `sync()`.
|
|
113
|
-
*/
|
|
114
|
-
const transactionReceiptsCache = new Map<
|
|
115
|
-
Hash,
|
|
116
|
-
Promise<SyncTransactionReceipt>
|
|
117
|
-
>();
|
|
118
|
-
|
|
119
|
-
const childAddressesCache = new Map<LogFactory, Map<Address, number>>();
|
|
120
103
|
|
|
121
104
|
/**
|
|
122
105
|
* Data about the range passed to "eth_getLogs" share among all log
|
|
@@ -131,32 +114,28 @@ export const createHistoricalSync = (
|
|
|
131
114
|
estimatedRange: 500,
|
|
132
115
|
};
|
|
133
116
|
|
|
134
|
-
// Closest-to-tip block that has been synced.
|
|
135
|
-
let latestBlock: SyncBlock | undefined;
|
|
136
|
-
|
|
137
117
|
////////
|
|
138
118
|
// Helper functions for sync tasks
|
|
139
119
|
////////
|
|
140
120
|
|
|
121
|
+
type EthGetLogsParams = {
|
|
122
|
+
address: Address | Address[] | undefined;
|
|
123
|
+
topic0?: LogTopic;
|
|
124
|
+
topic1?: LogTopic;
|
|
125
|
+
topic2?: LogTopic;
|
|
126
|
+
topic3?: LogTopic;
|
|
127
|
+
interval: Interval;
|
|
128
|
+
};
|
|
129
|
+
|
|
141
130
|
/**
|
|
142
131
|
* Split "eth_getLogs" requests into ranges inferred from errors
|
|
143
132
|
* and batch requests.
|
|
144
133
|
*/
|
|
145
134
|
const syncLogsDynamic = async (
|
|
146
|
-
{
|
|
147
|
-
filter,
|
|
148
|
-
address,
|
|
149
|
-
interval,
|
|
150
|
-
}: {
|
|
151
|
-
filter: LogFilter | LogFactory;
|
|
152
|
-
interval: Interval;
|
|
153
|
-
/** Explicitly set because of the complexity of factory contracts. */
|
|
154
|
-
address: Address | Address[] | undefined;
|
|
155
|
-
},
|
|
135
|
+
{ address, topic0, topic1, topic2, topic3, interval }: EthGetLogsParams,
|
|
156
136
|
context?: Parameters<Rpc["request"]>[1],
|
|
157
137
|
): Promise<SyncLog[]> => {
|
|
158
|
-
//
|
|
159
|
-
|
|
138
|
+
// Use the recommended range if available, else don't chunk the interval at all.
|
|
160
139
|
const intervals = getChunks({
|
|
161
140
|
interval,
|
|
162
141
|
maxChunkSize:
|
|
@@ -164,15 +143,12 @@ export const createHistoricalSync = (
|
|
|
164
143
|
logsRequestMetadata.estimatedRange,
|
|
165
144
|
});
|
|
166
145
|
|
|
167
|
-
const topics =
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
filter.topic2 ?? null,
|
|
174
|
-
filter.topic3 ?? null,
|
|
175
|
-
];
|
|
146
|
+
const topics = [
|
|
147
|
+
topic0 ?? null,
|
|
148
|
+
topic1 ?? null,
|
|
149
|
+
topic2 ?? null,
|
|
150
|
+
topic3 ?? null,
|
|
151
|
+
];
|
|
176
152
|
|
|
177
153
|
// Note: the `topics` field is very fragile for many rpc providers, and
|
|
178
154
|
// cannot handle extra "null" topics
|
|
@@ -257,7 +233,10 @@ export const createHistoricalSync = (
|
|
|
257
233
|
: undefined,
|
|
258
234
|
};
|
|
259
235
|
|
|
260
|
-
return syncLogsDynamic(
|
|
236
|
+
return syncLogsDynamic(
|
|
237
|
+
{ address, topic0, topic1, topic2, topic3, interval },
|
|
238
|
+
context,
|
|
239
|
+
);
|
|
261
240
|
}),
|
|
262
241
|
),
|
|
263
242
|
),
|
|
@@ -277,66 +256,6 @@ export const createHistoricalSync = (
|
|
|
277
256
|
return logs;
|
|
278
257
|
};
|
|
279
258
|
|
|
280
|
-
/**
|
|
281
|
-
* Extract block, using `blockCache` to avoid fetching
|
|
282
|
-
* the same block twice. Also, update `latestBlock`.
|
|
283
|
-
*
|
|
284
|
-
* @param number Block to be extracted
|
|
285
|
-
*
|
|
286
|
-
* Note: This function could more accurately skip chain requests by taking
|
|
287
|
-
* advantage of `syncStore.hasBlock` and `syncStore.hasTransaction`.
|
|
288
|
-
*/
|
|
289
|
-
const syncBlock = async (
|
|
290
|
-
number: number,
|
|
291
|
-
context?: Parameters<Rpc["request"]>[1],
|
|
292
|
-
): Promise<SyncBlock> => {
|
|
293
|
-
let block: SyncBlock;
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* `blockCache` contains all blocks that have been extracted during the
|
|
297
|
-
* current call to `sync()`. If `number` is present in `blockCache` use it,
|
|
298
|
-
* otherwise, request the block and add it to `blockCache` and the sync-store.
|
|
299
|
-
*/
|
|
300
|
-
|
|
301
|
-
if (blockCache.has(number)) {
|
|
302
|
-
block = await blockCache.get(number)!;
|
|
303
|
-
} else {
|
|
304
|
-
const _block = _eth_getBlockByNumber(
|
|
305
|
-
args.rpc,
|
|
306
|
-
{ blockNumber: toHex(number) },
|
|
307
|
-
{ ...context, retryNullBlockRequest: true },
|
|
308
|
-
);
|
|
309
|
-
blockCache.set(number, _block);
|
|
310
|
-
block = await _block;
|
|
311
|
-
|
|
312
|
-
// Update `latestBlock` if `block` is closer to tip.
|
|
313
|
-
if (
|
|
314
|
-
hexToBigInt(block.number) >= hexToBigInt(latestBlock?.number ?? "0x0")
|
|
315
|
-
) {
|
|
316
|
-
latestBlock = block;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
return block;
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
const syncTrace = async (
|
|
324
|
-
block: number,
|
|
325
|
-
context?: Parameters<Rpc["request"]>[1],
|
|
326
|
-
) => {
|
|
327
|
-
if (traceCache.has(block)) {
|
|
328
|
-
return traceCache.get(block)!;
|
|
329
|
-
} else {
|
|
330
|
-
const traces = _debug_traceBlockByNumber(
|
|
331
|
-
args.rpc,
|
|
332
|
-
{ blockNumber: block },
|
|
333
|
-
context,
|
|
334
|
-
);
|
|
335
|
-
traceCache.set(block, traces);
|
|
336
|
-
return traces;
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
|
|
340
259
|
const syncTransactionReceipts = async (
|
|
341
260
|
block: SyncBlock,
|
|
342
261
|
transactionHashes: Set<Hash>,
|
|
@@ -349,7 +268,7 @@ export const createHistoricalSync = (
|
|
|
349
268
|
if (isBlockReceipts === false) {
|
|
350
269
|
const transactionReceipts = await Promise.all(
|
|
351
270
|
Array.from(transactionHashes).map((hash) =>
|
|
352
|
-
|
|
271
|
+
_eth_getTransactionReceipt(args.rpc, { hash }, context),
|
|
353
272
|
),
|
|
354
273
|
);
|
|
355
274
|
|
|
@@ -365,7 +284,11 @@ export const createHistoricalSync = (
|
|
|
365
284
|
|
|
366
285
|
let blockReceipts: SyncTransactionReceipt[];
|
|
367
286
|
try {
|
|
368
|
-
blockReceipts = await
|
|
287
|
+
blockReceipts = await _eth_getBlockReceipts(
|
|
288
|
+
args.rpc,
|
|
289
|
+
{ blockHash: block.hash },
|
|
290
|
+
context,
|
|
291
|
+
);
|
|
369
292
|
} catch (_error) {
|
|
370
293
|
const error = _error as Error;
|
|
371
294
|
args.common.logger.warn({
|
|
@@ -394,58 +317,26 @@ export const createHistoricalSync = (
|
|
|
394
317
|
return transactionReceipts;
|
|
395
318
|
};
|
|
396
319
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
const receipt = _eth_getTransactionReceipt(
|
|
405
|
-
args.rpc,
|
|
406
|
-
{ hash: transaction },
|
|
407
|
-
context,
|
|
408
|
-
);
|
|
409
|
-
transactionReceiptsCache.set(transaction, receipt);
|
|
410
|
-
return receipt;
|
|
411
|
-
}
|
|
412
|
-
};
|
|
413
|
-
|
|
414
|
-
const syncBlockReceipts = async (
|
|
415
|
-
block: SyncBlock,
|
|
416
|
-
context?: Parameters<Rpc["request"]>[1],
|
|
417
|
-
) => {
|
|
418
|
-
if (blockReceiptsCache.has(block.hash)) {
|
|
419
|
-
return blockReceiptsCache.get(block.hash)!;
|
|
420
|
-
} else {
|
|
421
|
-
const blockReceipts = _eth_getBlockReceipts(
|
|
422
|
-
args.rpc,
|
|
423
|
-
{ blockHash: block.hash },
|
|
424
|
-
context,
|
|
425
|
-
);
|
|
426
|
-
blockReceiptsCache.set(block.hash, blockReceipts);
|
|
427
|
-
return blockReceipts;
|
|
428
|
-
}
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
/** Extract and insert the log-based addresses that match `filter` + `interval`. */
|
|
432
|
-
const syncLogFactory = async (
|
|
433
|
-
factory: LogFactory,
|
|
320
|
+
/**
|
|
321
|
+
* Fetch child addresses for `factory` within `interval`
|
|
322
|
+
*
|
|
323
|
+
* @dev Newly fetched child addresses are added into `args.childAddresses`
|
|
324
|
+
*/
|
|
325
|
+
const syncAddressFactory = async (
|
|
326
|
+
factory: Factory,
|
|
434
327
|
interval: Interval,
|
|
435
328
|
context?: Parameters<Rpc["request"]>[1],
|
|
436
|
-
) => {
|
|
329
|
+
): Promise<Map<Address, number>> => {
|
|
437
330
|
const logs = await syncLogsDynamic(
|
|
438
331
|
{
|
|
439
|
-
filter: factory,
|
|
440
|
-
interval,
|
|
441
332
|
address: factory.address,
|
|
333
|
+
topic0: factory.eventSelector,
|
|
334
|
+
interval,
|
|
442
335
|
},
|
|
443
336
|
context,
|
|
444
337
|
);
|
|
445
338
|
|
|
446
|
-
const childAddresses =
|
|
447
|
-
childAddressesCache.get(factory) ?? new Map<Address, number>();
|
|
448
|
-
|
|
339
|
+
const childAddresses = new Map<Address, number>();
|
|
449
340
|
const childAddressesRecord = args.childAddresses.get(factory.id)!;
|
|
450
341
|
|
|
451
342
|
for (const log of logs) {
|
|
@@ -464,108 +355,160 @@ export const createHistoricalSync = (
|
|
|
464
355
|
}
|
|
465
356
|
}
|
|
466
357
|
|
|
467
|
-
|
|
468
|
-
// and not be a recovered factory from `recoverFilter`.
|
|
469
|
-
childAddressesCache.set(factory, childAddresses);
|
|
358
|
+
return childAddresses;
|
|
470
359
|
};
|
|
471
360
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
361
|
+
return {
|
|
362
|
+
async syncBlockRangeData({
|
|
363
|
+
interval,
|
|
364
|
+
requiredIntervals,
|
|
365
|
+
requiredFactoryIntervals,
|
|
366
|
+
syncStore,
|
|
367
|
+
}) {
|
|
368
|
+
const context = {
|
|
369
|
+
logger: args.common.logger.child({ action: "fetch_block_data" }),
|
|
370
|
+
};
|
|
371
|
+
const endClock = startClock();
|
|
372
|
+
const childAddresses: ChildAddresses = new Map();
|
|
373
|
+
const logs: SyncLog[] = [];
|
|
374
|
+
|
|
375
|
+
// Dedupe factory intervals by factory id
|
|
376
|
+
|
|
377
|
+
const factoryIntervalsById: Map<
|
|
378
|
+
Factory["id"],
|
|
379
|
+
{ factory: Factory; interval: Interval }
|
|
380
|
+
> = new Map();
|
|
381
|
+
|
|
382
|
+
for (const { factory, interval } of requiredFactoryIntervals) {
|
|
383
|
+
if (factoryIntervalsById.has(factory.id)) {
|
|
384
|
+
const existingInterval = factoryIntervalsById.get(
|
|
385
|
+
factory.id,
|
|
386
|
+
)!.interval;
|
|
387
|
+
|
|
388
|
+
factoryIntervalsById.get(factory.id)!.interval = intervalBounds([
|
|
389
|
+
existingInterval,
|
|
390
|
+
interval,
|
|
391
|
+
]);
|
|
392
|
+
} else {
|
|
393
|
+
factoryIntervalsById.set(factory.id, { factory, interval });
|
|
394
|
+
}
|
|
395
|
+
}
|
|
494
396
|
|
|
495
|
-
|
|
496
|
-
// Helper function for filter types
|
|
497
|
-
////////
|
|
397
|
+
requiredFactoryIntervals = Array.from(factoryIntervalsById.values());
|
|
498
398
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
const childAddresses = await syncAddressFactory(
|
|
507
|
-
filter.address,
|
|
508
|
-
interval,
|
|
509
|
-
context,
|
|
399
|
+
await Promise.all(
|
|
400
|
+
requiredFactoryIntervals.map(async ({ factory, interval }) => {
|
|
401
|
+
childAddresses.set(
|
|
402
|
+
factory.id,
|
|
403
|
+
await syncAddressFactory(factory, interval, context)!,
|
|
404
|
+
);
|
|
405
|
+
}),
|
|
510
406
|
);
|
|
511
407
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
408
|
+
const mergedEthGetLogsParams: Map<string, EthGetLogsParams> = new Map();
|
|
409
|
+
const singleEthGetLogsParams: EthGetLogsParams[] = [];
|
|
410
|
+
|
|
411
|
+
for (const { filter, interval } of requiredIntervals) {
|
|
412
|
+
if (filter.type !== "log") continue;
|
|
413
|
+
|
|
414
|
+
const hasAddress = filter.address !== undefined;
|
|
415
|
+
const hasTopic1 = filter.topic1 !== undefined;
|
|
416
|
+
const hasTopic2 = filter.topic2 !== undefined;
|
|
417
|
+
const hasTopic3 = filter.topic3 !== undefined;
|
|
418
|
+
|
|
419
|
+
if (hasAddress === false || hasTopic1 || hasTopic2 || hasTopic3) {
|
|
420
|
+
if (isAddressFactory(filter.address)) {
|
|
421
|
+
const childAddresses = args.childAddresses.get(filter.address.id)!;
|
|
422
|
+
singleEthGetLogsParams.push({
|
|
423
|
+
address:
|
|
424
|
+
childAddresses.size >=
|
|
425
|
+
args.common.options.factoryAddressCountThreshold
|
|
426
|
+
? undefined
|
|
427
|
+
: Array.from(childAddresses.keys()),
|
|
428
|
+
topic0: filter.topic0,
|
|
429
|
+
topic1: filter.topic1,
|
|
430
|
+
topic2: filter.topic2,
|
|
431
|
+
topic3: filter.topic3,
|
|
432
|
+
interval,
|
|
433
|
+
});
|
|
434
|
+
} else {
|
|
435
|
+
singleEthGetLogsParams.push({
|
|
436
|
+
address: filter.address,
|
|
437
|
+
topic0: filter.topic0,
|
|
438
|
+
topic1: filter.topic1,
|
|
439
|
+
topic2: filter.topic2,
|
|
440
|
+
topic3: filter.topic3,
|
|
441
|
+
interval,
|
|
442
|
+
});
|
|
443
|
+
}
|
|
527
444
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
address: log.address,
|
|
531
|
-
blockNumber: hexToNumber(log.blockNumber),
|
|
532
|
-
childAddresses,
|
|
533
|
-
}),
|
|
534
|
-
);
|
|
535
|
-
} else {
|
|
536
|
-
logs = await syncLogsDynamic(
|
|
537
|
-
{
|
|
538
|
-
filter,
|
|
539
|
-
interval,
|
|
540
|
-
address: filter.address,
|
|
541
|
-
},
|
|
542
|
-
context,
|
|
543
|
-
);
|
|
544
|
-
}
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
545
447
|
|
|
546
|
-
|
|
448
|
+
let addressKey: string;
|
|
449
|
+
if (isAddressFactory(filter.address)) {
|
|
450
|
+
addressKey = filter.address.id;
|
|
451
|
+
} else if (Array.isArray(filter.address)) {
|
|
452
|
+
addressKey = filter.address.join("_");
|
|
453
|
+
} else {
|
|
454
|
+
addressKey = filter.address as Address;
|
|
455
|
+
}
|
|
547
456
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
457
|
+
if (mergedEthGetLogsParams.has(addressKey) === false) {
|
|
458
|
+
if (isAddressFactory(filter.address)) {
|
|
459
|
+
const childAddresses = args.childAddresses.get(filter.address.id)!;
|
|
460
|
+
mergedEthGetLogsParams.set(addressKey, {
|
|
461
|
+
address:
|
|
462
|
+
childAddresses.size >=
|
|
463
|
+
args.common.options.factoryAddressCountThreshold
|
|
464
|
+
? undefined
|
|
465
|
+
: Array.from(childAddresses.keys()),
|
|
466
|
+
topic0: filter.topic0,
|
|
467
|
+
topic1: filter.topic1,
|
|
468
|
+
topic2: filter.topic2,
|
|
469
|
+
topic3: filter.topic3,
|
|
470
|
+
interval,
|
|
471
|
+
});
|
|
472
|
+
} else {
|
|
473
|
+
mergedEthGetLogsParams.set(addressKey, {
|
|
474
|
+
address: filter.address,
|
|
475
|
+
topic0: filter.topic0,
|
|
476
|
+
topic1: filter.topic1,
|
|
477
|
+
topic2: filter.topic2,
|
|
478
|
+
topic3: filter.topic3,
|
|
479
|
+
interval,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
} else {
|
|
483
|
+
const existingInterval =
|
|
484
|
+
mergedEthGetLogsParams.get(addressKey)!.interval;
|
|
485
|
+
const existingTopic0 = mergedEthGetLogsParams.get(addressKey)!
|
|
486
|
+
.topic0 as Hex | Hex[];
|
|
487
|
+
|
|
488
|
+
mergedEthGetLogsParams.get(addressKey)!.topic0 = [
|
|
489
|
+
...(Array.isArray(existingTopic0)
|
|
490
|
+
? existingTopic0
|
|
491
|
+
: [existingTopic0]),
|
|
492
|
+
filter.topic0,
|
|
493
|
+
];
|
|
494
|
+
mergedEthGetLogsParams.get(addressKey)!.interval = intervalBounds([
|
|
495
|
+
existingInterval,
|
|
496
|
+
interval,
|
|
497
|
+
]);
|
|
498
|
+
}
|
|
553
499
|
}
|
|
554
|
-
logsPerBlock.get(blockNumber)!.push(log);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
const blocks = await Promise.all(
|
|
558
|
-
Array.from(logsPerBlock.keys()).map((number) =>
|
|
559
|
-
syncBlock(number, context),
|
|
560
|
-
),
|
|
561
|
-
);
|
|
562
500
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
501
|
+
const ethGetLogsParams = [
|
|
502
|
+
...singleEthGetLogsParams,
|
|
503
|
+
...Array.from(mergedEthGetLogsParams.values()),
|
|
504
|
+
];
|
|
566
505
|
|
|
567
|
-
|
|
568
|
-
|
|
506
|
+
await Promise.all(
|
|
507
|
+
ethGetLogsParams.map(async (params) => {
|
|
508
|
+
const _logs = await syncLogsDynamic(params, context);
|
|
509
|
+
logs.push(..._logs);
|
|
510
|
+
}),
|
|
511
|
+
);
|
|
569
512
|
|
|
570
513
|
for (const log of logs) {
|
|
571
514
|
if (log.transactionHash === zeroHash) {
|
|
@@ -574,503 +517,424 @@ export const createHistoricalSync = (
|
|
|
574
517
|
action: "fetch_block_data",
|
|
575
518
|
chain: args.chain.name,
|
|
576
519
|
chain_id: args.chain.id,
|
|
577
|
-
number: hexToNumber(
|
|
578
|
-
hash:
|
|
520
|
+
number: hexToNumber(log.blockNumber),
|
|
521
|
+
hash: log.blockHash,
|
|
579
522
|
logIndex: hexToNumber(log.logIndex),
|
|
580
523
|
});
|
|
581
524
|
}
|
|
582
525
|
}
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
const transactionHashes = new Set(logs.map((l) => l.transactionHash));
|
|
586
|
-
for (const hash of transactionHashes) {
|
|
587
|
-
transactionsCache.add(hash);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (filter.hasTransactionReceipt) {
|
|
591
|
-
const transactionReceipts = await Promise.all(
|
|
592
|
-
blocks.map((block) => {
|
|
593
|
-
const blockTransactionHashes = new Set<Hash>();
|
|
594
|
-
|
|
595
|
-
for (const log of logsPerBlock.get(hexToNumber(block.number))!) {
|
|
596
|
-
if (log.transactionHash !== zeroHash) {
|
|
597
|
-
blockTransactionHashes.add(log.transactionHash);
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
526
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
);
|
|
606
|
-
}),
|
|
607
|
-
).then((receipts) => receipts.flat());
|
|
527
|
+
let childAddressCount = 0;
|
|
528
|
+
for (const { size } of childAddresses.values()) {
|
|
529
|
+
childAddressCount += size;
|
|
530
|
+
}
|
|
608
531
|
|
|
609
|
-
|
|
532
|
+
args.common.logger.debug(
|
|
610
533
|
{
|
|
611
|
-
|
|
612
|
-
|
|
534
|
+
msg: "Fetched block range data",
|
|
535
|
+
chain: args.chain.name,
|
|
536
|
+
chain_id: args.chain.id,
|
|
537
|
+
block_range: JSON.stringify(interval),
|
|
538
|
+
log_count: logs.length,
|
|
539
|
+
child_address_count: childAddressCount,
|
|
540
|
+
duration: endClock(),
|
|
613
541
|
},
|
|
614
|
-
|
|
542
|
+
["chain", "block_range"],
|
|
615
543
|
);
|
|
616
|
-
}
|
|
617
|
-
};
|
|
618
|
-
|
|
619
|
-
const syncBlockFilter = async (
|
|
620
|
-
filter: BlockFilter,
|
|
621
|
-
interval: Interval,
|
|
622
|
-
context?: Parameters<Rpc["request"]>[1],
|
|
623
|
-
) => {
|
|
624
|
-
const baseOffset = (interval[0] - filter.offset) % filter.interval;
|
|
625
|
-
const offset = baseOffset === 0 ? 0 : filter.interval - baseOffset;
|
|
626
|
-
|
|
627
|
-
// Determine which blocks are matched by the block filter.
|
|
628
|
-
const requiredBlocks: number[] = [];
|
|
629
|
-
for (let b = interval[0] + offset; b <= interval[1]; b += filter.interval) {
|
|
630
|
-
requiredBlocks.push(b);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
await Promise.all(
|
|
634
|
-
requiredBlocks.map(async (number) => {
|
|
635
|
-
const block = await syncBlock(number, context);
|
|
636
|
-
validateTransactionsAndBlock(block, "number");
|
|
637
|
-
return block;
|
|
638
|
-
}),
|
|
639
|
-
);
|
|
640
|
-
};
|
|
641
|
-
|
|
642
|
-
const syncTransactionFilter = async (
|
|
643
|
-
filter: TransactionFilter,
|
|
644
|
-
interval: Interval,
|
|
645
|
-
context?: Parameters<Rpc["request"]>[1],
|
|
646
|
-
) => {
|
|
647
|
-
const fromChildAddresses = isAddressFactory(filter.fromAddress)
|
|
648
|
-
? await syncAddressFactory(filter.fromAddress, interval, context)
|
|
649
|
-
: undefined;
|
|
650
|
-
|
|
651
|
-
const toChildAddresses = isAddressFactory(filter.toAddress)
|
|
652
|
-
? await syncAddressFactory(filter.toAddress, interval, context)
|
|
653
|
-
: undefined;
|
|
654
|
-
|
|
655
|
-
// Note: Exit early when only the factory needs to be synced
|
|
656
|
-
if ((filter.fromBlock ?? 0) > interval[1]) return;
|
|
657
544
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
545
|
+
await promiseAllSettledWithThrow(
|
|
546
|
+
Array.from(childAddresses.entries()).map(
|
|
547
|
+
([factoryId, childAddresses]) =>
|
|
548
|
+
syncStore.insertChildAddresses(
|
|
549
|
+
{
|
|
550
|
+
factory: factoryIntervalsById.get(factoryId)!.factory,
|
|
551
|
+
childAddresses,
|
|
552
|
+
chainId: args.chain.id,
|
|
553
|
+
},
|
|
554
|
+
context,
|
|
555
|
+
),
|
|
556
|
+
),
|
|
557
|
+
);
|
|
661
558
|
|
|
662
|
-
|
|
663
|
-
|
|
559
|
+
return logs;
|
|
560
|
+
},
|
|
561
|
+
async syncBlockData({ syncStore, interval, requiredIntervals, logs }) {
|
|
562
|
+
const context = {
|
|
563
|
+
logger: args.common.logger.child({ action: "fetch_block_data" }),
|
|
564
|
+
};
|
|
565
|
+
const endClock = startClock();
|
|
664
566
|
|
|
665
|
-
|
|
666
|
-
|
|
567
|
+
const blockFilters: BlockFilter[] = [];
|
|
568
|
+
const transactionFilters: TransactionFilter[] = [];
|
|
569
|
+
const traceFilters: TraceFilter[] = [];
|
|
570
|
+
const logFilters: LogFilter[] = [];
|
|
571
|
+
const transferFilters: TransferFilter[] = [];
|
|
667
572
|
|
|
668
|
-
for (const
|
|
669
|
-
|
|
670
|
-
|
|
573
|
+
for (const { filter } of requiredIntervals) {
|
|
574
|
+
switch (filter.type) {
|
|
575
|
+
case "block": {
|
|
576
|
+
blockFilters.push(filter as BlockFilter);
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
case "transaction": {
|
|
580
|
+
transactionFilters.push(filter as TransactionFilter);
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
case "trace": {
|
|
584
|
+
traceFilters.push(filter as TraceFilter);
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
case "log": {
|
|
588
|
+
logFilters.push(filter as LogFilter);
|
|
589
|
+
break;
|
|
590
|
+
}
|
|
591
|
+
case "transfer": {
|
|
592
|
+
transferFilters.push(filter as TransferFilter);
|
|
593
|
+
break;
|
|
594
|
+
}
|
|
671
595
|
}
|
|
596
|
+
}
|
|
672
597
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
childAddresses: fromChildAddresses!,
|
|
679
|
-
}) === false
|
|
680
|
-
) {
|
|
681
|
-
continue;
|
|
598
|
+
const perBlockLogs = new Map<number, SyncLog[]>();
|
|
599
|
+
for (const log of logs) {
|
|
600
|
+
const blockNumber = hexToNumber(log.blockNumber);
|
|
601
|
+
if (perBlockLogs.has(blockNumber) === false) {
|
|
602
|
+
perBlockLogs.set(blockNumber, []);
|
|
682
603
|
}
|
|
604
|
+
perBlockLogs.get(blockNumber)!.push(log);
|
|
605
|
+
}
|
|
683
606
|
|
|
684
|
-
|
|
685
|
-
isAddressFactory(filter.toAddress) &&
|
|
686
|
-
isAddressMatched({
|
|
687
|
-
address: transaction.to ?? undefined,
|
|
688
|
-
blockNumber: Number(block.number),
|
|
689
|
-
childAddresses: toChildAddresses!,
|
|
690
|
-
}) === false
|
|
691
|
-
) {
|
|
692
|
-
continue;
|
|
693
|
-
}
|
|
607
|
+
let closestToTipBlock: SyncBlock | undefined;
|
|
694
608
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
}
|
|
698
|
-
}
|
|
609
|
+
const syncBlockData = async (blockNumber: number) => {
|
|
610
|
+
let block: SyncBlock | undefined;
|
|
699
611
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
}
|
|
612
|
+
const requiredTransactions = new Set<Hash>();
|
|
613
|
+
const requiredTransactionReceipts = new Set<Hash>();
|
|
703
614
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
block.transactions
|
|
708
|
-
.filter((t) => transactionHashes.has(t.hash))
|
|
709
|
-
.map((t) => t.hash),
|
|
710
|
-
);
|
|
711
|
-
return syncTransactionReceipts(block, blockTransactionHashes, context);
|
|
712
|
-
}),
|
|
713
|
-
).then((receipts) => receipts.flat());
|
|
615
|
+
////////
|
|
616
|
+
// Logs
|
|
617
|
+
////////
|
|
714
618
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
};
|
|
619
|
+
let logs: SyncLog[] = [];
|
|
620
|
+
if (perBlockLogs.has(blockNumber)) {
|
|
621
|
+
block = await _eth_getBlockByNumber(
|
|
622
|
+
args.rpc,
|
|
623
|
+
{ blockNumber },
|
|
624
|
+
context,
|
|
625
|
+
);
|
|
723
626
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
trace: trace.trace,
|
|
752
|
-
block: { number: BigInt(number) },
|
|
753
|
-
}) === false
|
|
754
|
-
) {
|
|
755
|
-
return false;
|
|
756
|
-
}
|
|
627
|
+
logs = perBlockLogs.get(blockNumber)!.filter((log) => {
|
|
628
|
+
let isMatched = false;
|
|
629
|
+
|
|
630
|
+
for (const filter of logFilters) {
|
|
631
|
+
if (
|
|
632
|
+
isLogFilterMatched({ filter, log }) &&
|
|
633
|
+
(isAddressFactory(filter.address)
|
|
634
|
+
? isAddressMatched({
|
|
635
|
+
address: log.address,
|
|
636
|
+
blockNumber,
|
|
637
|
+
childAddresses: args.childAddresses.get(
|
|
638
|
+
filter.address.id,
|
|
639
|
+
)!,
|
|
640
|
+
})
|
|
641
|
+
: true)
|
|
642
|
+
) {
|
|
643
|
+
isMatched = true;
|
|
644
|
+
|
|
645
|
+
requiredTransactions.add(log.transactionHash);
|
|
646
|
+
if (filter.hasTransactionReceipt) {
|
|
647
|
+
requiredTransactionReceipts.add(log.transactionHash);
|
|
648
|
+
|
|
649
|
+
// skip to next log
|
|
650
|
+
break;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
757
654
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
isTransferFilterMatched({
|
|
761
|
-
filter,
|
|
762
|
-
trace: trace.trace,
|
|
763
|
-
block: { number: BigInt(number) },
|
|
764
|
-
}) === false
|
|
765
|
-
) {
|
|
766
|
-
return false;
|
|
767
|
-
}
|
|
655
|
+
return isMatched;
|
|
656
|
+
});
|
|
768
657
|
|
|
769
|
-
if (
|
|
770
|
-
|
|
771
|
-
isAddressMatched({
|
|
772
|
-
address: trace.trace.from,
|
|
773
|
-
blockNumber: number,
|
|
774
|
-
childAddresses: fromChildAddresses!,
|
|
775
|
-
}) === false
|
|
776
|
-
) {
|
|
777
|
-
return false;
|
|
658
|
+
if (logs.length > 0) {
|
|
659
|
+
validateLogsAndBlock(logs, block!, "number");
|
|
778
660
|
}
|
|
661
|
+
}
|
|
779
662
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
address: trace.trace.to,
|
|
784
|
-
blockNumber: number,
|
|
785
|
-
childAddresses: toChildAddresses!,
|
|
786
|
-
}) === false
|
|
787
|
-
) {
|
|
788
|
-
return false;
|
|
789
|
-
}
|
|
663
|
+
////////
|
|
664
|
+
// Traces
|
|
665
|
+
////////
|
|
790
666
|
|
|
791
|
-
|
|
792
|
-
|
|
667
|
+
const shouldRequestTraces =
|
|
668
|
+
traceFilters.some((filter) => isBlockInFilter(filter, blockNumber)) ||
|
|
669
|
+
transferFilters.some((filter) =>
|
|
670
|
+
isBlockInFilter(filter, blockNumber),
|
|
671
|
+
);
|
|
793
672
|
|
|
794
|
-
|
|
673
|
+
let traces: SyncTrace[] = [];
|
|
674
|
+
if (shouldRequestTraces) {
|
|
675
|
+
if (block === undefined) {
|
|
676
|
+
[block, traces] = await Promise.all([
|
|
677
|
+
_eth_getBlockByNumber(args.rpc, { blockNumber }, context),
|
|
678
|
+
_debug_traceBlockByNumber(args.rpc, { blockNumber }, context),
|
|
679
|
+
]);
|
|
680
|
+
} else {
|
|
681
|
+
traces = await _debug_traceBlockByNumber(
|
|
682
|
+
args.rpc,
|
|
683
|
+
{ blockNumber },
|
|
684
|
+
context,
|
|
685
|
+
);
|
|
686
|
+
}
|
|
795
687
|
|
|
796
|
-
|
|
688
|
+
traces = traces.filter((trace) => {
|
|
689
|
+
let isMatched = false;
|
|
690
|
+
for (const filter of transferFilters) {
|
|
691
|
+
if (
|
|
692
|
+
isTransferFilterMatched({
|
|
693
|
+
filter,
|
|
694
|
+
trace: trace.trace,
|
|
695
|
+
block: { number: BigInt(blockNumber) },
|
|
696
|
+
}) &&
|
|
697
|
+
(isAddressFactory(filter.fromAddress)
|
|
698
|
+
? isAddressMatched({
|
|
699
|
+
address: trace.trace.from,
|
|
700
|
+
blockNumber,
|
|
701
|
+
childAddresses: args.childAddresses.get(
|
|
702
|
+
filter.fromAddress.id,
|
|
703
|
+
)!,
|
|
704
|
+
})
|
|
705
|
+
: true) &&
|
|
706
|
+
(isAddressFactory(filter.toAddress)
|
|
707
|
+
? isAddressMatched({
|
|
708
|
+
address: trace.trace.to,
|
|
709
|
+
blockNumber,
|
|
710
|
+
childAddresses: args.childAddresses.get(
|
|
711
|
+
filter.toAddress.id,
|
|
712
|
+
)!,
|
|
713
|
+
})
|
|
714
|
+
: true)
|
|
715
|
+
) {
|
|
716
|
+
isMatched = true;
|
|
717
|
+
requiredTransactions.add(trace.transactionHash);
|
|
718
|
+
if (filter.hasTransactionReceipt) {
|
|
719
|
+
requiredTransactionReceipts.add(trace.transactionHash);
|
|
720
|
+
// skip to next trace
|
|
721
|
+
break;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
797
725
|
|
|
798
|
-
|
|
799
|
-
|
|
726
|
+
for (const filter of traceFilters) {
|
|
727
|
+
if (
|
|
728
|
+
isTraceFilterMatched({
|
|
729
|
+
filter,
|
|
730
|
+
trace: trace.trace,
|
|
731
|
+
block: { number: BigInt(blockNumber) },
|
|
732
|
+
}) &&
|
|
733
|
+
(isAddressFactory(filter.fromAddress)
|
|
734
|
+
? isAddressMatched({
|
|
735
|
+
address: trace.trace.from,
|
|
736
|
+
blockNumber,
|
|
737
|
+
childAddresses: args.childAddresses.get(
|
|
738
|
+
filter.fromAddress.id,
|
|
739
|
+
)!,
|
|
740
|
+
})
|
|
741
|
+
: true) &&
|
|
742
|
+
(isAddressFactory(filter.toAddress)
|
|
743
|
+
? isAddressMatched({
|
|
744
|
+
address: trace.trace.to,
|
|
745
|
+
blockNumber,
|
|
746
|
+
childAddresses: args.childAddresses.get(
|
|
747
|
+
filter.toAddress.id,
|
|
748
|
+
)!,
|
|
749
|
+
})
|
|
750
|
+
: true)
|
|
751
|
+
) {
|
|
752
|
+
isMatched = true;
|
|
753
|
+
requiredTransactions.add(trace.transactionHash);
|
|
754
|
+
if (filter.hasTransactionReceipt) {
|
|
755
|
+
requiredTransactionReceipts.add(trace.transactionHash);
|
|
756
|
+
// skip to next trace
|
|
757
|
+
break;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
800
761
|
|
|
801
|
-
|
|
762
|
+
return isMatched;
|
|
763
|
+
});
|
|
802
764
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
765
|
+
if (traces.length > 0) {
|
|
766
|
+
validateTracesAndBlock(traces, block, "number");
|
|
767
|
+
}
|
|
806
768
|
}
|
|
807
769
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
return { trace, transaction, block };
|
|
813
|
-
});
|
|
814
|
-
}),
|
|
815
|
-
).then((traces) => traces.flat());
|
|
816
|
-
|
|
817
|
-
await args.syncStore.insertTraces(
|
|
818
|
-
{
|
|
819
|
-
traces,
|
|
820
|
-
chainId: args.chain.id,
|
|
821
|
-
},
|
|
822
|
-
context,
|
|
823
|
-
);
|
|
770
|
+
////////
|
|
771
|
+
// Block
|
|
772
|
+
////////
|
|
824
773
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
)
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
774
|
+
if (
|
|
775
|
+
block === undefined &&
|
|
776
|
+
blockFilters.some((filter) =>
|
|
777
|
+
isBlockFilterMatched({
|
|
778
|
+
filter,
|
|
779
|
+
block: { number: BigInt(blockNumber) },
|
|
780
|
+
}),
|
|
781
|
+
)
|
|
782
|
+
) {
|
|
783
|
+
block = await _eth_getBlockByNumber(
|
|
784
|
+
args.rpc,
|
|
785
|
+
{ blockNumber },
|
|
836
786
|
context,
|
|
837
787
|
);
|
|
838
|
-
}),
|
|
839
|
-
).then((receipts) => receipts.flat());
|
|
840
|
-
|
|
841
|
-
await args.syncStore.insertTransactionReceipts(
|
|
842
|
-
{
|
|
843
|
-
transactionReceipts,
|
|
844
|
-
chainId: args.chain.id,
|
|
845
|
-
},
|
|
846
|
-
context,
|
|
847
|
-
);
|
|
848
|
-
}
|
|
849
|
-
};
|
|
850
|
-
|
|
851
|
-
return {
|
|
852
|
-
async sync(_interval) {
|
|
853
|
-
const context = {
|
|
854
|
-
logger: args.common.logger.child({ action: "fetch_block_data" }),
|
|
855
|
-
};
|
|
856
|
-
const endClock = startClock();
|
|
857
|
-
|
|
858
|
-
const intervalsToSync: {
|
|
859
|
-
interval: Interval;
|
|
860
|
-
filter: FilterWithoutBlocks;
|
|
861
|
-
}[] = [];
|
|
862
|
-
|
|
863
|
-
// Determine the requests that need to be made, and which intervals need to be inserted.
|
|
864
|
-
// Fragments are used to create a minimal filter, to avoid refetching data even if a filter
|
|
865
|
-
// is only partially synced.
|
|
866
|
-
|
|
867
|
-
for (const { filter } of args.sources) {
|
|
868
|
-
let filterIntervals: Interval[] = [
|
|
869
|
-
[
|
|
870
|
-
Math.max(filter.fromBlock ?? 0, _interval[0]),
|
|
871
|
-
Math.min(filter.toBlock ?? Number.POSITIVE_INFINITY, _interval[1]),
|
|
872
|
-
],
|
|
873
|
-
];
|
|
874
|
-
|
|
875
|
-
switch (filter.type) {
|
|
876
|
-
case "log":
|
|
877
|
-
if (isAddressFactory(filter.address)) {
|
|
878
|
-
filterIntervals.push([
|
|
879
|
-
Math.max(filter.address.fromBlock ?? 0, _interval[0]),
|
|
880
|
-
Math.min(
|
|
881
|
-
filter.address.toBlock ?? Number.POSITIVE_INFINITY,
|
|
882
|
-
_interval[1],
|
|
883
|
-
),
|
|
884
|
-
]);
|
|
885
|
-
}
|
|
886
|
-
break;
|
|
887
|
-
case "trace":
|
|
888
|
-
case "transaction":
|
|
889
|
-
case "transfer":
|
|
890
|
-
if (isAddressFactory(filter.fromAddress)) {
|
|
891
|
-
filterIntervals.push([
|
|
892
|
-
Math.max(filter.fromAddress.fromBlock ?? 0, _interval[0]),
|
|
893
|
-
Math.min(
|
|
894
|
-
filter.fromAddress.toBlock ?? Number.POSITIVE_INFINITY,
|
|
895
|
-
_interval[1],
|
|
896
|
-
),
|
|
897
|
-
]);
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
if (isAddressFactory(filter.toAddress)) {
|
|
901
|
-
filterIntervals.push([
|
|
902
|
-
Math.max(filter.toAddress.fromBlock ?? 0, _interval[0]),
|
|
903
|
-
Math.min(
|
|
904
|
-
filter.toAddress.toBlock ?? Number.POSITIVE_INFINITY,
|
|
905
|
-
_interval[1],
|
|
906
|
-
),
|
|
907
|
-
]);
|
|
908
|
-
}
|
|
909
788
|
}
|
|
910
789
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
790
|
+
////////
|
|
791
|
+
// Transactions
|
|
792
|
+
////////
|
|
914
793
|
|
|
915
|
-
if
|
|
916
|
-
|
|
794
|
+
// Return early if no data is fetched
|
|
795
|
+
if (
|
|
796
|
+
block === undefined &&
|
|
797
|
+
transactionFilters.some((filter) =>
|
|
798
|
+
isBlockInFilter(filter, blockNumber),
|
|
799
|
+
) === false
|
|
800
|
+
) {
|
|
801
|
+
return;
|
|
917
802
|
}
|
|
918
803
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
intervals: Interval[];
|
|
925
|
-
}[] = [];
|
|
926
|
-
|
|
927
|
-
for (const {
|
|
928
|
-
fragment,
|
|
929
|
-
intervals: fragmentIntervals,
|
|
930
|
-
} of completedIntervals) {
|
|
931
|
-
const requiredFragmentIntervals = intervalDifference(
|
|
932
|
-
filterIntervals,
|
|
933
|
-
fragmentIntervals,
|
|
804
|
+
if (block === undefined) {
|
|
805
|
+
block = await _eth_getBlockByNumber(
|
|
806
|
+
args.rpc,
|
|
807
|
+
{ blockNumber },
|
|
808
|
+
context,
|
|
934
809
|
);
|
|
810
|
+
}
|
|
935
811
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
}
|
|
812
|
+
if (
|
|
813
|
+
closestToTipBlock === undefined ||
|
|
814
|
+
hexToNumber(block.number) > hexToNumber(closestToTipBlock.number)
|
|
815
|
+
) {
|
|
816
|
+
closestToTipBlock = block;
|
|
942
817
|
}
|
|
943
818
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
819
|
+
const transactions = block.transactions.filter((transaction) => {
|
|
820
|
+
let isMatched = requiredTransactions.has(transaction.hash);
|
|
821
|
+
for (const filter of transactionFilters) {
|
|
822
|
+
if (
|
|
823
|
+
isTransactionFilterMatched({ filter, transaction }) &&
|
|
824
|
+
(isAddressFactory(filter.fromAddress)
|
|
825
|
+
? isAddressMatched({
|
|
826
|
+
address: transaction.from,
|
|
827
|
+
blockNumber,
|
|
828
|
+
childAddresses: args.childAddresses.get(
|
|
829
|
+
filter.fromAddress.id,
|
|
830
|
+
)!,
|
|
831
|
+
})
|
|
832
|
+
: true) &&
|
|
833
|
+
(isAddressFactory(filter.toAddress)
|
|
834
|
+
? isAddressMatched({
|
|
835
|
+
address: transaction.to ?? undefined,
|
|
836
|
+
blockNumber,
|
|
837
|
+
childAddresses: args.childAddresses.get(
|
|
838
|
+
filter.toAddress.id,
|
|
839
|
+
)!,
|
|
840
|
+
})
|
|
841
|
+
: true)
|
|
842
|
+
) {
|
|
843
|
+
requiredTransactionReceipts.add(transaction.hash);
|
|
844
|
+
isMatched = true;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
return isMatched;
|
|
848
|
+
});
|
|
948
849
|
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
);
|
|
850
|
+
if (transactions.length > 0) {
|
|
851
|
+
validateTransactionsAndBlock(block, "number");
|
|
852
|
+
}
|
|
953
853
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
});
|
|
854
|
+
const transactionsByHash = new Map<Hash, SyncTransaction>();
|
|
855
|
+
for (const transaction of transactions) {
|
|
856
|
+
transactionsByHash.set(transaction.hash, transaction);
|
|
958
857
|
}
|
|
959
|
-
}
|
|
960
858
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
const blockPromise = syncBlock(interval[1], context);
|
|
965
|
-
|
|
966
|
-
switch (filter.type) {
|
|
967
|
-
case "log": {
|
|
968
|
-
await syncLogFilter(filter as LogFilter, interval, context);
|
|
969
|
-
break;
|
|
970
|
-
}
|
|
859
|
+
////////
|
|
860
|
+
// Transaction Receipts
|
|
861
|
+
////////
|
|
971
862
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
863
|
+
const transactionReceipts = await syncTransactionReceipts(
|
|
864
|
+
block,
|
|
865
|
+
requiredTransactionReceipts,
|
|
866
|
+
);
|
|
976
867
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
context,
|
|
982
|
-
);
|
|
983
|
-
break;
|
|
984
|
-
}
|
|
868
|
+
blockCount += 1;
|
|
869
|
+
transactionCount += transactions.length;
|
|
870
|
+
receiptCount += transactionReceipts.length;
|
|
871
|
+
traceCount += traces.length;
|
|
985
872
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
await syncTraceOrTransferFilter(
|
|
989
|
-
filter as TraceFilter | TransferFilter,
|
|
990
|
-
interval,
|
|
991
|
-
context,
|
|
992
|
-
);
|
|
993
|
-
break;
|
|
994
|
-
}
|
|
995
|
-
}
|
|
873
|
+
// Free memory of all unused transactions
|
|
874
|
+
block.transactions = transactions;
|
|
996
875
|
|
|
997
|
-
|
|
998
|
-
|
|
876
|
+
await promiseAllSettledWithThrow([
|
|
877
|
+
syncStore.insertBlocks({ blocks: [block], chainId: args.chain.id }),
|
|
878
|
+
syncStore.insertTransactions({
|
|
879
|
+
transactions,
|
|
880
|
+
chainId: args.chain.id,
|
|
881
|
+
}),
|
|
882
|
+
syncStore.insertTransactionReceipts({
|
|
883
|
+
transactionReceipts,
|
|
884
|
+
chainId: args.chain.id,
|
|
885
|
+
}),
|
|
886
|
+
syncStore.insertTraces({
|
|
887
|
+
traces: traces.map((trace) => ({
|
|
888
|
+
trace,
|
|
889
|
+
block: block!,
|
|
890
|
+
transaction: transactionsByHash.get(trace.transactionHash)!,
|
|
891
|
+
})),
|
|
892
|
+
chainId: args.chain.id,
|
|
893
|
+
}),
|
|
894
|
+
syncStore.insertLogs({ logs, chainId: args.chain.id }),
|
|
895
|
+
]);
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
let blockCount = 0;
|
|
899
|
+
let transactionCount = 0;
|
|
900
|
+
let receiptCount = 0;
|
|
901
|
+
let traceCount = 0;
|
|
902
|
+
|
|
903
|
+
// Same memory usage as `sync-realtime`.
|
|
904
|
+
const MAX_BLOCKS_IN_MEM = Math.max(
|
|
905
|
+
args.chain.finalityBlockCount * 2,
|
|
906
|
+
100,
|
|
999
907
|
);
|
|
1000
908
|
|
|
1001
|
-
|
|
909
|
+
if (requiredIntervals.length > 0) {
|
|
910
|
+
const queue = createQueue({
|
|
911
|
+
browser: false,
|
|
912
|
+
initialStart: true,
|
|
913
|
+
concurrency: MAX_BLOCKS_IN_MEM,
|
|
914
|
+
worker: syncBlockData,
|
|
915
|
+
});
|
|
1002
916
|
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
{ blocks, chainId: args.chain.id },
|
|
1006
|
-
context,
|
|
1007
|
-
),
|
|
1008
|
-
args.syncStore.insertTransactions(
|
|
1009
|
-
{
|
|
1010
|
-
transactions: blocks.flatMap((block) =>
|
|
1011
|
-
block.transactions.filter(({ hash }) =>
|
|
1012
|
-
transactionsCache.has(hash),
|
|
1013
|
-
),
|
|
1014
|
-
),
|
|
1015
|
-
chainId: args.chain.id,
|
|
1016
|
-
},
|
|
1017
|
-
context,
|
|
1018
|
-
),
|
|
1019
|
-
...Array.from(childAddressesCache.entries()).map(
|
|
1020
|
-
([factory, childAddresses]) =>
|
|
1021
|
-
args.syncStore.insertChildAddresses(
|
|
1022
|
-
{
|
|
1023
|
-
factory,
|
|
1024
|
-
childAddresses,
|
|
1025
|
-
chainId: args.chain.id,
|
|
1026
|
-
},
|
|
1027
|
-
context,
|
|
1028
|
-
),
|
|
1029
|
-
),
|
|
1030
|
-
]);
|
|
1031
|
-
|
|
1032
|
-
// Add corresponding intervals to the sync-store
|
|
1033
|
-
// Note: this should happen after so the database doesn't become corrupted
|
|
1034
|
-
if (args.chain.disableCache === false) {
|
|
1035
|
-
await args.syncStore.insertIntervals(
|
|
1036
|
-
{
|
|
1037
|
-
intervals: intervalsToSync,
|
|
1038
|
-
chainId: args.chain.id,
|
|
1039
|
-
},
|
|
1040
|
-
context,
|
|
917
|
+
await Promise.all(
|
|
918
|
+
intervalRange(interval).map((blockNumber) => queue.add(blockNumber)),
|
|
1041
919
|
);
|
|
1042
920
|
}
|
|
1043
921
|
|
|
1044
|
-
let childAddressCount = 0;
|
|
1045
|
-
for (const childAddresses of childAddressesCache.values()) {
|
|
1046
|
-
childAddressCount += childAddresses.size;
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
922
|
args.common.logger.debug(
|
|
1050
923
|
{
|
|
1051
924
|
msg: "Fetched block data",
|
|
1052
925
|
chain: args.chain.name,
|
|
1053
926
|
chain_id: args.chain.id,
|
|
1054
|
-
block_range: JSON.stringify(
|
|
1055
|
-
block_count:
|
|
1056
|
-
transaction_count:
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
trace_count: traceCache.size,
|
|
1060
|
-
child_address_count: childAddressCount,
|
|
927
|
+
block_range: JSON.stringify(interval),
|
|
928
|
+
block_count: blockCount,
|
|
929
|
+
transaction_count: transactionCount,
|
|
930
|
+
receipt_count: receiptCount,
|
|
931
|
+
trace_count: traceCount,
|
|
1061
932
|
duration: endClock(),
|
|
1062
933
|
},
|
|
1063
934
|
["chain", "block_range"],
|
|
1064
935
|
);
|
|
1065
936
|
|
|
1066
|
-
|
|
1067
|
-
traceCache.clear();
|
|
1068
|
-
transactionsCache.clear();
|
|
1069
|
-
blockReceiptsCache.clear();
|
|
1070
|
-
transactionReceiptsCache.clear();
|
|
1071
|
-
childAddressesCache.clear();
|
|
1072
|
-
|
|
1073
|
-
return latestBlock;
|
|
937
|
+
return closestToTipBlock;
|
|
1074
938
|
},
|
|
1075
939
|
};
|
|
1076
940
|
};
|