@subsquid/batch-processor 0.0.0 → 0.1.0-portal-api.d0738f

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,5 +1,5 @@
1
- import { Database, HashAndHeight } from './database';
2
- import { DataSource } from './datasource';
1
+ import { Database } from './database';
2
+ import { DataSource, BlockRef } from '@subsquid/util-internal-data-source';
3
3
  export interface DataHandlerContext<Block, Store> {
4
4
  /**
5
5
  * Storage interface provided by the database
@@ -14,8 +14,8 @@ export interface DataHandlerContext<Block, Store> {
14
14
  */
15
15
  isHead: boolean;
16
16
  }
17
- interface BlockBase {
18
- header: HashAndHeight;
17
+ export interface BlockBase {
18
+ header: BlockRef;
19
19
  }
20
20
  /**
21
21
  * Run data processing.
@@ -32,5 +32,4 @@ interface BlockBase {
32
32
  * @param dataHandler - The data handler, see {@link DataHandlerContext} for an API available to the handler.
33
33
  */
34
34
  export declare function run<Block extends BlockBase, Store>(src: DataSource<Block>, db: Database<Store>, dataHandler: (ctx: DataHandlerContext<Block, Store>) => Promise<void>): void;
35
- export {};
36
35
  //# sourceMappingURL=run.d.ts.map
package/lib/run.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,QAAQ,EAAE,aAAa,EAAC,MAAM,YAAY,CAAA;AAClD,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AAQvC,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;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,GACtE,IAAI,CAMN"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAIA,OAAO,EAAgB,QAAQ,EAAmB,MAAM,YAAY,CAAA;AAEpE,OAAO,EAAC,UAAU,EAAmB,QAAQ,EAAkB,MAAM,qCAAqC,CAAA;AAM1G,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;AAED,MAAM,WAAW,SAAS;IACtB,MAAM,EAAE,QAAQ,CAAA;CACnB;AAOD;;;;;;;;;;;;;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,GACtE,IAAI,CASN"}
package/lib/run.js CHANGED
@@ -22,14 +22,19 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.run = void 0;
29
+ exports.run = run;
27
30
  const logger_1 = require("@subsquid/logger");
28
31
  const util_internal_1 = require("@subsquid/util-internal");
29
32
  const util_internal_prometheus_server_1 = require("@subsquid/util-internal-prometheus-server");
30
33
  const prom = __importStar(require("prom-client"));
31
34
  const metrics_1 = require("./metrics");
35
+ const util_internal_data_source_1 = require("@subsquid/util-internal-data-source");
32
36
  const util_1 = require("./util");
37
+ const assert_1 = __importDefault(require("assert"));
33
38
  const log = (0, logger_1.createLogger)('sqd:batch-processor');
