@xyo-network/event-kit-statement-graph 0.1.5 → 0.1.8
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/README.md +29 -11
- package/dist/neutral/finalizedReplayChain.d.ts +16 -0
- package/dist/neutral/finalizedReplayChain.d.ts.map +1 -0
- package/dist/neutral/finalizedReplayController.d.ts +19 -3
- package/dist/neutral/finalizedReplayController.d.ts.map +1 -1
- package/dist/neutral/index.d.ts +2 -1
- package/dist/neutral/index.d.ts.map +1 -1
- package/dist/neutral/index.mjs +264 -93
- package/dist/neutral/index.mjs.map +4 -4
- package/dist/neutral/replayCheckpoint.d.ts +23 -22
- package/dist/neutral/replayCheckpoint.d.ts.map +1 -1
- package/package.json +12 -12
package/dist/neutral/index.mjs
CHANGED
|
@@ -217,9 +217,9 @@ var EventKitClaimedObjectSchemas = Object.freeze([
|
|
|
217
217
|
var EventKitClaimedObjectSchemaSet = new Set(EventKitClaimedObjectSchemas);
|
|
218
218
|
|
|
219
219
|
// src/finalizedReplayController.ts
|
|
220
|
-
import { HashZod as
|
|
220
|
+
import { HashZod as HashZod4 } from "@ariestools/sdk";
|
|
221
221
|
import {
|
|
222
|
-
ChainIdZod as
|
|
222
|
+
ChainIdZod as ChainIdZod3,
|
|
223
223
|
normalizeAddress as normalizeAddress3,
|
|
224
224
|
NormalizedAddressZod as NormalizedAddressZod3,
|
|
225
225
|
WakeSubscriptionAcceptanceSchema as WakeSubscriptionAcceptanceSchema2,
|
|
@@ -231,13 +231,70 @@ import {
|
|
|
231
231
|
scanFinalizedStatements
|
|
232
232
|
} from "@xyo-network/xl1-statement-graph-sdk";
|
|
233
233
|
|
|
234
|
-
// src/
|
|
234
|
+
// src/finalizedReplayChain.ts
|
|
235
235
|
import { HashZod as HashZod2 } from "@ariestools/sdk";
|
|
236
|
+
import { ChainIdZod } from "@xyo-network/event-kit-schemas";
|
|
237
|
+
import { PayloadBuilder } from "@xyo-network/sdk";
|
|
238
|
+
import { isBlockBoundWitness } from "@xyo-network/xl1-protocol";
|
|
239
|
+
async function requireBlockIdentity(chain, raw, chainId, requestedBlock) {
|
|
240
|
+
if (!Array.isArray(raw) || raw.length !== 2 || !Array.isArray(raw[1])) {
|
|
241
|
+
throw new TypeError(requestedBlock === void 0 ? "finalized block is unavailable" : `finalized block ${requestedBlock} is unavailable`);
|
|
242
|
+
}
|
|
243
|
+
const header = raw[0];
|
|
244
|
+
if (!isBlockBoundWitness(header) || !Number.isSafeInteger(header.block) || header.block < 0) {
|
|
245
|
+
throw new TypeError("finalized block has an invalid header");
|
|
246
|
+
}
|
|
247
|
+
const block = header.block;
|
|
248
|
+
const expectedChainId = chain.chainId === void 0 ? chainId : ChainIdZod.parse(String(await chain.chainId(block)).toLowerCase());
|
|
249
|
+
if (requestedBlock !== void 0 && block !== requestedBlock || header.chain !== expectedChainId) {
|
|
250
|
+
throw new TypeError(`finalized block ${block} does not match the configured chain`);
|
|
251
|
+
}
|
|
252
|
+
return header;
|
|
253
|
+
}
|
|
254
|
+
async function exactFinalizedBlockHash(chain, block, chainId) {
|
|
255
|
+
const raw = await chain.block.blockByNumber(block);
|
|
256
|
+
const header = await requireBlockIdentity(chain, raw, chainId, block);
|
|
257
|
+
const hash = await PayloadBuilder.hash(PayloadBuilder.omitStorageMeta(header));
|
|
258
|
+
const storageHash = header._hash;
|
|
259
|
+
if (typeof storageHash === "string" && storageHash !== hash) {
|
|
260
|
+
throw new TypeError(`finalized block ${block} has invalid storage hash metadata`);
|
|
261
|
+
}
|
|
262
|
+
return HashZod2.parse(hash);
|
|
263
|
+
}
|
|
264
|
+
function lineageValidatingScanChain(chain, chainId) {
|
|
265
|
+
return {
|
|
266
|
+
block: {
|
|
267
|
+
async blockByNumber(block) {
|
|
268
|
+
const raw = await chain.block.blockByNumber(block);
|
|
269
|
+
await requireBlockIdentity(chain, raw, chainId, block);
|
|
270
|
+
return raw;
|
|
271
|
+
},
|
|
272
|
+
...chain.block.blocksByNumber === void 0 ? {} : {
|
|
273
|
+
async blocksByNumber(high, count) {
|
|
274
|
+
const values = await chain.block.blocksByNumber?.(high, count) ?? [];
|
|
275
|
+
for (const value of values) await requireBlockIdentity(chain, value, chainId);
|
|
276
|
+
return values;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
finalization: chain.finalization
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
async function requireCurrentReplayChain(chain, finalizedHead, chainId) {
|
|
284
|
+
if (chain.chainId === void 0) return;
|
|
285
|
+
const headChainId = ChainIdZod.parse(String(await chain.chainId(finalizedHead)).toLowerCase());
|
|
286
|
+
if (headChainId !== chainId) {
|
|
287
|
+
throw new TypeError(`finalized head ${finalizedHead} does not match the configured current chain`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/replayCheckpoint.ts
|
|
292
|
+
import { HashZod as HashZod3 } from "@ariestools/sdk";
|
|
236
293
|
import {
|
|
237
|
-
ChainIdZod,
|
|
294
|
+
ChainIdZod as ChainIdZod2,
|
|
238
295
|
NormalizedAddressZod as NormalizedAddressZod2
|
|
239
296
|
} from "@xyo-network/event-kit-schemas";
|
|
240
|
-
import { PayloadBuilder } from "@xyo-network/sdk";
|
|
297
|
+
import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk";
|
|
241
298
|
import {
|
|
242
299
|
AppliedEventRecordZod,
|
|
243
300
|
BlockNumberZod,
|
|
@@ -249,10 +306,10 @@ import {
|
|
|
249
306
|
StatementScanCheckpointZod
|
|
250
307
|
} from "@xyo-network/xl1-statement-graph-sdk";
|
|
251
308
|
import { z } from "zod";
|
|
252
|
-
var EVENT_KIT_REPLAY_CHECKPOINT_VERSION =
|
|
309
|
+
var EVENT_KIT_REPLAY_CHECKPOINT_VERSION = 3;
|
|
253
310
|
var ResolvedReplayBodyZod = z.strictObject({
|
|
254
311
|
body: z.record(z.string(), z.unknown()),
|
|
255
|
-
hash:
|
|
312
|
+
hash: HashZod3
|
|
256
313
|
});
|
|
257
314
|
var ReplayCorruptBodyZod = z.strictObject({
|
|
258
315
|
claimedHash: z.string().optional(),
|
|
@@ -261,18 +318,19 @@ var ReplayCorruptBodyZod = z.strictObject({
|
|
|
261
318
|
var ReplayBlockedStateZod = z.strictObject({
|
|
262
319
|
atBlock: BlockNumberZod,
|
|
263
320
|
corrupt: z.array(ReplayCorruptBodyZod),
|
|
264
|
-
objectHashes: z.array(
|
|
321
|
+
objectHashes: z.array(HashZod3),
|
|
265
322
|
unresolvedEvents: z.array(UnresolvedEventReferenceZod)
|
|
266
323
|
});
|
|
267
324
|
var EventKitReplayCheckpointZod = z.strictObject({
|
|
268
325
|
applied: z.array(AppliedEventRecordZod),
|
|
269
326
|
blocked: ReplayBlockedStateZod.optional(),
|
|
270
327
|
bodies: z.array(ResolvedReplayBodyZod),
|
|
271
|
-
chainId:
|
|
328
|
+
chainId: ChainIdZod2,
|
|
272
329
|
finalizedHead: BlockNumberZod,
|
|
273
330
|
floorBlock: BlockNumberZod,
|
|
274
331
|
foldVersion: z.literal(STATEMENT_FOLD_VERSION),
|
|
275
332
|
indexedThrough: z.union([BlockNumberZod, z.null()]),
|
|
333
|
+
indexedThroughHash: z.union([HashZod3, z.null()]),
|
|
276
334
|
network: z.string().min(1),
|
|
277
335
|
objectSchemas: z.tuple(EventKitClaimedObjectSchemas.map((schema) => z.literal(schema))),
|
|
278
336
|
publisher: NormalizedAddressZod2,
|
|
@@ -280,6 +338,22 @@ var EventKitReplayCheckpointZod = z.strictObject({
|
|
|
280
338
|
sourceId: z.string().min(1),
|
|
281
339
|
version: z.literal(EVENT_KIT_REPLAY_CHECKPOINT_VERSION)
|
|
282
340
|
});
|
|
341
|
+
var LegacyEventKitReplayCheckpointIdentityZod = z.looseObject({
|
|
342
|
+
chainId: ChainIdZod2,
|
|
343
|
+
floorBlock: BlockNumberZod,
|
|
344
|
+
network: z.string().min(1),
|
|
345
|
+
publisher: NormalizedAddressZod2,
|
|
346
|
+
sourceId: z.string().min(1),
|
|
347
|
+
version: z.literal(2)
|
|
348
|
+
});
|
|
349
|
+
function checkpointIdentityError(checkpoint, identity) {
|
|
350
|
+
if (checkpoint.chainId !== identity.chainId) return `chainId ${checkpoint.chainId} != ${identity.chainId}`;
|
|
351
|
+
if (checkpoint.floorBlock !== identity.floorBlock) return `floorBlock ${checkpoint.floorBlock} != ${identity.floorBlock}`;
|
|
352
|
+
if (checkpoint.network !== identity.network) return `network ${checkpoint.network} != ${identity.network}`;
|
|
353
|
+
if (checkpoint.sourceId !== identity.sourceId) return `sourceId ${checkpoint.sourceId} != ${identity.sourceId}`;
|
|
354
|
+
if (checkpoint.publisher !== identity.publisher) return `publisher ${checkpoint.publisher} != ${identity.publisher}`;
|
|
355
|
+
return void 0;
|
|
356
|
+
}
|
|
283
357
|
function appliedKey(record) {
|
|
284
358
|
return `${record.txHash}:${record.eventHash}:${record.hashIndex}`;
|
|
285
359
|
}
|
|
@@ -328,7 +402,7 @@ function sameClaimRecords(left, right) {
|
|
|
328
402
|
});
|
|
329
403
|
}
|
|
330
404
|
function progressIntegrityError(checkpoint) {
|
|
331
|
-
const { indexedThrough } = checkpoint;
|
|
405
|
+
const { indexedThrough, indexedThroughHash } = checkpoint;
|
|
332
406
|
if (indexedThrough !== null && indexedThrough > checkpoint.finalizedHead) {
|
|
333
407
|
return `indexedThrough ${indexedThrough} exceeds finalizedHead ${checkpoint.finalizedHead}`;
|
|
334
408
|
}
|
|
@@ -341,6 +415,9 @@ function progressIntegrityError(checkpoint) {
|
|
|
341
415
|
if (indexedThrough !== null && checkpoint.scan === null) {
|
|
342
416
|
return "scan checkpoint is missing for indexed state";
|
|
343
417
|
}
|
|
418
|
+
if (indexedThrough === null !== (indexedThroughHash === null)) {
|
|
419
|
+
return "indexedThrough and indexedThroughHash must be present together";
|
|
420
|
+
}
|
|
344
421
|
if (indexedThrough === null && checkpoint.applied.length > 0) {
|
|
345
422
|
return "applied events exist before floorBlock has been indexed";
|
|
346
423
|
}
|
|
@@ -500,7 +577,7 @@ async function persistedBodyIntegrityError(checkpoint) {
|
|
|
500
577
|
for (const entry of checkpoint.bodies) {
|
|
501
578
|
let computedHash;
|
|
502
579
|
try {
|
|
503
|
-
computedHash = await
|
|
580
|
+
computedHash = await PayloadBuilder2.dataHash(entry.body);
|
|
504
581
|
} catch {
|
|
505
582
|
return `persisted body ${entry.hash} cannot be hashed`;
|
|
506
583
|
}
|
|
@@ -512,26 +589,21 @@ async function persistedBodyIntegrityError(checkpoint) {
|
|
|
512
589
|
}
|
|
513
590
|
async function loadEventKitReplayCheckpoint(value, identity) {
|
|
514
591
|
if (value === void 0 || value === null) return { status: "missing" };
|
|
592
|
+
if (typeof value === "object" && value !== null && value.version === 2) {
|
|
593
|
+
const legacy = LegacyEventKitReplayCheckpointIdentityZod.safeParse(value);
|
|
594
|
+
if (!legacy.success) {
|
|
595
|
+
return { detail: "recognized Event Kit replay checkpoint v2 has invalid identity", status: "corrupt" };
|
|
596
|
+
}
|
|
597
|
+
const mismatch2 = checkpointIdentityError(legacy.data, identity);
|
|
598
|
+
return mismatch2 === void 0 ? { status: "missing" } : { detail: mismatch2, status: "identity-mismatch" };
|
|
599
|
+
}
|
|
515
600
|
const parsed = EventKitReplayCheckpointZod.safeParse(value);
|
|
516
601
|
if (!parsed.success) {
|
|
517
602
|
return { detail: "recognized Event Kit replay checkpoint has invalid content", status: "corrupt" };
|
|
518
603
|
}
|
|
519
604
|
const checkpoint = parsed.data;
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
}
|
|
523
|
-
if (checkpoint.floorBlock !== identity.floorBlock) {
|
|
524
|
-
return { detail: `floorBlock ${checkpoint.floorBlock} != ${identity.floorBlock}`, status: "identity-mismatch" };
|
|
525
|
-
}
|
|
526
|
-
if (checkpoint.network !== identity.network) {
|
|
527
|
-
return { detail: `network ${checkpoint.network} != ${identity.network}`, status: "identity-mismatch" };
|
|
528
|
-
}
|
|
529
|
-
if (checkpoint.sourceId !== identity.sourceId) {
|
|
530
|
-
return { detail: `sourceId ${checkpoint.sourceId} != ${identity.sourceId}`, status: "identity-mismatch" };
|
|
531
|
-
}
|
|
532
|
-
if (checkpoint.publisher !== identity.publisher) {
|
|
533
|
-
return { detail: `publisher ${checkpoint.publisher} != ${identity.publisher}`, status: "identity-mismatch" };
|
|
534
|
-
}
|
|
605
|
+
const mismatch = checkpointIdentityError(checkpoint, identity);
|
|
606
|
+
if (mismatch !== void 0) return { detail: mismatch, status: "identity-mismatch" };
|
|
535
607
|
const bodyIntegrityError = await persistedBodyIntegrityError(checkpoint);
|
|
536
608
|
if (bodyIntegrityError !== void 0) return { detail: bodyIntegrityError, status: "corrupt" };
|
|
537
609
|
const integrityError = checkpointIntegrityError(checkpoint);
|
|
@@ -540,6 +612,8 @@ async function loadEventKitReplayCheckpoint(value, identity) {
|
|
|
540
612
|
}
|
|
541
613
|
|
|
542
614
|
// src/finalizedReplayController.ts
|
|
615
|
+
var DEFAULT_CHECKPOINT_BATCH_SIZE = 4096;
|
|
616
|
+
var DEFAULT_SCAN_BATCH_SIZE = 16;
|
|
543
617
|
function requireHead(value) {
|
|
544
618
|
const head = Number(value);
|
|
545
619
|
if (!Number.isSafeInteger(head) || head < 0) {
|
|
@@ -553,6 +627,19 @@ function requireFloor(value) {
|
|
|
553
627
|
}
|
|
554
628
|
return value;
|
|
555
629
|
}
|
|
630
|
+
function requirePositiveInteger(value, fallback, name) {
|
|
631
|
+
const selected = value ?? fallback;
|
|
632
|
+
if (!Number.isSafeInteger(selected) || selected < 1) {
|
|
633
|
+
throw new TypeError(`${name} must be a positive safe integer, received ${String(selected)}`);
|
|
634
|
+
}
|
|
635
|
+
return selected;
|
|
636
|
+
}
|
|
637
|
+
function requireMaxBlocks(value) {
|
|
638
|
+
if (value !== void 0 && (!Number.isSafeInteger(value) || value < 0)) {
|
|
639
|
+
throw new TypeError(`maxBlocks must be a nonnegative safe integer, received ${String(value)}`);
|
|
640
|
+
}
|
|
641
|
+
return value;
|
|
642
|
+
}
|
|
556
643
|
function replayContract(options, throughBlock) {
|
|
557
644
|
return {
|
|
558
645
|
eventBodyCorpus: { sourceId: options.sourceId },
|
|
@@ -572,6 +659,7 @@ function initialCheckpoint(options) {
|
|
|
572
659
|
floorBlock: options.floorBlock,
|
|
573
660
|
foldVersion: STATEMENT_FOLD_VERSION2,
|
|
574
661
|
indexedThrough: null,
|
|
662
|
+
indexedThroughHash: null,
|
|
575
663
|
network: options.network,
|
|
576
664
|
objectSchemas: [...EventKitClaimedObjectSchemas],
|
|
577
665
|
publisher: options.publisher,
|
|
@@ -613,23 +701,9 @@ function mergeBodies(existing, additions) {
|
|
|
613
701
|
}
|
|
614
702
|
merged.set(hash, body);
|
|
615
703
|
}
|
|
616
|
-
return [...merged].map(([hash, body]) => ({ body, hash:
|
|
704
|
+
return [...merged].map(([hash, body]) => ({ body, hash: HashZod4.parse(hash) })).toSorted((left, right) => left.hash.localeCompare(right.hash));
|
|
617
705
|
}
|
|
618
|
-
async function
|
|
619
|
-
const result = await scanFinalizedStatements(
|
|
620
|
-
options.chain,
|
|
621
|
-
options.bodies,
|
|
622
|
-
replayContract(options, block),
|
|
623
|
-
{
|
|
624
|
-
batchSize: 1,
|
|
625
|
-
...prior.scan === null ? {} : { resumeFrom: prior.scan },
|
|
626
|
-
strict: { rejectAmbiguousSchemaDeclarations: true },
|
|
627
|
-
through: block
|
|
628
|
-
}
|
|
629
|
-
);
|
|
630
|
-
const applied = result.fold.applied.filter(
|
|
631
|
-
(record) => normalizeAddress3(record.subject) === options.publisher
|
|
632
|
-
);
|
|
706
|
+
async function stageAppliedBlock(options, applied) {
|
|
633
707
|
const appliedObjectHashes = uniqueStrings(applied.map((record) => record.objectHash));
|
|
634
708
|
const objects = await resolveVerifiedBodies(options.bodies, appliedObjectHashes);
|
|
635
709
|
const missingObjects = appliedObjectHashes.filter((hash) => !objects.bodies.has(hash));
|
|
@@ -654,20 +728,73 @@ async function stageBlock(options, prior, block) {
|
|
|
654
728
|
...missingObjects,
|
|
655
729
|
...schemaMismatchedObjects,
|
|
656
730
|
...missingAttachments
|
|
657
|
-
]).map((hash) =>
|
|
658
|
-
const isBlocked = result.unresolved.length > 0 || objectHashes.length > 0 || corrupt.length > 0;
|
|
731
|
+
]).map((hash) => HashZod4.parse(hash));
|
|
659
732
|
return {
|
|
660
|
-
applied,
|
|
661
733
|
bodies: new Map([...objects.bodies, ...attachments.bodies]),
|
|
734
|
+
corrupt,
|
|
735
|
+
objectHashes
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
async function stageRange(options, prior, fromBlock, throughBlock, signal) {
|
|
739
|
+
signal?.throwIfAborted();
|
|
740
|
+
const beforeHash = await exactFinalizedBlockHash(options.chain, throughBlock, options.chainId);
|
|
741
|
+
signal?.throwIfAborted();
|
|
742
|
+
const result = await scanFinalizedStatements(
|
|
743
|
+
lineageValidatingScanChain(options.chain, options.chainId),
|
|
744
|
+
options.bodies,
|
|
745
|
+
replayContract(options, throughBlock),
|
|
746
|
+
{
|
|
747
|
+
batchSize: requirePositiveInteger(options.scanBatchSize, DEFAULT_SCAN_BATCH_SIZE, "scanBatchSize"),
|
|
748
|
+
...prior.scan === null ? {} : { resumeFrom: prior.scan },
|
|
749
|
+
...signal === void 0 ? {} : { signal },
|
|
750
|
+
strict: { rejectAmbiguousSchemaDeclarations: true },
|
|
751
|
+
through: throughBlock
|
|
752
|
+
}
|
|
753
|
+
);
|
|
754
|
+
signal?.throwIfAborted();
|
|
755
|
+
const throughHash = await exactFinalizedBlockHash(options.chain, throughBlock, options.chainId);
|
|
756
|
+
signal?.throwIfAborted();
|
|
757
|
+
if (beforeHash !== throughHash) {
|
|
758
|
+
throw new Error(`finalized block root changed while staging through ${throughBlock}`);
|
|
759
|
+
}
|
|
760
|
+
if (result.head !== throughBlock || result.checkpoint.contract.throughBlock !== throughBlock) {
|
|
761
|
+
throw new RangeError(
|
|
762
|
+
`finalized range scan stopped at ${result.head}/${result.checkpoint.contract.throughBlock}; requested ${throughBlock}`
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
const applied = result.fold.applied.filter((record) => record.block >= fromBlock && record.block <= throughBlock && normalizeAddress3(record.subject) === options.publisher);
|
|
766
|
+
const appliedByBlock = Map.groupBy(applied, (record) => record.block);
|
|
767
|
+
const unresolvedByBlock = Map.groupBy(
|
|
768
|
+
result.unresolved.filter((event) => event.block >= fromBlock && event.block <= throughBlock),
|
|
769
|
+
(event) => event.block
|
|
770
|
+
);
|
|
771
|
+
const relevantBlocks = [.../* @__PURE__ */ new Set([...appliedByBlock.keys(), ...unresolvedByBlock.keys()])].toSorted((left, right) => left - right);
|
|
772
|
+
const bodies = /* @__PURE__ */ new Map();
|
|
773
|
+
for (const block of relevantBlocks) {
|
|
774
|
+
signal?.throwIfAborted();
|
|
775
|
+
const staged = await stageAppliedBlock(options, appliedByBlock.get(block) ?? []);
|
|
776
|
+
for (const [hash, body] of staged.bodies) bodies.set(hash, body);
|
|
777
|
+
const unresolvedEvents = unresolvedByBlock.get(block) ?? [];
|
|
778
|
+
if (unresolvedEvents.length > 0 || staged.objectHashes.length > 0 || staged.corrupt.length > 0) {
|
|
779
|
+
return {
|
|
780
|
+
applied,
|
|
781
|
+
blocked: {
|
|
782
|
+
atBlock: block,
|
|
783
|
+
corrupt: staged.corrupt,
|
|
784
|
+
objectHashes: staged.objectHashes,
|
|
785
|
+
unresolvedEvents
|
|
786
|
+
},
|
|
787
|
+
bodies,
|
|
788
|
+
scan: result.checkpoint,
|
|
789
|
+
throughHash
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
return {
|
|
794
|
+
applied,
|
|
795
|
+
bodies,
|
|
662
796
|
scan: result.checkpoint,
|
|
663
|
-
|
|
664
|
-
blocked: {
|
|
665
|
-
atBlock: block,
|
|
666
|
-
corrupt,
|
|
667
|
-
objectHashes,
|
|
668
|
-
unresolvedEvents: result.unresolved
|
|
669
|
-
}
|
|
670
|
-
} : {}
|
|
797
|
+
throughHash
|
|
671
798
|
};
|
|
672
799
|
}
|
|
673
800
|
var DefaultFinalizedEventKitReplayController = class {
|
|
@@ -678,6 +805,9 @@ var DefaultFinalizedEventKitReplayController = class {
|
|
|
678
805
|
this.#options = options;
|
|
679
806
|
this.#checkpoint = checkpoint;
|
|
680
807
|
}
|
|
808
|
+
anchor() {
|
|
809
|
+
return this.#checkpoint.indexedThrough === null || this.#checkpoint.indexedThroughHash === null ? null : Object.freeze({ block: this.#checkpoint.indexedThrough, hash: this.#checkpoint.indexedThroughHash });
|
|
810
|
+
}
|
|
681
811
|
body(hash) {
|
|
682
812
|
return this.#checkpoint.bodies.find((entry) => entry.hash === hash)?.body;
|
|
683
813
|
}
|
|
@@ -691,8 +821,8 @@ var DefaultFinalizedEventKitReplayController = class {
|
|
|
691
821
|
indexedThrough: this.#checkpoint.indexedThrough
|
|
692
822
|
};
|
|
693
823
|
}
|
|
694
|
-
sync() {
|
|
695
|
-
const result = this.#syncTail.then(async () => await this.#syncOnce());
|
|
824
|
+
sync(options) {
|
|
825
|
+
const result = this.#syncTail.then(async () => await this.#syncOnce(options));
|
|
696
826
|
this.#syncTail = result.then(
|
|
697
827
|
() => true,
|
|
698
828
|
() => false
|
|
@@ -702,8 +832,56 @@ var DefaultFinalizedEventKitReplayController = class {
|
|
|
702
832
|
viewer() {
|
|
703
833
|
return createCheckpointStatementGraphViewer(this.#checkpoint);
|
|
704
834
|
}
|
|
705
|
-
async #
|
|
835
|
+
async #commitRange(fromBlock, throughBlock, finalizedHead, signal) {
|
|
836
|
+
const staged = await stageRange(this.#options, this.#checkpoint, fromBlock, throughBlock, signal);
|
|
837
|
+
signal?.throwIfAborted();
|
|
838
|
+
if (staged.blocked !== void 0) {
|
|
839
|
+
const blockedAt = staged.blocked.atBlock;
|
|
840
|
+
if (blockedAt > fromBlock) {
|
|
841
|
+
const prefixBlocked = await this.#commitRange(fromBlock, blockedAt - 1, finalizedHead, signal);
|
|
842
|
+
if (prefixBlocked) return true;
|
|
843
|
+
}
|
|
844
|
+
const exact = await stageRange(this.#options, this.#checkpoint, blockedAt, blockedAt, signal);
|
|
845
|
+
signal?.throwIfAborted();
|
|
846
|
+
if (exact.blocked === void 0) {
|
|
847
|
+
await this.#commitStaged(exact, blockedAt, finalizedHead, signal);
|
|
848
|
+
return blockedAt === throughBlock ? false : await this.#commitRange(blockedAt + 1, throughBlock, finalizedHead, signal);
|
|
849
|
+
}
|
|
850
|
+
const blocked = EventKitReplayCheckpointZod.parse({
|
|
851
|
+
...this.#checkpoint,
|
|
852
|
+
blocked: exact.blocked,
|
|
853
|
+
finalizedHead
|
|
854
|
+
});
|
|
855
|
+
signal?.throwIfAborted();
|
|
856
|
+
await this.#options.checkpointStore.save(blocked);
|
|
857
|
+
this.#checkpoint = blocked;
|
|
858
|
+
return true;
|
|
859
|
+
}
|
|
860
|
+
await this.#commitStaged(staged, throughBlock, finalizedHead, signal);
|
|
861
|
+
return false;
|
|
862
|
+
}
|
|
863
|
+
async #commitStaged(staged, throughBlock, finalizedHead, signal) {
|
|
864
|
+
const committed = EventKitReplayCheckpointZod.parse({
|
|
865
|
+
...this.#checkpoint,
|
|
866
|
+
applied: mergeApplied(this.#checkpoint.applied, staged.applied),
|
|
867
|
+
bodies: mergeBodies(this.#checkpoint.bodies, staged.bodies),
|
|
868
|
+
blocked: void 0,
|
|
869
|
+
finalizedHead,
|
|
870
|
+
indexedThrough: throughBlock,
|
|
871
|
+
indexedThroughHash: staged.throughHash,
|
|
872
|
+
scan: staged.scan
|
|
873
|
+
});
|
|
874
|
+
signal?.throwIfAborted();
|
|
875
|
+
await this.#options.checkpointStore.save(committed);
|
|
876
|
+
this.#checkpoint = committed;
|
|
877
|
+
}
|
|
878
|
+
async #syncOnce(rawOptions) {
|
|
879
|
+
const maxBlocks = requireMaxBlocks(rawOptions?.maxBlocks);
|
|
880
|
+
const signal = rawOptions?.signal;
|
|
881
|
+
signal?.throwIfAborted();
|
|
706
882
|
const finalizedHead = requireHead(await this.#options.chain.finalization.headNumber());
|
|
883
|
+
signal?.throwIfAborted();
|
|
884
|
+
await requireCurrentReplayChain(this.#options.chain, finalizedHead, this.#options.chainId);
|
|
707
885
|
if (finalizedHead < this.#checkpoint.finalizedHead) {
|
|
708
886
|
throw new RangeError(
|
|
709
887
|
`finalized head regressed from ${this.#checkpoint.finalizedHead} to ${finalizedHead}; refusing to roll back`
|
|
@@ -714,39 +892,26 @@ var DefaultFinalizedEventKitReplayController = class {
|
|
|
714
892
|
throw new RangeError(`finalized head ${finalizedHead} is behind indexedThrough ${indexedThrough}`);
|
|
715
893
|
}
|
|
716
894
|
let next = indexedThrough === null ? this.#options.floorBlock : indexedThrough + 1;
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
const committed = EventKitReplayCheckpointZod.parse({
|
|
731
|
-
...this.#checkpoint,
|
|
732
|
-
applied: mergeApplied(this.#checkpoint.applied, staged.applied),
|
|
733
|
-
bodies: mergeBodies(this.#checkpoint.bodies, staged.bodies),
|
|
734
|
-
blocked: void 0,
|
|
735
|
-
finalizedHead,
|
|
736
|
-
indexedThrough: next,
|
|
737
|
-
scan: staged.scan
|
|
738
|
-
});
|
|
739
|
-
await this.#options.checkpointStore.save(committed);
|
|
740
|
-
this.#checkpoint = committed;
|
|
741
|
-
changed = false;
|
|
742
|
-
next += 1;
|
|
895
|
+
const remaining = next <= finalizedHead ? finalizedHead - next + 1 : 0;
|
|
896
|
+
const budget = maxBlocks === void 0 ? remaining : Math.min(maxBlocks, remaining);
|
|
897
|
+
const target = budget === 0 ? next - 1 : next + budget - 1;
|
|
898
|
+
const checkpointBatchSize = requirePositiveInteger(
|
|
899
|
+
this.#options.checkpointBatchSize,
|
|
900
|
+
DEFAULT_CHECKPOINT_BATCH_SIZE,
|
|
901
|
+
"checkpointBatchSize"
|
|
902
|
+
);
|
|
903
|
+
while (next <= target) {
|
|
904
|
+
signal?.throwIfAborted();
|
|
905
|
+
const throughBlock = Math.min(target, next + Math.min(checkpointBatchSize, target - next + 1) - 1);
|
|
906
|
+
if (await this.#commitRange(next, throughBlock, finalizedHead, signal)) return this.status();
|
|
907
|
+
next = throughBlock + 1;
|
|
743
908
|
}
|
|
744
|
-
if (
|
|
909
|
+
if (this.#checkpoint.finalizedHead !== finalizedHead) {
|
|
745
910
|
const observed = EventKitReplayCheckpointZod.parse({
|
|
746
911
|
...this.#checkpoint,
|
|
747
|
-
blocked: void 0,
|
|
748
912
|
finalizedHead
|
|
749
913
|
});
|
|
914
|
+
signal?.throwIfAborted();
|
|
750
915
|
await this.#options.checkpointStore.save(observed);
|
|
751
916
|
this.#checkpoint = observed;
|
|
752
917
|
}
|
|
@@ -756,10 +921,16 @@ var DefaultFinalizedEventKitReplayController = class {
|
|
|
756
921
|
async function createFinalizedEventKitReplayController(rawOptions) {
|
|
757
922
|
const options = {
|
|
758
923
|
...rawOptions,
|
|
759
|
-
chainId:
|
|
924
|
+
chainId: ChainIdZod3.parse(rawOptions.chainId),
|
|
925
|
+
checkpointBatchSize: requirePositiveInteger(
|
|
926
|
+
rawOptions.checkpointBatchSize,
|
|
927
|
+
DEFAULT_CHECKPOINT_BATCH_SIZE,
|
|
928
|
+
"checkpointBatchSize"
|
|
929
|
+
),
|
|
760
930
|
floorBlock: requireFloor(rawOptions.floorBlock),
|
|
761
931
|
network: rawOptions.network.trim(),
|
|
762
932
|
publisher: NormalizedAddressZod3.parse(rawOptions.publisher),
|
|
933
|
+
scanBatchSize: requirePositiveInteger(rawOptions.scanBatchSize, DEFAULT_SCAN_BATCH_SIZE, "scanBatchSize"),
|
|
763
934
|
sourceId: rawOptions.sourceId.trim()
|
|
764
935
|
};
|
|
765
936
|
if (options.network.length === 0) throw new TypeError("network must not be empty");
|
|
@@ -787,7 +958,7 @@ function createMemoryEventKitReplayCheckpointStore(initial) {
|
|
|
787
958
|
}
|
|
788
959
|
|
|
789
960
|
// src/grantReadModel.ts
|
|
790
|
-
import { HashZod as
|
|
961
|
+
import { HashZod as HashZod5 } from "@ariestools/sdk";
|
|
791
962
|
import { XyoAddressZod } from "@xyo-network/sdk-protocol/address";
|
|
792
963
|
function createStatementGraphGrantReadModel(options) {
|
|
793
964
|
const { viewer } = options;
|
|
@@ -800,7 +971,7 @@ function createStatementGraphGrantReadModel(options) {
|
|
|
800
971
|
return Object.freeze(records.map(toGrantClaim));
|
|
801
972
|
},
|
|
802
973
|
async object(objectHash) {
|
|
803
|
-
const record = await viewer.object(
|
|
974
|
+
const record = await viewer.object(HashZod5.parse(objectHash));
|
|
804
975
|
return record === void 0 ? void 0 : toGrantObject(record);
|
|
805
976
|
}
|
|
806
977
|
});
|
|
@@ -809,7 +980,7 @@ function toClaimQuery(query) {
|
|
|
809
980
|
if (query === void 0) return void 0;
|
|
810
981
|
return {
|
|
811
982
|
...query.declaredObjectSchemaPrefix === void 0 ? {} : { declaredObjectSchemaPrefix: query.declaredObjectSchemaPrefix },
|
|
812
|
-
...query.objectHash === void 0 ? {} : { objectHash:
|
|
983
|
+
...query.objectHash === void 0 ? {} : { objectHash: HashZod5.parse(query.objectHash) },
|
|
813
984
|
...query.subject === void 0 ? {} : { subject: XyoAddressZod.parse(query.subject) }
|
|
814
985
|
};
|
|
815
986
|
}
|
|
@@ -862,7 +1033,7 @@ import {
|
|
|
862
1033
|
selectPublisherService
|
|
863
1034
|
} from "@xyo-network/event-kit-protocol";
|
|
864
1035
|
import {
|
|
865
|
-
ChainIdZod as
|
|
1036
|
+
ChainIdZod as ChainIdZod4,
|
|
866
1037
|
NormalizedAddressZod as NormalizedAddressZod4,
|
|
867
1038
|
PublisherEncryptionKeyRevocationSchema as PublisherEncryptionKeyRevocationSchema2,
|
|
868
1039
|
PublisherEncryptionKeyRevocationZod,
|
|
@@ -874,7 +1045,7 @@ import {
|
|
|
874
1045
|
PublisherServiceZod,
|
|
875
1046
|
SOURCE_WAKE_EVENT_KIND as SOURCE_WAKE_EVENT_KIND2
|
|
876
1047
|
} from "@xyo-network/event-kit-schemas";
|
|
877
|
-
import { PayloadBuilder as
|
|
1048
|
+
import { PayloadBuilder as PayloadBuilder3 } from "@xyo-network/sdk";
|
|
878
1049
|
import { XyoAddressZod as XyoAddressZod2 } from "@xyo-network/sdk-protocol/address";
|
|
879
1050
|
function handshakeEvidence(record) {
|
|
880
1051
|
return {
|
|
@@ -914,12 +1085,12 @@ async function verifiedHandshakeObjectBody(viewer, record) {
|
|
|
914
1085
|
const object = await viewer.object(record.objectHash);
|
|
915
1086
|
if (object?.assurance !== "resolved" || object.declaredSchema !== record.objectSchema || object.params === null) return void 0;
|
|
916
1087
|
const body = { schema: object.declaredSchema, ...object.params };
|
|
917
|
-
return await
|
|
1088
|
+
return await PayloadBuilder3.dataHash(body) === record.objectHash ? body : void 0;
|
|
918
1089
|
}
|
|
919
1090
|
async function verifiedHandshakeAttachmentBody(resolver, hash) {
|
|
920
1091
|
const body = resolver?.(hash);
|
|
921
1092
|
if (body === void 0) return void 0;
|
|
922
|
-
return await
|
|
1093
|
+
return await PayloadBuilder3.dataHash(body) === hash ? { ...body } : void 0;
|
|
923
1094
|
}
|
|
924
1095
|
function firstHandshakeRevocation(revocations, target) {
|
|
925
1096
|
const blocks = revocations.filter((item) => item.target === target).map((item) => item.block);
|
|
@@ -1070,7 +1241,7 @@ function hasPendingPublisherService(catalogs, query) {
|
|
|
1070
1241
|
async function discoverHandshakeService(options, rawQuery) {
|
|
1071
1242
|
const query = {
|
|
1072
1243
|
...rawQuery,
|
|
1073
|
-
chainId:
|
|
1244
|
+
chainId: ChainIdZod4.parse(rawQuery.chainId),
|
|
1074
1245
|
eventKind: rawQuery.eventKind ?? SOURCE_WAKE_EVENT_KIND2,
|
|
1075
1246
|
publisher: NormalizedAddressZod4.parse(rawQuery.publisher)
|
|
1076
1247
|
};
|