envio 3.1.0-rc.2 → 3.1.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/index.d.ts CHANGED
@@ -1201,6 +1201,18 @@ export type IndexerFromConfig<Config extends IndexerConfigTypes = GlobalConfig>
1201
1201
  readonly name: string;
1202
1202
  /** The indexer description from config.yaml. */
1203
1203
  readonly description: string | undefined;
1204
+ /**
1205
+ * Internal, unstable API that will be removed without notice. Registers a
1206
+ * callback fired once per chain affected by a reorg rollback, after the
1207
+ * rollback is durably written to the database. A throwing callback crashes
1208
+ * the indexer through the same path as a failed write.
1209
+ */
1210
+ readonly "~internalAndWillBeRemovedSoon_onRollbackCommit": (
1211
+ callback: (args: {
1212
+ readonly chainId: number;
1213
+ readonly rollbackToBlock: number;
1214
+ }) => Promise<void>,
1215
+ ) => void;
1204
1216
  } & SingleEcosystemChains<Config>
1205
1217
  >;
1206
1218
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "3.1.0-rc.2",
3
+ "version": "3.1.0",
4
4
  "type": "module",
5
5
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
6
6
  "bin": "./bin.mjs",
@@ -70,10 +70,10 @@
70
70
  "tsx": "4.21.0"
71
71
  },
72
72
  "optionalDependencies": {
73
- "envio-linux-x64": "3.1.0-rc.2",
74
- "envio-linux-x64-musl": "3.1.0-rc.2",
75
- "envio-linux-arm64": "3.1.0-rc.2",
76
- "envio-darwin-x64": "3.1.0-rc.2",
77
- "envio-darwin-arm64": "3.1.0-rc.2"
73
+ "envio-linux-x64": "3.1.0",
74
+ "envio-linux-x64-musl": "3.1.0",
75
+ "envio-linux-arm64": "3.1.0",
76
+ "envio-darwin-x64": "3.1.0",
77
+ "envio-darwin-arm64": "3.1.0"
78
78
  }
79
79
  }
@@ -1159,6 +1159,7 @@ let injectedTaskReducer = (
1159
1159
  ~persistence=state.ctx.persistence,
1160
1160
  ~rollbackTargetCheckpointId,
1161
1161
  ~rollbackDiffCheckpointId=state.ctx.inMemoryStore.committedCheckpointId->BigInt.add(1n),
1162
+ ~progressBlockNumberByChainId=newProgressBlockNumberPerChain,
1162
1163
  )
1163
1164
 
1164
1165
  let chainManager = {
@@ -1151,7 +1151,7 @@ function injectedTaskReducer(waitForNewBlock, executeQuery, getLastKnownValidBlo
1151
1151
  };
1152
1152
  });
1153
1153
  await InMemoryStore.flush(state.ctx.inMemoryStore);
1154
- let diff$1 = await InMemoryStore.prepareRollbackDiff(state.ctx.inMemoryStore, state.ctx.persistence, rollbackTargetCheckpointId, state.ctx.inMemoryStore.committedCheckpointId + 1n);
1154
+ let diff$1 = await InMemoryStore.prepareRollbackDiff(state.ctx.inMemoryStore, state.ctx.persistence, rollbackTargetCheckpointId, state.ctx.inMemoryStore.committedCheckpointId + 1n, newProgressBlockNumberPerChain);
1155
1155
  let init = state.chainManager;
1156
1156
  let chainManager_isInReorgThreshold = init.isInReorgThreshold;
1157
1157
  let chainManager_isRealtime = init.isRealtime;
@@ -359,6 +359,12 @@ let runOneWrite = async (inMemoryStore: t, ~persistence: Persistence.t, ~config)
359
359
  )
360
360
 
361
361
  inMemoryStore.committedCheckpointId = upToCheckpointId
362
+
363
+ switch rollback {
364
+ | Some({progressBlockNumberByChainId}) if RollbackCommit.callbacks->Utils.Array.notEmpty =>
365
+ await RollbackCommit.fire(~progressBlockNumberByChainId)
366
+ | _ => ()
367
+ }
362
368
  }
363
369
  }
364
370
 
