@subsquid/batch-processor 0.1.0 → 0.2.0-portal-api.b88e99

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/lib/database.d.ts CHANGED
@@ -10,9 +10,11 @@ export interface FinalTxInfo {
10
10
  }
11
11
  export interface FinalDatabase<S> {
12
12
  supportsHotBlocks?: false;
13
- connect(): Promise<HashAndHeight>;
13
+ connect(): Promise<FinalDatabaseState>;
14
14
  transact(info: FinalTxInfo, cb: (store: S) => Promise<void>): Promise<void>;
15
15
  }
16
+ export interface FinalDatabaseState extends HashAndHeight {
17
+ }
16
18
  export interface HotTxInfo {
17
19
  finalizedHead: HashAndHeight;
18
20
  baseHead: HashAndHeight;
@@ -22,11 +24,7 @@ export interface HotDatabase<S> {
22
24
  supportsHotBlocks: true;
23
25
  connect(): Promise<HotDatabaseState>;
24
26
  transact(info: FinalTxInfo, cb: (store: S) => Promise<void>): Promise<void>;
25
- /**
26
- * @deprecated
27
- */
28
- transactHot(info: HotTxInfo, cb: (store: S, block: HashAndHeight) => Promise<void>): Promise<void>;
29
- transactHot2?(info: HotTxInfo, cb: (store: S, blockSliceStart: number, blockSliceEnd: number) => Promise<void>): Promise<void>;
27
+ transactHot2(info: HotTxInfo, cb: (store: S, blockSliceStart: number, blockSliceEnd: number) => Promise<void>): Promise<void>;
30
28
  }
31
29
  export interface HotDatabaseState extends HashAndHeight {
32
30
  top: HashAndHeight[];
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;AAG3D,MAAM,WAAW,WAAW;IACxB,QAAQ,EAAE,aAAa,CAAA;IACvB,QAAQ,EAAE,aAAa,CAAA;IACvB,OAAO,EAAE,OAAO,CAAA;CACnB;AAGD,MAAM,WAAW,aAAa,CAAC,CAAC;IAC5B,iBAAiB,CAAC,EAAE,KAAK,CAAA;IACzB,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC,CAAA;IACjC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9E;AAGD,MAAM,WAAW,SAAS;IACtB,aAAa,EAAE,aAAa,CAAA;IAC5B,QAAQ,EAAE,aAAa,CAAA;IACvB,SAAS,EAAE,aAAa,EAAE,CAAA;CAC7B;AAGD,MAAM,WAAW,WAAW,CAAC,CAAC;IAC1B,iBAAiB,EAAE,IAAI,CAAA;IACvB,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3E;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAElG,YAAY,CAAC,CACT,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAChF,OAAO,CAAC,IAAI,CAAC,CAAA;CACnB;AAGD,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACnD,GAAG,EAAE,aAAa,EAAE,CAAA;CACvB;AAGD,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;CACf"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;AAG3D,MAAM,WAAW,WAAW;IACxB,QAAQ,EAAE,aAAa,CAAA;IACvB,QAAQ,EAAE,aAAa,CAAA;IACvB,OAAO,EAAE,OAAO,CAAA;CACnB;AAGD,MAAM,WAAW,aAAa,CAAC,CAAC;IAC5B,iBAAiB,CAAC,EAAE,KAAK,CAAA;IACzB,OAAO,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACtC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9E;AAGD,MAAM,WAAW,kBAAmB,SAAQ,aAAa;CAAG;AAG5D,MAAM,WAAW,SAAS;IACtB,aAAa,EAAE,aAAa,CAAA;IAC5B,QAAQ,EAAE,aAAa,CAAA;IACvB,SAAS,EAAE,aAAa,EAAE,CAAA;CAC7B;AAGD,MAAM,WAAW,WAAW,CAAC,CAAC;IAC1B,iBAAiB,EAAE,IAAI,CAAA;IACvB,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3E,YAAY,CACR,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAChF,OAAO,CAAC,IAAI,CAAC,CAAA;CACnB;AAGD,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACnD,GAAG,EAAE,aAAa,EAAE,CAAA;CACvB;AAGD,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;CACf"}
package/lib/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export * from './database';
2
- export * from './datasource';
3
2
  export * from './run';
4
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,OAAO,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,OAAO,CAAA"}
package/lib/index.js CHANGED
@@ -15,6 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./database"), exports);
18
- __exportStar(require("./datasource"), exports);
19
18
  __exportStar(require("./run"), exports);
20
19
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA0B;AAC1B,+CAA4B;AAC5B,wCAAqB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA0B;AAC1B,wCAAqB"}
package/lib/run.d.ts CHANGED
@@ -1,6 +1,6 @@
1
+ import { Database } from './database';
2
+ import { DataSource, BlockRef } from '@subsquid/util-internal-data-source';
1
3
  import { PrometheusServer } from '@subsquid/util-internal-processor-tools';
2
- import { Database, HashAndHeight } from './database';
3
- import { DataSource } from './datasource';
4
4
  export { PrometheusServer };
5
5
  export interface DataHandlerContext<Block, Store> {
6
6
  /**
@@ -16,8 +16,8 @@ export interface DataHandlerContext<Block, Store> {
16
16
  */
17
17
  isHead: boolean;
18
18
  }
19
- interface BlockBase {
20
- header: HashAndHeight;
19
+ export interface BlockBase {
20
+ header: BlockRef;
21
21
  }
22
22
  interface RunOptions {
23
23
  prometheus?: PrometheusServer;
package/lib/run.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,gBAAgB,EAAgB,MAAM,yCAAyC,CAAA;AACvF,OAAO,EAAC,QAAQ,EAAE,aAAa,EAAC,MAAM,YAAY,CAAA;AAClD,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AAGvC,OAAO,EAAC,gBAAgB,EAAC,CAAA;AAMzB,MAAM,WAAW,kBAAkB,CAAC,KAAK,EAAE,KAAK;IAC5C;;OAEG;IACH,KAAK,EAAE,KAAK,CAAA;IACZ;;OAEG;IACH,MAAM,EAAE,KAAK,EAAE,CAAA;IACf;;OAEG;IACH,MAAM,EAAE,OAAO,CAAA;CAClB;AAGD,UAAU,SAAS;IACf,MAAM,EAAE,aAAa,CAAA;CACxB;AAED,UAAU,UAAU;IAChB,UAAU,CAAC,EAAE,gBAAgB,CAAA;CAChC;AAGD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,GAAG,CAAC,KAAK,SAAS,SAAS,EAAE,KAAK,EAC9C,GAAG,EAAE,UAAU,CAAC,KAAK,CAAC,EACtB,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,EACnB,WAAW,EAAE,CAAC,GAAG,EAAE,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,EACrE,IAAI,CAAC,EAAE,UAAU,GAClB,IAAI,CAMN"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,QAAQ,EAAC,MAAM,YAAY,CAAA;AAClD,OAAO,EAAC,UAAU,EAAmB,QAAQ,EAAkB,MAAM,qCAAqC,CAAA;AAE1G,OAAO,EAAC,gBAAgB,EAAgB,MAAM,yCAAyC,CAAA;AAIvF,OAAO,EAAC,gBAAgB,EAAC,CAAA;AAKzB,MAAM,WAAW,kBAAkB,CAAC,KAAK,EAAE,KAAK;IAC5C;;OAEG;IACH,KAAK,EAAE,KAAK,CAAA;IACZ;;OAEG;IACH,MAAM,EAAE,KAAK,EAAE,CAAA;IACf;;OAEG;IACH,MAAM,EAAE,OAAO,CAAA;CAClB;AAGD,MAAM,WAAW,SAAS;IACtB,MAAM,EAAE,QAAQ,CAAA;CACnB;AASD,UAAU,UAAU;IAChB,UAAU,CAAC,EAAE,gBAAgB,CAAA;CAChC;AAGD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,GAAG,CAAC,KAAK,SAAS,SAAS,EAAE,KAAK,EAC9C,GAAG,EAAE,UAAU,CAAC,KAAK,CAAC,EACtB,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,EACnB,WAAW,EAAE,CAAC,GAAG,EAAE,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,EACrE,IAAI,CAAC,EAAE,UAAU,GAClB,IAAI,CAMN"}
package/lib/run.js CHANGED
@@ -1,9 +1,14 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.PrometheusServer = void 0;
4
7
  exports.run = run;
5
8
  const logger_1 = require("@subsquid/logger");
6
9
  const util_internal_1 = require("@subsquid/util-internal");
10
+ const util_internal_data_source_1 = require("@subsquid/util-internal-data-source");
11
+ const assert_1 = __importDefault(require("assert"));
7
12
  const util_internal_processor_tools_1 = require("@subsquid/util-internal-processor-tools");
8
13
  Object.defineProperty(exports, "PrometheusServer", { enumerable: true, get: function () { return util_internal_processor_tools_1.PrometheusServer; } });
9
14
  const util_1 = require("./util");
@@ -37,32 +42,63 @@ class Processor {
37
42
  this.opts = opts;
38
43
  this.hasStatusNews = false;
39
44
  this.metrics = new util_internal_processor_tools_1.RunnerMetrics(src.getBlocksCountInRange?.bind(src) ?? ((range) => Math.max(0, range.to - range.from + 1)));
40
- this.chainHeight = new util_internal_1.Throttler(() => this.src.getFinalizedHeight(), 30000);
41
45
  }
42
46
  async run() {
43
- let state = await this.db.connect();
44
- if (state.height >= 0) {
45
- log.info(`last processed final block was ${state.height}`);
46
- }
47
- await this.assertWeAreOnTheSameChain(state);
48
- await this.initMetrics(state);
49
- for await (let blocks of this.src.getBlockStream(state.height + 1)) {
50
- if (blocks.length > 0) {
51
- state = await this.processBatch(state, blocks);
47
+ let getHead = this.db.supportsHotBlocks ? this.src.getHead.bind(this.src) : this.src.getFinalizedHead.bind(this.src);
48
+ let chainHeight = new util_internal_1.Throttler(() => getHead()?.then((r) => r?.number ?? -1), 10000);
49
+ let state = {
50
+ finalizedHead: undefined,
51
+ unfinalizedHeads: [],
52
+ };
53
+ if (this.db.supportsHotBlocks) {
54
+ let dbState = await this.db.connect();
55
+ state.finalizedHead = dbState.height < 0 ? undefined : toBlockRef(dbState);
56
+ state.unfinalizedHeads = dbState.top.map(toBlockRef);
57
+ }
58
+ else {
59
+ let dbState = await this.db.connect();
60
+ state.finalizedHead = dbState.height < 0 ? undefined : toBlockRef(dbState);
61
+ }
62
+ let head = getStateHead(state);
63
+ if (head != null) {
64
+ log.info(`last processed block was ${head.number}`);
65
+ }
66
+ await this.initMetrics(head?.number ?? -1, await chainHeight.get());
67
+ while (true) {
68
+ let getStream = this.db.supportsHotBlocks
69
+ ? this.src.getStream.bind(this.src)
70
+ : this.src.getFinalizedStream.bind(this.src);
71
+ head = getStateHead(state);
72
+ try {
73
+ for await (let data of getStream({ after: head })) {
74
+ state = await this.processBatch(state, data, await chainHeight.get());
75
+ }
76
+ break; // Stream completed successfully, exit loop
77
+ }
78
+ catch (e) {
79
+ if (!(0, util_internal_data_source_1.isForkException)(e) || !this.db.supportsHotBlocks)
80
+ throw e;
81
+ // Handle fork and continue loop to retry
82
+ let chain = state.finalizedHead
83
+ ? [state.finalizedHead, ...state.unfinalizedHeads]
84
+ : state.unfinalizedHeads;
85
+ let rollbackIndex = findRollbackIndex(chain, e.previousBlocks);
86
+ if (rollbackIndex === -1) {
87
+ if (state.finalizedHead != null)
88
+ throw new Error('Unable to process fork');
89
+ state.unfinalizedHeads = [];
90
+ }
91
+ else {
92
+ const rollbackHead = chain[rollbackIndex];
93
+ log.info(`navigating a fork on a common base ${(0, util_1.formatHead)(rollbackHead)}`);
94
+ state.unfinalizedHeads = chain.slice(1, rollbackIndex + 1);
95
+ }
52
96
  }
53
97
  }
54
98
  this.reportFinalStatus();
55
99
  }
56
- async assertWeAreOnTheSameChain(state) {
57
- if (state.height < 0)
58
- return;
59
- let hash = await this.src.getBlockHash(state.height);
60
- if (state.hash === hash)
61
- return;
62
- throw new Error(`already indexed block ${(0, util_1.formatHead)(state)} was not found on chain`);
63
- }
64
- async initMetrics(state) {
65
- this.updateProgressMetrics(await this.chainHeight.get(), state);
100
+ async initMetrics(state, chainHeight) {
101
+ this.updateProgressMetrics(chainHeight, state);
66
102
  let port = process.env.PROCESSOR_PROMETHEUS_PORT || process.env.PROMETHEUS_PORT;
67
103
  let prometheusServer;
68
104
  if (this.opts?.prometheus != null) {
@@ -78,35 +114,80 @@ class Processor {
78
114
  let listening = await prometheusServer.serve();
79
115
  log.info(`prometheus metrics are served on port ${listening.port}`);
80
116
  }
81
- updateProgressMetrics(chainHeight, state, time) {
117
+ updateProgressMetrics(chainHeight, indexerHeight, time) {
82
118
  this.metrics.setChainHeight(chainHeight);
83
- this.metrics.setLastProcessedBlock(state.height);
119
+ this.metrics.setLastProcessedBlock(indexerHeight);
84
120
  this.metrics.updateProgress(time);
85
121
  }
86
- async processBatch(prevHead, blocks) {
87
- let chainHeight = await this.chainHeight.get();
88
- let nextHead = {
89
- hash: (0, util_internal_1.last)(blocks).header.hash,
90
- height: (0, util_internal_1.last)(blocks).header.height
91
- };
92
- let isOnTop = nextHead.height >= chainHeight;
122
+ async processBatch(state, data, chainHeight) {
123
+ let { blocks, finalizedHead: finalizedHeadData } = data;
124
+ if (blocks.length === 0)
125
+ return state;
126
+ let prevHead = getStateHead(state);
127
+ // Validate data continuity
128
+ if (prevHead && prevHead.number >= blocks[0].header.number) {
129
+ throw new Error('Data is not continuous');
130
+ }
131
+ if (finalizedHeadData != null && state.finalizedHead != null && finalizedHeadData.number <= state.finalizedHead.number) {
132
+ finalizedHeadData = state.finalizedHead;
133
+ }
134
+ let unfinalizedIndex = 0;
135
+ if (finalizedHeadData != null) {
136
+ unfinalizedIndex = blocks.findIndex((b) => b.header.number > finalizedHeadData.number);
137
+ }
138
+ let nextHead = (0, util_internal_1.last)(blocks).header;
139
+ let isOnTop = nextHead.number >= chainHeight;
93
140
  let mappingStartTime = process.hrtime.bigint();
94
- await this.db.transact({
95
- prevHead,
96
- nextHead,
97
- isOnTop
98
- }, store => {
99
- return this.handler({
100
- store,
101
- blocks,
102
- isHead: isOnTop
141
+ // All new blocks are finalized
142
+ if (unfinalizedIndex < 0) {
143
+ const finalizedRef = blocks[blocks.length - 1].header;
144
+ state.finalizedHead = { number: finalizedRef.number, hash: finalizedRef.hash };
145
+ state.unfinalizedHeads = [];
146
+ await this.db.transact({
147
+ prevHead: prevHead ? toHashAndHeight(prevHead) : { height: -1, hash: '0x' },
148
+ nextHead: toHashAndHeight(nextHead),
149
+ isOnTop,
150
+ }, (store) => {
151
+ return this.handler({
152
+ store,
153
+ blocks,
154
+ isHead: isOnTop,
155
+ });
103
156
  });
104
- });
157
+ }
158
+ else {
159
+ (0, assert_1.default)(this.db.supportsHotBlocks);
160
+ let finalizedRef = blocks[unfinalizedIndex - 1]?.header;
161
+ if (finalizedHeadData?.hash && finalizedHeadData?.number != null) {
162
+ finalizedRef = { hash: finalizedHeadData.hash, number: finalizedHeadData.number };
163
+ }
164
+ state.finalizedHead = finalizedRef ?? state.finalizedHead;
165
+ // Finalize all hot heads that are older than the cold head
166
+ if (state.finalizedHead) {
167
+ let finalizeIndex = state.unfinalizedHeads.findIndex((h) => h.number > state.finalizedHead.number);
168
+ state.unfinalizedHeads = finalizeIndex < 0 ? [] : state.unfinalizedHeads.slice(finalizeIndex);
169
+ }
170
+ // Process unfinalized blocks
171
+ for (let i = unfinalizedIndex; i < blocks.length; i++) {
172
+ state.unfinalizedHeads.push({ number: blocks[i].header.number, hash: blocks[i].header.hash });
173
+ }
174
+ await this.db.transactHot2({
175
+ finalizedHead: toHashAndHeight(finalizedHeadData ?? state.finalizedHead),
176
+ baseHead: toHashAndHeight(prevHead ?? state.finalizedHead),
177
+ newBlocks: blocks.map((b) => toHashAndHeight(b.header)),
178
+ }, (store, start, end) => {
179
+ return this.handler({
180
+ store,
181
+ blocks: blocks.slice(start, end),
182
+ isHead: isOnTop,
183
+ });
184
+ });
185
+ }
105
186
  let mappingEndTime = process.hrtime.bigint();
106
- this.updateProgressMetrics(chainHeight, nextHead, mappingEndTime);
187
+ this.updateProgressMetrics(chainHeight, nextHead.number, mappingEndTime);
107
188
  this.metrics.registerBatch(blocks.length, (0, util_1.getItemsCount)(blocks), mappingStartTime, mappingEndTime);
108
189
  this.reportStatus();
109
- return nextHead;
190
+ return state;
110
191
  }
111
192
  reportStatus() {
112
193
  if (this.statusReportTimer == null) {
@@ -133,4 +214,37 @@ class Processor {
133
214
  }
134
215
  }
135
216
  }
217
+ function findRollbackIndex(currentChain, forkChain) {
218
+ let currentIndex = 0;
219
+ let forkIndex = 0;
220
+ let lastCommonIndex = -1;
221
+ while (currentIndex < currentChain.length && forkIndex < forkChain.length) {
222
+ const currentBlock = currentChain[currentIndex];
223
+ const forkBlock = forkChain[forkIndex];
224
+ if (currentBlock.number > forkBlock.number) {
225
+ forkIndex++;
226
+ continue;
227
+ }
228
+ if (currentBlock.number < forkBlock.number) {
229
+ currentIndex++;
230
+ continue;
231
+ }
232
+ if (currentBlock.hash !== forkBlock.hash) {
233
+ return lastCommonIndex;
234
+ }
235
+ lastCommonIndex = currentIndex;
236
+ currentIndex++;
237
+ forkIndex++;
238
+ }
239
+ return lastCommonIndex;
240
+ }
241
+ function toHashAndHeight(ref) {
242
+ return { height: ref.number, hash: ref.hash };
243
+ }
244
+ function toBlockRef(hashAndHeight) {
245
+ return { number: hashAndHeight.height, hash: hashAndHeight.hash };
246
+ }
247
+ function getStateHead(state) {
248
+ return (0, util_internal_1.maybeLast)(state.unfinalizedHeads) ?? state.finalizedHead;
249
+ }
136
250
  //# sourceMappingURL=run.js.map
package/lib/run.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
package/lib/util.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { HashAndHeight } from './database';
1
+ import type { BlockRef } from '@subsquid/util-internal-data-source';
2
2
  export declare function timeInterval(seconds: number): string;
3
3
  export declare function getItemsCount(blocks: any[]): number;
4
- export declare function formatHead(head: HashAndHeight): string;
4
+ export declare function formatHead(head: BlockRef): string;
5
5
  export declare function shortHash(hash: string): string;
6
6
  //# sourceMappingURL=util.d.ts.map
package/lib/util.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,YAAY,CAAA;AAGxC,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAWpD;AAGD,wBAAgB,aAAa,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,CAWnD;AAGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAEtD;AAGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM9C"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,qCAAqC,CAAA;AAIjE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAWpD;AAGD,wBAAgB,aAAa,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,CAWnD;AAGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAEjD;AAGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM9C"}
package/lib/util.js CHANGED
@@ -29,7 +29,7 @@ function getItemsCount(blocks) {
29
29
  return count;
30
30
  }
31
31
  function formatHead(head) {
32
- return `${head.height}#${shortHash(head.hash)}`;
32
+ return `${head.number}#${shortHash(head.hash)}`;
33
33
  }
34
34
  function shortHash(hash) {
35
35
  if (hash.startsWith('0x')) {
package/lib/util.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;AAGA,oCAWC;AAGD,sCAWC;AAGD,gCAEC;AAGD,8BAMC;AAvCD,SAAgB,YAAY,CAAC,OAAe;IACxC,IAAI,OAAO,GAAG,EAAE,EAAE,CAAC;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,GAAG,CAAA;IACpC,CAAC;IACD,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,GAAC,EAAE,CAAC,CAAA;IACnC,IAAI,OAAO,GAAG,EAAE,EAAE,CAAC;QACf,OAAQ,OAAO,GAAC,GAAG,CAAA;IACvB,CAAC;IACD,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAA;IACpC,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,EAAE,CAAA;IAC9B,OAAO,KAAK,GAAG,IAAI,GAAG,OAAO,GAAG,GAAG,CAAA;AACvC,CAAC;AAGD,SAAgB,aAAa,CAAC,MAAa;IACvC,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;QACvB,KAAK,IAAI,GAAG,IAAI,KAAK,EAAE,CAAC;YACpB,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;YACpB,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,KAAK,IAAI,GAAG,CAAC,MAAM,CAAA;YACvB,CAAC;QACL,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAA;AAChB,CAAC;AAGD,SAAgB,UAAU,CAAC,IAAmB;IAC1C,OAAO,GAAG,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;AACnD,CAAC;AAGD,SAAgB,SAAS,CAAC,IAAY;IAClC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3B,CAAC;SAAM,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3B,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;AAIA,oCAWC;AAGD,sCAWC;AAGD,gCAEC;AAGD,8BAMC;AAvCD,SAAgB,YAAY,CAAC,OAAe;IACxC,IAAI,OAAO,GAAG,EAAE,EAAE,CAAC;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,GAAG,CAAA;IACpC,CAAC;IACD,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,GAAC,EAAE,CAAC,CAAA;IACnC,IAAI,OAAO,GAAG,EAAE,EAAE,CAAC;QACf,OAAQ,OAAO,GAAC,GAAG,CAAA;IACvB,CAAC;IACD,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAA;IACpC,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,EAAE,CAAA;IAC9B,OAAO,KAAK,GAAG,IAAI,GAAG,OAAO,GAAG,GAAG,CAAA;AACvC,CAAC;AAGD,SAAgB,aAAa,CAAC,MAAa;IACvC,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;QACvB,KAAK,IAAI,GAAG,IAAI,KAAK,EAAE,CAAC;YACpB,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;YACpB,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,KAAK,IAAI,GAAG,CAAC,MAAM,CAAA;YACvB,CAAC;QACL,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAA;AAChB,CAAC;AAGD,SAAgB,UAAU,CAAC,IAAc;IACrC,OAAO,GAAG,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;AACnD,CAAC;AAGD,SAAgB,SAAS,CAAC,IAAY;IAClC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3B,CAAC;SAAM,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3B,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subsquid/batch-processor",
3
- "version": "0.1.0",
3
+ "version": "0.2.0-portal-api.b88e99",
4
4
  "description": "ETL processor",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": "git@github.com:subsquid/squid-sdk.git",
@@ -18,7 +18,9 @@
18
18
  "@subsquid/util-internal": "^3.2.0",
19
19
  "@subsquid/util-internal-processor-tools": "^4.4.0",
20
20
  "@subsquid/util-internal-counters": "^1.3.2",
21
- "@subsquid/util-internal-range": "^0.3.0"
21
+ "@subsquid/util-internal-prometheus-server": "^1.3.0",
22
+ "@subsquid/util-internal-range": "^0.3.0",
23
+ "@subsquid/util-internal-data-source": "0.0.1-portal-api.b88e99"
22
24
  },
23
25
  "devDependencies": {
24
26
  "@types/node": "^18.18.14",
package/src/database.ts CHANGED
@@ -14,11 +14,14 @@ export interface FinalTxInfo {
14
14
 
15
15
  export interface FinalDatabase<S> {
16
16
  supportsHotBlocks?: false
17
- connect(): Promise<HashAndHeight>
17
+ connect(): Promise<FinalDatabaseState>
18
18
  transact(info: FinalTxInfo, cb: (store: S) => Promise<void>): Promise<void>
19
19
  }
20
20
 
21
21
 
22
+ export interface FinalDatabaseState extends HashAndHeight {}
23
+
24
+
22
25
  export interface HotTxInfo {
23
26
  finalizedHead: HashAndHeight
24
27
  baseHead: HashAndHeight
@@ -30,12 +33,8 @@ export interface HotDatabase<S> {
30
33
  supportsHotBlocks: true
31
34
  connect(): Promise<HotDatabaseState>
32
35
  transact(info: FinalTxInfo, cb: (store: S) => Promise<void>): Promise<void>
33
- /**
34
- * @deprecated
35
- */
36
- transactHot(info: HotTxInfo, cb: (store: S, block: HashAndHeight) => Promise<void>): Promise<void>
37
36
 
38
- transactHot2?(
37
+ transactHot2(
39
38
  info: HotTxInfo,
40
39
  cb: (store: S, blockSliceStart: number, blockSliceEnd: number) => Promise<void>
41
40
  ): Promise<void>
@@ -50,4 +49,4 @@ export interface HotDatabaseState extends HashAndHeight {
50
49
  export interface HashAndHeight {
51
50
  height: number
52
51
  hash: string
53
- }
52
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export * from './database'
2
- export * from './datasource'
3
2
  export * from './run'
package/src/run.ts CHANGED
@@ -1,16 +1,17 @@
1
1
  import {createLogger} from '@subsquid/logger'
2
- import {last, runProgram, Throttler} from '@subsquid/util-internal'
2
+ import {last, maybeLast, runProgram, Throttler} from '@subsquid/util-internal'
3
+ import {HashAndHeight, Database} from './database'
4
+ import {DataSource, isForkException, BlockRef, type BlockBatch} from '@subsquid/util-internal-data-source'
5
+ import assert from 'assert'
3
6
  import {PrometheusServer, RunnerMetrics} from '@subsquid/util-internal-processor-tools'
4
- import {Database, HashAndHeight} from './database'
5
- import {DataSource} from './datasource'
6
7
  import {formatHead, getItemsCount} from './util'
7
8
 
9
+
8
10
  export {PrometheusServer}
9
11
 
10
12
 
11
13
  const log = createLogger('sqd:batch-processor')
12
14
 
13
-
14
15
  export interface DataHandlerContext<Block, Store> {
15
16
  /**
16
17
  * Storage interface provided by the database
@@ -27,10 +28,17 @@ export interface DataHandlerContext<Block, Store> {
27
28
  }
28
29
 
29
30
 
30
- interface BlockBase {
31
- header: HashAndHeight
31
+ export interface BlockBase {
32
+ header: BlockRef
32
33
  }
33
34
 
35
+
36
+ interface ProcessorState {
37
+ finalizedHead: BlockRef | undefined
38
+ unfinalizedHeads: BlockRef[]
39
+ }
40
+
41
+
34
42
  interface RunOptions {
35
43
  prometheus?: PrometheusServer
36
44
  }
@@ -63,10 +71,8 @@ export function run<Block extends BlockBase, Store>(
63
71
  })
64
72
  }
65
73
 
66
-
67
74
  class Processor<B extends BlockBase, S> {
68
75
  private metrics: RunnerMetrics
69
- private chainHeight: Throttler<number>
70
76
  private statusReportTimer?: any
71
77
  private hasStatusNews = false
72
78
 
@@ -79,38 +85,67 @@ class Processor<B extends BlockBase, S> {
79
85
  this.metrics = new RunnerMetrics(
80
86
  src.getBlocksCountInRange?.bind(src) ?? ((range) => Math.max(0, range.to - range.from + 1)),
81
87
  )
82
- this.chainHeight = new Throttler(() => this.src.getFinalizedHeight(), 30_000)
83
88
  }
84
89
 
85
90
  async run(): Promise<void> {
86
- let state = await this.db.connect()
87
- if (state.height >= 0) {
88
- log.info(`last processed final block was ${state.height}`)
91
+ let getHead = this.db.supportsHotBlocks ? this.src.getHead.bind(this.src) : this.src.getFinalizedHead.bind(this.src)
92
+ let chainHeight = new Throttler(() => getHead()?.then((r) => r?.number ?? -1), 10_000)
93
+
94
+ let state: ProcessorState = {
95
+ finalizedHead: undefined,
96
+ unfinalizedHeads: [],
97
+ }
98
+ if (this.db.supportsHotBlocks) {
99
+ let dbState = await this.db.connect()
100
+ state.finalizedHead = dbState.height < 0 ? undefined : toBlockRef(dbState)
101
+ state.unfinalizedHeads = dbState.top.map(toBlockRef)
102
+ } else {
103
+ let dbState = await this.db.connect()
104
+ state.finalizedHead = dbState.height < 0 ? undefined : toBlockRef(dbState)
89
105
  }
90
106
 
91
- await this.assertWeAreOnTheSameChain(state)
92
- await this.initMetrics(state)
107
+ let head = getStateHead(state)
108
+ if (head != null) {
109
+ log.info(`last processed block was ${head.number}`)
110
+ }
111
+ await this.initMetrics(head?.number ?? -1, await chainHeight.get())
93
112
 
94
- for await (let blocks of this.src.getBlockStream(state.height + 1)) {
95
- if (blocks.length > 0) {
96
- state = await this.processBatch(state, blocks)
113
+ while (true) {
114
+ let getStream = this.db.supportsHotBlocks
115
+ ? this.src.getStream.bind(this.src)
116
+ : this.src.getFinalizedStream.bind(this.src)
117
+
118
+ head = getStateHead(state)
119
+ try {
120
+ for await (let data of getStream({after: head})) {
121
+ state = await this.processBatch(state, data, await chainHeight.get())
122
+ }
123
+ break // Stream completed successfully, exit loop
124
+ } catch (e) {
125
+ if (!isForkException(e) || !this.db.supportsHotBlocks) throw e
126
+
127
+ // Handle fork and continue loop to retry
128
+ let chain = state.finalizedHead
129
+ ? [state.finalizedHead, ...state.unfinalizedHeads]
130
+ : state.unfinalizedHeads
131
+ let rollbackIndex = findRollbackIndex(chain, e.previousBlocks)
132
+ if (rollbackIndex === -1) {
133
+ if (state.finalizedHead != null) throw new Error('Unable to process fork')
134
+ state.unfinalizedHeads = []
135
+ } else {
136
+ const rollbackHead = chain[rollbackIndex]
137
+ log.info(`navigating a fork on a common base ${formatHead(rollbackHead)}`)
138
+
139
+ state.unfinalizedHeads = chain.slice(1, rollbackIndex + 1)
140
+ }
97
141
  }
98
142
  }
99
143
 
100
144
  this.reportFinalStatus()
101
145
  }
102
146
 
103
- private async assertWeAreOnTheSameChain(state: HashAndHeight): Promise<void> {
104
- if (state.height < 0) return
105
- let hash = await this.src.getBlockHash(state.height)
106
- if (state.hash === hash) return
107
- throw new Error(
108
- `already indexed block ${formatHead(state)} was not found on chain`
109
- )
110
- }
111
-
112
- private async initMetrics(state: HashAndHeight): Promise<void> {
113
- this.updateProgressMetrics(await this.chainHeight.get(), state)
147
+ private async initMetrics(state: number, chainHeight: number): Promise<void> {
148
+ this.updateProgressMetrics(chainHeight, state)
114
149
  let port = process.env.PROCESSOR_PROMETHEUS_PORT || process.env.PROMETHEUS_PORT
115
150
 
116
151
  let prometheusServer: PrometheusServer | undefined
@@ -127,49 +162,106 @@ class Processor<B extends BlockBase, S> {
127
162
  log.info(`prometheus metrics are served on port ${listening.port}`)
128
163
  }
129
164
 
130
- private updateProgressMetrics(chainHeight: number, state: HashAndHeight, time?: bigint): void {
165
+ private updateProgressMetrics(chainHeight: number, indexerHeight: number, time?: bigint): void {
131
166
  this.metrics.setChainHeight(chainHeight)
132
- this.metrics.setLastProcessedBlock(state.height)
167
+ this.metrics.setLastProcessedBlock(indexerHeight)
133
168
  this.metrics.updateProgress(time)
134
169
  }
135
170
 
136
- private async processBatch(prevHead: HashAndHeight, blocks: B[]): Promise<HashAndHeight> {
137
- let chainHeight = await this.chainHeight.get()
171
+ private async processBatch(
172
+ state: ProcessorState,
173
+ data: BlockBatch<B>,
174
+ chainHeight: number
175
+ ): Promise<ProcessorState> {
176
+ let {blocks, finalizedHead: finalizedHeadData} = data
177
+
178
+ if (blocks.length === 0) return state
138
179
 
139
- let nextHead = {
140
- hash: last(blocks).header.hash,
141
- height: last(blocks).header.height
180
+ let prevHead = getStateHead(state)
181
+
182
+ // Validate data continuity
183
+ if (prevHead && prevHead.number >= blocks[0].header.number) {
184
+ throw new Error('Data is not continuous')
142
185
  }
143
186
 
144
- let isOnTop = nextHead.height >= chainHeight
187
+ if (finalizedHeadData != null && state.finalizedHead != null && finalizedHeadData.number <= state.finalizedHead.number) {
188
+ finalizedHeadData = state.finalizedHead
189
+ }
190
+
191
+ let unfinalizedIndex = 0
192
+ if (finalizedHeadData != null) {
193
+ unfinalizedIndex = blocks.findIndex((b) => b.header.number > finalizedHeadData!.number)
194
+ }
195
+
196
+ let nextHead = last(blocks).header
197
+ let isOnTop = nextHead.number >= chainHeight
145
198
 
146
199
  let mappingStartTime = process.hrtime.bigint()
147
200
 
148
- await this.db.transact({
149
- prevHead,
150
- nextHead,
151
- isOnTop
152
- }, store => {
153
- return this.handler({
154
- store,
155
- blocks,
156
- isHead: isOnTop
157
- })
158
- })
201
+ // All new blocks are finalized
202
+ if (unfinalizedIndex < 0) {
203
+ const finalizedRef = blocks[blocks.length - 1].header
204
+ state.finalizedHead = {number: finalizedRef.number, hash: finalizedRef.hash}
205
+ state.unfinalizedHeads = []
206
+
207
+ await this.db.transact(
208
+ {
209
+ prevHead: prevHead ? toHashAndHeight(prevHead) : {height: -1, hash: '0x'},
210
+ nextHead: toHashAndHeight(nextHead),
211
+ isOnTop,
212
+ },
213
+ (store) => {
214
+ return this.handler({
215
+ store,
216
+ blocks,
217
+ isHead: isOnTop,
218
+ })
219
+ }
220
+ )
221
+ } else {
222
+ assert(this.db.supportsHotBlocks)
223
+
224
+ let finalizedRef: BlockRef | undefined = blocks[unfinalizedIndex - 1]?.header
225
+ if (finalizedHeadData?.hash && finalizedHeadData?.number != null) {
226
+ finalizedRef = {hash: finalizedHeadData.hash, number: finalizedHeadData.number}
227
+ }
228
+ state.finalizedHead = finalizedRef ?? state.finalizedHead
229
+
230
+ // Finalize all hot heads that are older than the cold head
231
+ if (state.finalizedHead) {
232
+ let finalizeIndex = state.unfinalizedHeads.findIndex((h) => h.number > state.finalizedHead!.number)
233
+ state.unfinalizedHeads = finalizeIndex < 0 ? [] : state.unfinalizedHeads.slice(finalizeIndex)
234
+ }
235
+
236
+ // Process unfinalized blocks
237
+ for (let i = unfinalizedIndex; i < blocks.length; i++) {
238
+ state.unfinalizedHeads.push({number: blocks[i].header.number, hash: blocks[i].header.hash})
239
+ }
240
+
241
+ await this.db.transactHot2(
242
+ {
243
+ finalizedHead: toHashAndHeight(finalizedHeadData ?? state.finalizedHead),
244
+ baseHead: toHashAndHeight(prevHead ?? state.finalizedHead),
245
+ newBlocks: blocks.map((b) => toHashAndHeight(b.header)),
246
+ },
247
+ (store, start, end) => {
248
+ return this.handler({
249
+ store,
250
+ blocks: blocks.slice(start, end),
251
+ isHead: isOnTop,
252
+ })
253
+ }
254
+ )
255
+ }
159
256
 
160
257
  let mappingEndTime = process.hrtime.bigint()
161
258
 
162
- this.updateProgressMetrics(chainHeight, nextHead, mappingEndTime)
163
- this.metrics.registerBatch(
164
- blocks.length,
165
- getItemsCount(blocks),
166
- mappingStartTime,
167
- mappingEndTime
168
- )
259
+ this.updateProgressMetrics(chainHeight, nextHead.number, mappingEndTime)
260
+ this.metrics.registerBatch(blocks.length, getItemsCount(blocks), mappingStartTime, mappingEndTime)
169
261
 
170
262
  this.reportStatus()
171
263
 
172
- return nextHead
264
+ return state
173
265
  }
174
266
 
175
267
  private reportStatus(): void {
@@ -181,7 +273,7 @@ class Processor<B extends BlockBase, S> {
181
273
  this.hasStatusNews = false
182
274
  this.reportStatus()
183
275
  }
184
- }, 5000)
276
+ }, 5_000)
185
277
  } else {
186
278
  this.hasStatusNews = true
187
279
  }
@@ -197,3 +289,46 @@ class Processor<B extends BlockBase, S> {
197
289
  }
198
290
  }
199
291
  }
292
+
293
+ function findRollbackIndex(currentChain: BlockRef[], forkChain: BlockRef[]): number {
294
+ let currentIndex = 0
295
+ let forkIndex = 0
296
+ let lastCommonIndex = -1
297
+
298
+ while (currentIndex < currentChain.length && forkIndex < forkChain.length) {
299
+ const currentBlock = currentChain[currentIndex]
300
+ const forkBlock = forkChain[forkIndex]
301
+
302
+ if (currentBlock.number > forkBlock.number) {
303
+ forkIndex++
304
+ continue
305
+ }
306
+
307
+ if (currentBlock.number < forkBlock.number) {
308
+ currentIndex++
309
+ continue
310
+ }
311
+
312
+ if (currentBlock.hash !== forkBlock.hash) {
313
+ return lastCommonIndex
314
+ }
315
+
316
+ lastCommonIndex = currentIndex
317
+ currentIndex++
318
+ forkIndex++
319
+ }
320
+
321
+ return lastCommonIndex
322
+ }
323
+
324
+ function toHashAndHeight(ref: BlockRef): HashAndHeight {
325
+ return {height: ref.number, hash: ref.hash}
326
+ }
327
+
328
+ function toBlockRef(hashAndHeight: HashAndHeight): BlockRef {
329
+ return {number: hashAndHeight.height, hash: hashAndHeight.hash}
330
+ }
331
+
332
+ function getStateHead(state: ProcessorState): BlockRef | undefined {
333
+ return maybeLast(state.unfinalizedHeads) ?? state.finalizedHead
334
+ }
package/src/util.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type {BlockRef} from '@subsquid/util-internal-data-source'
1
2
  import {HashAndHeight} from './database'
2
3
 
3
4
 
@@ -29,8 +30,8 @@ export function getItemsCount(blocks: any[]): number {
29
30
  }
30
31
 
31
32
 
32
- export function formatHead(head: HashAndHeight): string {
33
- return `${head.height}#${shortHash(head.hash)}`
33
+ export function formatHead(head: BlockRef): string {
34
+ return `${head.number}#${shortHash(head.hash)}`
34
35
  }
35
36
 
36
37
 
@@ -1,8 +0,0 @@
1
- import type { FiniteRange } from '@subsquid/util-internal-range';
2
- export interface DataSource<B> {
3
- getFinalizedHeight(): Promise<number>;
4
- getBlockHash(height: number): Promise<string | undefined>;
5
- getBlockStream(fromBlock?: number): AsyncIterable<B[]>;
6
- getBlocksCountInRange?(range: FiniteRange): number;
7
- }
8
- //# sourceMappingURL=datasource.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"datasource.d.ts","sourceRoot":"","sources":["../src/datasource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,+BAA+B,CAAA;AAG9D,MAAM,WAAW,UAAU,CAAC,CAAC;IACzB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IACrC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACzD,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,EAAE,CAAC,CAAA;IACtD,qBAAqB,CAAC,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAAA;CACrD"}
package/lib/datasource.js DELETED
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=datasource.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"datasource.js","sourceRoot":"","sources":["../src/datasource.ts"],"names":[],"mappings":""}
package/src/datasource.ts DELETED
@@ -1,9 +0,0 @@
1
- import type {FiniteRange} from '@subsquid/util-internal-range'
2
-
3
-
4
- export interface DataSource<B> {
5
- getFinalizedHeight(): Promise<number>
6
- getBlockHash(height: number): Promise<string | undefined>
7
- getBlockStream(fromBlock?: number): AsyncIterable<B[]>
8
- getBlocksCountInRange?(range: FiniteRange): number
9
- }