34
39
  /**
35
40
  * Run data processing.
@@ -48,11 +53,10 @@ const log = (0, logger_1.createLogger)('sqd:batch-processor');
48
53
  function run(src, db, dataHandler) {
49
54
  (0, util_internal_1.runProgram)(() => {
50
55
  return new Processor(src, db, dataHandler).run();
51
- }, err => {
56
+ }, (err) => {
52
57
  log.fatal(err);
53
58
  });
54
59
  }
55
- exports.run = run;
56
60
  class Processor {
57
61
  constructor(src, db, handler) {
58
62
  this.src = src;
@@ -60,32 +64,63 @@ class Processor {
60
64
  this.handler = handler;
61
65
  this.metrics = new metrics_1.Metrics();
62
66
  this.hasStatusNews = false;
63
- this.chainHeight = new util_internal_1.Throttler(() => this.src.getFinalizedHeight(), 30000);
64
67
  }
65
68
  async run() {
66
- let state = await this.db.connect();
67
- if (state.height >= 0) {
68
- log.info(`last processed final block was ${state.height}`);
69
+ let getHead = this.db.supportsHotBlocks ? this.src.getHead.bind(this.src) : this.src.getFinalizedHead.bind(this.src);
70
+ let chainHeight = new util_internal_1.Throttler(() => getHead()?.then((r) => r?.number ?? -1), 10000);
71
+ let state = {
72
+ finalizedHead: undefined,
73
+ unfinalizedHeads: [],
74
+ };
75
+ if (this.db.supportsHotBlocks) {
76
+ let dbState = await this.db.connect();
77
+ state.finalizedHead = dbState.height < 0 ? undefined : toBlockRef(dbState);
78
+ state.unfinalizedHeads = dbState.top.map(toBlockRef);
69
79
  }
70
- await this.assertWeAreOnTheSameChain(state);
71
- await this.initMetrics(state);
72
- for await (let blocks of this.src.getBlockStream(state.height + 1)) {
73
- if (blocks.length > 0) {
74
- state = await this.processBatch(state, blocks);
80
+ else {
81
+ let dbState = await this.db.connect();
82
+ state.finalizedHead = dbState.height < 0 ? undefined : toBlockRef(dbState);
83
+ }
84
+ let head = getStateHead(state);
85
+ if (head != null) {
86
+ log.info(`last processed block was ${head.number}`);
87
+ }
88
+ await this.initMetrics(head?.number ?? -1, await chainHeight.get());
89
+ while (true) {
90
+ let getStream = this.db.supportsHotBlocks
91
+ ? this.src.getStream.bind(this.src)
92
+ : this.src.getFinalizedStream.bind(this.src);
93
+ head = getStateHead(state);
94
+ try {
95
+ for await (let data of getStream({ after: head })) {
96
+ state = await this.processBatch(state, data, await chainHeight.get());
97
+ }
98
+ break; // Stream completed successfully, exit loop
99
+ }
100
+ catch (e) {
101
+ if (!(0, util_internal_data_source_1.isForkException)(e) || !this.db.supportsHotBlocks)
102
+ throw e;
103
+ // Handle fork and continue loop to retry
104
+ let chain = state.finalizedHead
105
+ ? [state.finalizedHead, ...state.unfinalizedHeads]
106
+ : state.unfinalizedHeads;
107
+ let rollbackIndex = findRollbackIndex(chain, e.previousBlocks);
108
+ if (rollbackIndex === -1) {
109
+ if (state.finalizedHead != null)
110
+ throw new Error('Unable to process fork');
111
+ state.unfinalizedHeads = [];
112
+ }
113
+ else {
114
+ const rollbackHead = chain[rollbackIndex];
115
+ log.info(`navigating a fork on a common base ${(0, util_1.formatHead)(rollbackHead)}`);
116
+ state.unfinalizedHeads = chain.slice(1, rollbackIndex + 1);
117
+ }
75
118
  }
76
119
  }
77
120
  this.reportFinalStatus();
78
121
  }
79
- async assertWeAreOnTheSameChain(state) {
80
- if (state.height < 0)
81
- return;
82
- let hash = await this.src.getBlockHash(state.height);
83
- if (state.hash === hash)
84
- return;
85
- throw new Error(`already indexed block ${(0, util_1.formatHead)(state)} was not found on chain`);
86
- }
87
- async initMetrics(state) {
88
- await this.updateProgressMetrics(await this.chainHeight.get(), state);
122
+ async initMetrics(state, chainHeight) {
123
+ this.updateProgressMetrics(chainHeight, state);
89
124
  let port = process.env.PROCESSOR_PROMETHEUS_PORT || process.env.PROMETHEUS_PORT;
90
125
  if (port == null)
91
126
  return;
@@ -94,51 +129,79 @@ class Processor {
94
129
  let server = await (0, util_internal_prometheus_server_1.createPrometheusServer)(prom.register, port);
95
130
  log.info(`prometheus metrics are served on port ${server.port}`);
96
131
  }
97
- updateProgressMetrics(chainHeight, state, time) {
132
+ updateProgressMetrics(chainHeight, indexerHeight, time) {
98
133
  this.metrics.setChainHeight(chainHeight);
99
- this.metrics.setLastProcessedBlock(state.height);
100
- let left;
101
- let processed;
102
- if (this.src.getBlocksCountInRange) {
103
- left = this.src.getBlocksCountInRange({
104
- from: this.metrics.getLastProcessedBlock() + 1,
105
- to: this.metrics.getChainHeight()
106
- });
107
- processed = this.src.getBlocksCountInRange({
108
- from: 0,
109
- to: this.metrics.getChainHeight()
110
- }) - left;
111
- }
112
- else {
113
- left = this.metrics.getChainHeight() - this.metrics.getLastProcessedBlock();
114
- processed = this.metrics.getLastProcessedBlock();
115
- }
134
+ this.metrics.setLastProcessedBlock(indexerHeight);
135
+ let left = this.metrics.getChainHeight() - this.metrics.getLastProcessedBlock();
136
+ let processed = this.metrics.getLastProcessedBlock();
116
137
  this.metrics.updateProgress(processed, left, time);
117
138
  }
118
- async processBatch(prevHead, blocks) {
119
- let chainHeight = await this.chainHeight.get();
120
- let nextHead = {
121
- hash: (0, util_internal_1.last)(blocks).header.hash,
122
- height: (0, util_internal_1.last)(blocks).header.height
123
- };
124
- let isOnTop = nextHead.height >= chainHeight;
139
+ async processBatch(state, data, chainHeight) {
140
+ let { blocks, finalizedHead: finalizedHeadData } = data;
141
+ if (blocks.length === 0)
142
+ return state;
143
+ let prevHead = getStateHead(state);
144
+ // Validate data continuity
145
+ if (prevHead && prevHead.number >= blocks[0].header.number) {
146
+ throw new Error('Data is not continuous');
147
+ }
148
+ let unfinalizedIndex = 0;
149
+ if (finalizedHeadData != null) {
150
+ unfinalizedIndex = blocks.findIndex((b) => b.header.number > finalizedHeadData.number);
151
+ }
152
+ let nextHead = (0, util_internal_1.last)(blocks).header;
153
+ let isOnTop = nextHead.number >= chainHeight;
125
154
  let mappingStartTime = process.hrtime.bigint();
126
- await this.db.transact({
127
- prevHead,
128
- nextHead,
129
- isOnTop
130
- }, store => {
131
- return this.handler({
132
- store,
133
- blocks,
134
- isHead: isOnTop
155
+ // All new blocks are finalized
156
+ if (unfinalizedIndex < 0) {
157
+ const finalizedRef = blocks[blocks.length - 1].header;
158
+ state.finalizedHead = { number: finalizedRef.number, hash: finalizedRef.hash };
159
+ state.unfinalizedHeads = [];
160
+ await this.db.transact({
161
+ prevHead: prevHead ? toHashAndHeight(prevHead) : { height: -1, hash: '0x' },
162
+ nextHead: toHashAndHeight(nextHead),
163
+ isOnTop,
164
+ }, (store) => {
165
+ return this.handler({
166
+ store,
167
+ blocks,
168
+ isHead: isOnTop,
169
+ });
170
+ });
171
+ }
172
+ else {
173
+ (0, assert_1.default)(this.db.supportsHotBlocks);
174
+ let finalizedRef = blocks[unfinalizedIndex - 1]?.header;
175
+ if (finalizedHeadData?.hash && finalizedHeadData?.number != null) {
176
+ finalizedRef = { hash: finalizedHeadData.hash, number: finalizedHeadData.number };
177
+ }
178
+ state.finalizedHead = finalizedRef ?? state.finalizedHead;
179
+ // Finalize all hot heads that are older than the cold head
180
+ if (state.finalizedHead) {
181
+ let finalizeIndex = state.unfinalizedHeads.findIndex((h) => h.number > state.finalizedHead.number);
182
+ state.unfinalizedHeads = finalizeIndex < 0 ? [] : state.unfinalizedHeads.slice(finalizeIndex);
183
+ }
184
+ // Process unfinalized blocks
185
+ for (let i = unfinalizedIndex; i < blocks.length; i++) {
186
+ state.unfinalizedHeads.push({ number: blocks[i].header.number, hash: blocks[i].header.hash });
187
+ }
188
+ await this.db.transactHot2({
189
+ finalizedHead: toHashAndHeight(finalizedHeadData ?? state.finalizedHead),
190
+ baseHead: toHashAndHeight(prevHead ?? state.finalizedHead),
191
+ newBlocks: blocks.map((b) => toHashAndHeight(b.header)),
192
+ }, (store, start, end) => {
193
+ return this.handler({
194
+ store,
195
+ blocks: blocks.slice(start, end),
196
+ isHead: isOnTop,
197
+ });
135
198
  });
136
- });
199
+ }
137
200
  let mappingEndTime = process.hrtime.bigint();
138
- this.updateProgressMetrics(chainHeight, nextHead, mappingEndTime);
201
+ this.updateProgressMetrics(chainHeight, nextHead.number, mappingEndTime);
139
202
  this.metrics.registerBatch(blocks.length, (0, util_1.getItemsCount)(blocks), mappingStartTime, mappingEndTime);
140
203
  this.reportStatus();
141
- return nextHead;
204
+ return state;
142
205
  }
143
206
  reportStatus() {
144
207
  if (this.statusReportTimer == null) {
@@ -165,4 +228,37 @@ class Processor {
165
228
  }
166
229
  }
167
230
  }
231
+ function findRollbackIndex(currentChain, forkChain) {
232
+ let currentIndex = 0;
233
+ let forkIndex = 0;
234
+ let lastCommonIndex = -1;
235
+ while (currentIndex < currentChain.length && forkIndex < forkChain.length) {
236
+ const currentBlock = currentChain[currentIndex];
237
+ const forkBlock = forkChain[forkIndex];
238
+ if (currentBlock.number > forkBlock.number) {
239
+ forkIndex++;
240
+ continue;
241
+ }
242
+ if (currentBlock.number < forkBlock.number) {
243
+ currentIndex++;
244
+ continue;
245
+ }
246
+ if (currentBlock.hash !== forkBlock.hash) {
247
+ return lastCommonIndex;
248
+ }
249
+ lastCommonIndex = currentIndex;
250
+ currentIndex++;
251
+ forkIndex++;
252
+ }
253
+ return lastCommonIndex;
254
+ }
255
+ function toHashAndHeight(ref) {
256
+ return { height: ref.number, hash: ref.hash };
257
+ }
258
+ function toBlockRef(hashAndHeight) {
259
+ return { number: hashAndHeight.height, hash: hashAndHeight.hash };
260
+ }
261
+ function getStateHead(state) {
262
+ return (0, util_internal_1.maybeLast)(state.unfinalizedHeads) ?? state.finalizedHead;
263
+ }
168
264
  //# 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
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.shortHash = exports.formatHead = exports.getItemsCount = exports.timeInterval = void 0;
3
+ exports.timeInterval = timeInterval;
4
+ exports.getItemsCount = getItemsCount;
5
+ exports.formatHead = formatHead;
6
+ exports.shortHash = shortHash;
4
7
  function timeInterval(seconds) {
5
8
  if (seconds < 60) {
6
9
  return Math.round(seconds) + 's';
@@ -13,7 +16,6 @@ function timeInterval(seconds) {
13
16
  minutes = minutes - hours * 60;
14
17
  return hours + 'h ' + minutes + 'm';
15
18
  }
16
- exports.timeInterval = timeInterval;
17
19
  function getItemsCount(blocks) {
18
20
  let count = 0;
19
21
  for (let block of blocks) {
@@ -26,11 +28,9 @@ function getItemsCount(blocks) {
26
28
  }
27
29
  return count;
28
30
  }
29
- exports.getItemsCount = getItemsCount;
30
31
  function formatHead(head) {
31
- return `${head.height}#${shortHash(head.hash)}`;
32
+ return `${head.number}#${shortHash(head.hash)}`;
32
33
  }
33
- exports.formatHead = formatHead;
34
34
  function shortHash(hash) {
35
35
  if (hash.startsWith('0x')) {
36
36
  return hash.slice(2, 7);
@@ -39,5 +39,4 @@ function shortHash(hash) {
39
39
  return hash.slice(0, 5);
40
40
  }
41
41
  }
42
- exports.shortHash = shortHash;
43
42
  //# sourceMappingURL=util.js.map
package/lib/util.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;AAGA,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;AAXD,oCAWC;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;AAXD,sCAWC;AAGD,SAAgB,UAAU,CAAC,IAAmB;IAC1C,OAAO,GAAG,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;AACnD,CAAC;AAFD,gCAEC;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;AAND,8BAMC"}
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.0.0",
3
+ "version": "0.1.0-portal-api.d0738f",
4
4
  "description": "ETL processor",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": "git@github.com:subsquid/squid.git",
@@ -14,16 +14,17 @@
14
14
  ],
15
15
  "main": "lib/index.js",
16
16
  "dependencies": {
17
- "@subsquid/logger": "^1.3.3",
17
+ "@subsquid/logger": "^1.4.0",
18
18
  "@subsquid/util-internal": "^3.2.0",
19
19
  "@subsquid/util-internal-counters": "^1.3.2",
20
20
  "@subsquid/util-internal-prometheus-server": "^1.3.0",
21
21
  "@subsquid/util-internal-range": "^0.3.0",
22
- "prom-client": "^14.2.0"
22
+ "prom-client": "^14.2.0",
23
+ "@subsquid/util-internal-data-source": "0.0.1-portal-api.d0738f"
23
24
  },
24
25
  "devDependencies": {
25
26
  "@types/node": "^18.18.14",
26
- "typescript": "~5.3.2"
27
+ "typescript": "~5.5.4"
27
28
  },
28
29
  "scripts": {
29
30
  "build": "rm -rf lib && tsc"
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,15 @@
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
3
  import {createPrometheusServer} from '@subsquid/util-internal-prometheus-server'
4
4
  import * as prom from 'prom-client'
5
- import {Database, HashAndHeight} from './database'
6
- import {DataSource} from './datasource'
5
+ import {HashAndHeight, Database, HotDatabaseState} from './database'
7
6
  import {Metrics} from './metrics'
7
+ import {DataSource, isForkException, BlockRef, type BlockBatch} from '@subsquid/util-internal-data-source'
8
8
  import {formatHead, getItemsCount} from './util'
9
-
9
+ import assert from 'assert'
10
10
 
11
11
  const log = createLogger('sqd:batch-processor')
12
12
 
13
-
14
13
  export interface DataHandlerContext<Block, Store> {
15
14
  /**
16
15
  * Storage interface provided by the database
@@ -26,11 +25,14 @@ export interface DataHandlerContext<Block, Store> {
26
25
  isHead: boolean
27
26
  }
28
27
 
29
-
30
- interface BlockBase {
31
- header: HashAndHeight
28
+ export interface BlockBase {
29
+ header: BlockRef
32
30
  }
33
31
 
32
+ interface ProcessorState {
33
+ finalizedHead: BlockRef | undefined
34
+ unfinalizedHeads: BlockRef[]
35
+ }
34
36
 
35
37
  /**
36
38
  * Run data processing.
@@ -51,17 +53,18 @@ export function run<Block extends BlockBase, Store>(
51
53
  db: Database<Store>,
52
54
  dataHandler: (ctx: DataHandlerContext<Block, Store>) => Promise<void>
53
55
  ): void {
54
- runProgram(() => {
55
- return new Processor(src, db, dataHandler).run()
56
- }, err => {
57
- log.fatal(err)
58
- })
56
+ runProgram(
57
+ () => {
58
+ return new Processor(src, db, dataHandler).run()
59
+ },
60
+ (err) => {
61
+ log.fatal(err)
62
+ }
63
+ )
59
64
  }
60
65
 
61
-
62
66
  class Processor<B extends BlockBase, S> {
63
67
  private metrics = new Metrics()
64
- private chainHeight: Throttler<number>
65
68
  private statusReportTimer?: any
66
69
  private hasStatusNews = false
67
70
 
@@ -69,39 +72,67 @@ class Processor<B extends BlockBase, S> {
69
72
  private src: DataSource<B>,
70
73
  private db: Database<S>,
71
74
  private handler: (ctx: DataHandlerContext<B, S>) => Promise<void>
72
- ) {
73
- this.chainHeight = new Throttler(() => this.src.getFinalizedHeight(), 30_000)
74
- }
75
+ ) {}
75
76
 
76
77
  async run(): Promise<void> {
77
- let state = await this.db.connect()
78
- if (state.height >= 0) {
79
- log.info(`last processed final block was ${state.height}`)
78
+ let getHead = this.db.supportsHotBlocks ? this.src.getHead.bind(this.src) : this.src.getFinalizedHead.bind(this.src)
79
+ let chainHeight = new Throttler(() => getHead()?.then((r) => r?.number ?? -1), 10_000)
80
+
81
+ let state: ProcessorState = {
82
+ finalizedHead: undefined,
83
+ unfinalizedHeads: [],
84
+ }
85
+ if (this.db.supportsHotBlocks) {
86
+ let dbState = await this.db.connect()
87
+ state.finalizedHead = dbState.height < 0 ? undefined : toBlockRef(dbState)
88
+ state.unfinalizedHeads = dbState.top.map(toBlockRef)
89
+ } else {
90
+ let dbState = await this.db.connect()
91
+ state.finalizedHead = dbState.height < 0 ? undefined : toBlockRef(dbState)
80
92
  }
81
93
 
82
- await this.assertWeAreOnTheSameChain(state)
83
- await this.initMetrics(state)
94
+ let head = getStateHead(state)
95
+ if (head != null) {
96
+ log.info(`last processed block was ${head.number}`)
97
+ }
98
+ await this.initMetrics(head?.number ?? -1, await chainHeight.get())
99
+
100
+ while (true) {
101
+ let getStream = this.db.supportsHotBlocks
102
+ ? this.src.getStream.bind(this.src)
103
+ : this.src.getFinalizedStream.bind(this.src)
104
+
105
+ head = getStateHead(state)
106
+ try {
107
+ for await (let data of getStream({after: head})) {
108
+ state = await this.processBatch(state, data, await chainHeight.get())
109
+ }
110
+ break // Stream completed successfully, exit loop
111
+ } catch (e) {
112
+ if (!isForkException(e) || !this.db.supportsHotBlocks) throw e
84
113
 
85
- for await (let blocks of this.src.getBlockStream(state.height + 1)) {
86
- if (blocks.length > 0) {
87
- state = await this.processBatch(state, blocks)
114
+ // Handle fork and continue loop to retry
115
+ let chain = state.finalizedHead
116
+ ? [state.finalizedHead, ...state.unfinalizedHeads]
117
+ : state.unfinalizedHeads
118
+ let rollbackIndex = findRollbackIndex(chain, e.previousBlocks)
119
+ if (rollbackIndex === -1) {
120
+ if (state.finalizedHead != null) throw new Error('Unable to process fork')
121
+ state.unfinalizedHeads = []
122
+ } else {
123
+ const rollbackHead = chain[rollbackIndex]
124
+ log.info(`navigating a fork on a common base ${formatHead(rollbackHead)}`)
125
+
126
+ state.unfinalizedHeads = chain.slice(1, rollbackIndex + 1)
127
+ }
88
128
  }
89
129
  }
90
130
 
91
131
  this.reportFinalStatus()
92
132
  }
93
133
 
94
- private async assertWeAreOnTheSameChain(state: HashAndHeight): Promise<void> {
95
- if (state.height < 0) return
96
- let hash = await this.src.getBlockHash(state.height)
97
- if (state.hash === hash) return
98
- throw new Error(
99
- `already indexed block ${formatHead(state)} was not found on chain`
100
- )
101
- }
102
-
103
- private async initMetrics(state: HashAndHeight): Promise<void> {
104
- await this.updateProgressMetrics(await this.chainHeight.get(), state)
134
+ private async initMetrics(state: number, chainHeight: number): Promise<void> {
135
+ this.updateProgressMetrics(chainHeight, state)
105
136
  let port = process.env.PROCESSOR_PROMETHEUS_PORT || process.env.PROMETHEUS_PORT
106
137
  if (port == null) return
107
138
  prom.collectDefaultMetrics()
@@ -110,64 +141,104 @@ class Processor<B extends BlockBase, S> {
110
141
  log.info(`prometheus metrics are served on port ${server.port}`)
111
142
  }
112
143
 
113
- private updateProgressMetrics(chainHeight: number, state: HashAndHeight, time?: bigint): void {
144
+ private updateProgressMetrics(chainHeight: number, indexerHeight: number, time?: bigint): void {
114
145
  this.metrics.setChainHeight(chainHeight)
115
- this.metrics.setLastProcessedBlock(state.height)
116
- let left: number
117
- let processed: number
118
- if (this.src.getBlocksCountInRange) {
119
- left = this.src.getBlocksCountInRange({
120
- from: this.metrics.getLastProcessedBlock() + 1,
121
- to: this.metrics.getChainHeight()
122
- })
123
- processed = this.src.getBlocksCountInRange({
124
- from: 0,
125
- to: this.metrics.getChainHeight()
126
- }) - left
127
- } else {
128
- left = this.metrics.getChainHeight() - this.metrics.getLastProcessedBlock()
129
- processed = this.metrics.getLastProcessedBlock()
130
- }
146
+ this.metrics.setLastProcessedBlock(indexerHeight)
147
+ let left = this.metrics.getChainHeight() - this.metrics.getLastProcessedBlock()
148
+ let processed = this.metrics.getLastProcessedBlock()
131
149
  this.metrics.updateProgress(processed, left, time)
132
150
  }
133
151
 
134
- private async processBatch(prevHead: HashAndHeight, blocks: B[]): Promise<HashAndHeight> {
135
- let chainHeight = await this.chainHeight.get()
152
+ private async processBatch(
153
+ state: ProcessorState,
154
+ data: BlockBatch<B>,
155
+ chainHeight: number
156
+ ): Promise<ProcessorState> {
157
+ let {blocks, finalizedHead: finalizedHeadData} = data
158
+
159
+ if (blocks.length === 0) return state
136
160
 
137
- let nextHead = {
138
- hash: last(blocks).header.hash,
139
- height: last(blocks).header.height
161
+ let prevHead = getStateHead(state)
162
+
163
+ // Validate data continuity
164
+ if (prevHead && prevHead.number >= blocks[0].header.number) {
165
+ throw new Error('Data is not continuous')
166
+ }
167
+
168
+ let unfinalizedIndex = 0
169
+ if (finalizedHeadData != null) {
170
+ unfinalizedIndex = blocks.findIndex((b) => b.header.number > finalizedHeadData!.number)
140
171
  }
141
172
 
142
- let isOnTop = nextHead.height >= chainHeight
173
+ let nextHead = last(blocks).header
174
+ let isOnTop = nextHead.number >= chainHeight
143
175
 
144
176
  let mappingStartTime = process.hrtime.bigint()
145
177
 
146
- await this.db.transact({
147
- prevHead,
148
- nextHead,
149
- isOnTop
150
- }, store => {
151
- return this.handler({
152
- store,
153
- blocks,
154
- isHead: isOnTop
155
- })
156
- })
178
+ // All new blocks are finalized
179
+ if (unfinalizedIndex < 0) {
180
+ const finalizedRef = blocks[blocks.length - 1].header
181
+ state.finalizedHead = {number: finalizedRef.number, hash: finalizedRef.hash}
182
+ state.unfinalizedHeads = []
183
+
184
+ await this.db.transact(
185
+ {
186
+ prevHead: prevHead ? toHashAndHeight(prevHead) : {height: -1, hash: '0x'},
187
+ nextHead: toHashAndHeight(nextHead),
188
+ isOnTop,
189
+ },
190
+ (store) => {
191
+ return this.handler({
192
+ store,
193
+ blocks,
194
+ isHead: isOnTop,
195
+ })
196
+ }
197
+ )
198
+ } else {
199
+ assert(this.db.supportsHotBlocks)
200
+
201
+ let finalizedRef: BlockRef | undefined = blocks[unfinalizedIndex - 1]?.header
202
+ if (finalizedHeadData?.hash && finalizedHeadData?.number != null) {
203
+ finalizedRef = {hash: finalizedHeadData.hash, number: finalizedHeadData.number}
204
+ }
205
+ state.finalizedHead = finalizedRef ?? state.finalizedHead
206
+
207
+ // Finalize all hot heads that are older than the cold head
208
+ if (state.finalizedHead) {
209
+ let finalizeIndex = state.unfinalizedHeads.findIndex((h) => h.number > state.finalizedHead!.number)
210
+ state.unfinalizedHeads = finalizeIndex < 0 ? [] : state.unfinalizedHeads.slice(finalizeIndex)
211
+ }
212
+
213
+ // Process unfinalized blocks
214
+ for (let i = unfinalizedIndex; i < blocks.length; i++) {
215
+ state.unfinalizedHeads.push({number: blocks[i].header.number, hash: blocks[i].header.hash})
216
+ }
217
+
218
+ await this.db.transactHot2(
219
+ {
220
+ finalizedHead: toHashAndHeight(finalizedHeadData ?? state.finalizedHead),
221
+ baseHead: toHashAndHeight(prevHead ?? state.finalizedHead),
222
+ newBlocks: blocks.map((b) => toHashAndHeight(b.header)),
223
+ },
224
+ (store, start, end) => {
225
+ return this.handler({
226
+ store,
227
+ blocks: blocks.slice(start, end),
228
+ isHead: isOnTop,
229
+ })
230
+ }
231
+ )
232
+ }
157
233
 
158
234
  let mappingEndTime = process.hrtime.bigint()
159
235
 
160
- this.updateProgressMetrics(chainHeight, nextHead, mappingEndTime)
161
- this.metrics.registerBatch(
162
- blocks.length,
163
- getItemsCount(blocks),
164
- mappingStartTime,
165
- mappingEndTime
166
- )
236
+ this.updateProgressMetrics(chainHeight, nextHead.number, mappingEndTime)
237
+ this.metrics.registerBatch(blocks.length, getItemsCount(blocks), mappingStartTime, mappingEndTime)
167
238
 
168
239
  this.reportStatus()
169
240
 
170
- return nextHead
241
+ return state
171
242
  }
172
243
 
173
244
  private reportStatus(): void {
@@ -179,7 +250,7 @@ class Processor<B extends BlockBase, S> {
179
250
  this.hasStatusNews = false
180
251
  this.reportStatus()
181
252
  }
182
- }, 5000)
253
+ }, 5_000)
183
254
  } else {
184
255
  this.hasStatusNews = true
185
256
  }
@@ -195,3 +266,46 @@ class Processor<B extends BlockBase, S> {
195
266
  }
196
267
  }
197
268
  }
269
+
270
+ function findRollbackIndex(currentChain: BlockRef[], forkChain: BlockRef[]): number {
271
+ let currentIndex = 0
272
+ let forkIndex = 0
273
+ let lastCommonIndex = -1
274
+
275
+ while (currentIndex < currentChain.length && forkIndex < forkChain.length) {
276
+ const currentBlock = currentChain[currentIndex]
277
+ const forkBlock = forkChain[forkIndex]
278
+
279
+ if (currentBlock.number > forkBlock.number) {
280
+ forkIndex++
281
+ continue
282
+ }
283
+
284
+ if (currentBlock.number < forkBlock.number) {
285
+ currentIndex++
286
+ continue
287
+ }
288
+
289
+ if (currentBlock.hash !== forkBlock.hash) {
290
+ return lastCommonIndex
291
+ }
292
+
293
+ lastCommonIndex = currentIndex
294
+ currentIndex++
295
+ forkIndex++
296
+ }
297
+
298
+ return lastCommonIndex
299
+ }
300
+
301
+ function toHashAndHeight(ref: BlockRef): HashAndHeight {
302
+ return {height: ref.number, hash: ref.hash}
303
+ }
304
+
305
+ function toBlockRef(hashAndHeight: HashAndHeight): BlockRef {
306
+ return {number: hashAndHeight.height, hash: hashAndHeight.hash}
307
+ }
308
+
309
+ function getStateHead(state: ProcessorState): BlockRef | undefined {
310
+ return maybeLast(state.unfinalizedHeads) ?? state.finalizedHead
311
+ }
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
- }