@@ -494,12 +500,14 @@ let prepareRollbackDiff = async (
494
500
  ~persistence: Persistence.t,
495
501
  ~rollbackTargetCheckpointId,
496
502
  ~rollbackDiffCheckpointId,
503
+ ~progressBlockNumberByChainId,
497
504
  ) => {
498
505
  inMemoryStore.entities = EntityTables.make(inMemoryStore.allEntities)
499
506
  inMemoryStore.effects = Dict.make()
500
507
  inMemoryStore.rollback = Some({
501
508
  targetCheckpointId: rollbackTargetCheckpointId,
502
509
  diffCheckpointId: rollbackDiffCheckpointId,
510
+ progressBlockNumberByChainId,
503
511
  })
504
512
 
505
513
  let deletedEntities = Dict.make()
@@ -11,6 +11,7 @@ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
11
11
  import * as ErrorHandling from "./ErrorHandling.res.mjs";
12
12
  import * as InMemoryTable from "./InMemoryTable.res.mjs";
13
13
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
14
+ import * as RollbackCommit from "./RollbackCommit.res.mjs";
14
15
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
15
16
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
16
17
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
@@ -300,6 +301,9 @@ async function runOneWrite(inMemoryStore, persistence, config) {
300
301
  let updatedEffectsCache = snapshotEffects(inMemoryStore, cache);
301
302
  await persistence.storage.writeBatch(batch, rollback, batch.isInReorgThreshold, config, persistence.allEntities, updatedEffectsCache, updatedEntities, chainMetaData);
302
303
  inMemoryStore.committedCheckpointId = upToCheckpointId;
304
+ if (rollback !== undefined && Utils.$$Array.notEmpty(RollbackCommit.callbacks)) {
305
+ return await RollbackCommit.fire(rollback.progressBlockNumberByChainId);
306
+ }
303
307
  }
304
308
 
305
309
  function hasPendingWrite(inMemoryStore) {
@@ -401,12 +405,13 @@ async function flush(inMemoryStore) {
401
405
  }
402
406
  }
403
407
 
404
- async function prepareRollbackDiff(inMemoryStore, persistence, rollbackTargetCheckpointId, rollbackDiffCheckpointId) {
408
+ async function prepareRollbackDiff(inMemoryStore, persistence, rollbackTargetCheckpointId, rollbackDiffCheckpointId, progressBlockNumberByChainId) {
405
409
  inMemoryStore.entities = make(inMemoryStore.allEntities);
406
410
  inMemoryStore.effects = {};
407
411
  inMemoryStore.rollback = {
408
412
  targetCheckpointId: rollbackTargetCheckpointId,
409
- diffCheckpointId: rollbackDiffCheckpointId
413
+ diffCheckpointId: rollbackDiffCheckpointId,
414
+ progressBlockNumberByChainId: progressBlockNumberByChainId
410
415
  };
411
416
  let deletedEntities = {};
412
417
  let setEntities = {};
package/src/Main.res CHANGED
@@ -312,6 +312,13 @@ let getGlobalIndexer = (): 'indexer => {
312
312
  )
313
313
  }
314
314
 
315
+ let onRollbackCommitFn = (callback: 'a) => {
316
+ HandlerRegister.throwIfFinishedRegistration(
317
+ ~methodName="~internalAndWillBeRemovedSoon_onRollbackCommit",
318
+ )
319
+ let _ = RollbackCommit.register(callback->(Utils.magic: 'a => RollbackCommit.callback))
320
+ }
321
+
315
322
  // Two-stage parse: first the ecosystem-specific outer schema unwraps the
316
323
  // wrapper (`block.number` / `block.height` / `slot`) and surfaces the
317
324
  // inner chunk as raw `unknown`; then the shared `blockRangeSchema`
@@ -453,8 +460,16 @@ let getGlobalIndexer = (): 'indexer => {
453
460
  "onEvent",
454
461
  "contractRegister",
455
462
  "onBlock",
463
+ "~internalAndWillBeRemovedSoon_onRollbackCommit",
464
+ ]
465
+ | Svm => [
466
+ "name",
467
+ "description",
468
+ "chainIds",
469
+ "chains",
470
+ "onSlot",
471
+ "~internalAndWillBeRemovedSoon_onRollbackCommit",
456
472
  ]
457
- | Svm => ["name", "description", "chainIds", "chains", "onSlot"]
458
473
  }
459
474
  keysMemo := Some(keys)
460
475
  keys
@@ -477,6 +492,7 @@ let getGlobalIndexer = (): 'indexer => {
477
492
  | "onEvent" => onEventFn->Utils.magic
478
493
  | "contractRegister" => contractRegisterFn->Utils.magic
479
494
  | "onBlock" | "onSlot" => onBlockFn->Utils.magic
495
+ | "~internalAndWillBeRemovedSoon_onRollbackCommit" => onRollbackCommitFn->Utils.magic
480
496
  | _ =>
481
497
  JsError.throwWithMessage(
482
498
  `Field \`${prop}\` does not exist on \`indexer\`. Available fields: ${getKeys()->Array.join(
package/src/Main.res.mjs CHANGED
@@ -25,6 +25,7 @@ import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
25
25
  import * as SourceManager from "./sources/SourceManager.res.mjs";
26
26
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
27
27
  import * as Helpers from "yargs/helpers";
28
+ import * as RollbackCommit from "./RollbackCommit.res.mjs";
28
29
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
29
30
  import * as HandlerRegister from "./HandlerRegister.res.mjs";
30
31
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
@@ -255,6 +256,10 @@ function getGlobalIndexer() {
255
256
  let match = parseIdentityConfig(identityConfig);
256
257
  HandlerRegister.setContractRegister(match[0], match[1], handler, match[2], undefined);
257
258
  };
259
+ let onRollbackCommitFn = callback => {
260
+ HandlerRegister.throwIfFinishedRegistration("~internalAndWillBeRemovedSoon_onRollbackCommit");
261
+ RollbackCommit.register(callback);
262
+ };
258
263
  let extractRange = (filter, name, ecosystem) => {
259
264
  try {
260
265
  let inner = S$RescriptSchema.parseOrThrow(filter, ecosystem.onBlockFilterSchema);
@@ -341,7 +346,8 @@ function getGlobalIndexer() {
341
346
  "description",
342
347
  "chainIds",
343
348
  "chains",
344
- "onSlot"
349
+ "onSlot",
350
+ "~internalAndWillBeRemovedSoon_onRollbackCommit"
345
351
  ];
346
352
  break;
347
353
  }
@@ -353,7 +359,8 @@ function getGlobalIndexer() {
353
359
  "chains",
354
360
  "onEvent",
355
361
  "contractRegister",
356
- "onBlock"
362
+ "onBlock",
363
+ "~internalAndWillBeRemovedSoon_onRollbackCommit"
357
364
  ];
358
365
  }
359
366
  keysMemo.contents = keys;
@@ -376,6 +383,8 @@ function getGlobalIndexer() {
376
383
  case "onBlock" :
377
384
  case "onSlot" :
378
385
  return onBlockFn;
386
+ case "~internalAndWillBeRemovedSoon_onRollbackCommit" :
387
+ return onRollbackCommitFn;
379
388
  default:
380
389
  return Stdlib_JsError.throwWithMessage(`Field \`` + prop + `\` does not exist on \`indexer\`. Available fields: ` + getKeys().join(", ") + `.`);
381
390
  }
@@ -51,6 +51,9 @@ type updatedEffectCache = {
51
51
  type rollback = {
52
52
  targetCheckpointId: Internal.checkpointId,
53
53
  diffCheckpointId: Internal.checkpointId,
54
+ // Last valid block per chain affected by the rollback. Read by
55
+ // `RollbackCommit.fire` once the diff is durably written.
56
+ progressBlockNumberByChainId: dict<int>,
54
57
  }
55
58
 
56
59
  type updatedEntity = {
@@ -0,0 +1,32 @@
1
+ // Temporary, internal-only support for the unstable
2
+ // `indexer.~internalAndWillBeRemovedSoon_onRollbackCommit` API. The whole
3
+ // feature lives here plus two call sites: registration in `Main.res` and the
4
+ // fire on a successful rollback write in `InMemoryStore.res`. Delete those
5
+ // together with this module.
6
+ type args = {chainId: int, rollbackToBlock: int}
7
+ type callback = args => promise<unit>
8
+
9
+ let callbacks: array<callback> = []
10
+
11
+ let register = (callback: callback) => {
12
+ callbacks->Array.push(callback)
13
+ () =>
14
+ switch callbacks->Array.indexOf(callback) {
15
+ | -1 => ()
16
+ | index => callbacks->Array.splice(~start=index, ~remove=1, ~insert=[])
17
+ }
18
+ }
19
+
20
+ // Fired after a rollback diff is durably written, once per affected chain.
21
+ // `progressBlockNumberByChainId` is the last valid block per chain, taken from
22
+ // the in-memory store's rollback object. A throwing callback bubbles to the
23
+ // write loop's onError, crashing the indexer like a failed write.
24
+ let fire = async (~progressBlockNumberByChainId: dict<int>) => {
25
+ let _ = await progressBlockNumberByChainId
26
+ ->Dict.toArray
27
+ ->Array.flatMap(((chainIdKey, rollbackToBlock)) => {
28
+ let args = {chainId: chainIdKey->Int.fromString->Option.getUnsafe, rollbackToBlock}
29
+ callbacks->Array.map(callback => callback(args))
30
+ })
31
+ ->Promise.all
32
+ }
@@ -0,0 +1,35 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
4
+
5
+ let callbacks = [];
6
+
7
+ function register(callback) {
8
+ callbacks.push(callback);
9
+ return () => {
10
+ let index = callbacks.indexOf(callback);
11
+ if (index !== -1) {
12
+ callbacks.splice(index, 1);
13
+ return;
14
+ }
15
+ };
16
+ }
17
+
18
+ async function fire(progressBlockNumberByChainId) {
19
+ await Promise.all(Object.entries(progressBlockNumberByChainId).flatMap(param => {
20
+ let args_chainId = Stdlib_Int.fromString(param[0], undefined);
21
+ let args_rollbackToBlock = param[1];
22
+ let args = {
23
+ chainId: args_chainId,
24
+ rollbackToBlock: args_rollbackToBlock
25
+ };
26
+ return callbacks.map(callback => callback(args));
27
+ }));
28
+ }
29
+
30
+ export {
31
+ callbacks,
32
+ register,
33
+ fire,
34
+ }
35
+ /* No side effect */