@xyo-network/xl1-protocol-sdk 2.0.10 → 2.0.12

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.
Files changed (69) hide show
  1. package/README.md +3 -6
  2. package/dist/neutral/ChainContextHelpers.d.ts.map +1 -1
  3. package/dist/neutral/CreatableProvider/AbstractCreatableProvider.d.ts +8 -1
  4. package/dist/neutral/CreatableProvider/AbstractCreatableProvider.d.ts.map +1 -1
  5. package/dist/neutral/config/Actor.d.ts +48 -6
  6. package/dist/neutral/config/Actor.d.ts.map +1 -1
  7. package/dist/neutral/config/Actors.d.ts +8 -1
  8. package/dist/neutral/config/Actors.d.ts.map +1 -1
  9. package/dist/neutral/config/Base.d.ts +8 -1
  10. package/dist/neutral/config/Base.d.ts.map +1 -1
  11. package/dist/neutral/config/Config.d.ts +32 -4
  12. package/dist/neutral/config/Config.d.ts.map +1 -1
  13. package/dist/neutral/config/HostActor.d.ts +48 -6
  14. package/dist/neutral/config/HostActor.d.ts.map +1 -1
  15. package/dist/neutral/config/Log.d.ts +1 -1
  16. package/dist/neutral/config/index.d.ts +1 -1
  17. package/dist/neutral/config/index.d.ts.map +1 -1
  18. package/dist/neutral/config/storage/Storage.d.ts +7 -0
  19. package/dist/neutral/config/storage/Storage.d.ts.map +1 -1
  20. package/dist/neutral/config/storage/driver/R2.d.ts +25 -0
  21. package/dist/neutral/config/storage/driver/R2.d.ts.map +1 -0
  22. package/dist/neutral/config/storage/driver/index.d.ts +1 -0
  23. package/dist/neutral/config/storage/driver/index.d.ts.map +1 -1
  24. package/dist/neutral/context/Actor.d.ts +48 -6
  25. package/dist/neutral/context/Actor.d.ts.map +1 -1
  26. package/dist/neutral/context/HostActor.d.ts +48 -6
  27. package/dist/neutral/context/HostActor.d.ts.map +1 -1
  28. package/dist/neutral/getFileConfig.d.ts +16 -2
  29. package/dist/neutral/getFileConfig.d.ts.map +1 -1
  30. package/dist/neutral/getFileConfig.mjs +76 -44
  31. package/dist/neutral/getFileConfig.mjs.map +4 -4
  32. package/dist/neutral/index.d.ts +2 -1
  33. package/dist/neutral/index.d.ts.map +1 -1
  34. package/dist/neutral/index.mjs +820 -358
  35. package/dist/neutral/index.mjs.map +4 -4
  36. package/dist/neutral/model/CreatableProviderContext.zod.d.ts +48 -6
  37. package/dist/neutral/model/CreatableProviderContext.zod.d.ts.map +1 -1
  38. package/dist/neutral/simple/block/SimpleBlockViewer.d.ts +13 -2
  39. package/dist/neutral/simple/block/SimpleBlockViewer.d.ts.map +1 -1
  40. package/dist/neutral/simple/mempool/SimpleMempoolRunner.d.ts.map +1 -1
  41. package/dist/neutral/simple/windowedBlock/SimpleWindowedBlockViewer.d.ts +33 -0
  42. package/dist/neutral/simple/windowedBlock/SimpleWindowedBlockViewer.d.ts.map +1 -1
  43. package/dist/neutral/summary/model/BlocksStepSummary.d.ts +26 -0
  44. package/dist/neutral/summary/model/BlocksStepSummary.d.ts.map +1 -0
  45. package/dist/neutral/summary/model/index.d.ts +1 -0
  46. package/dist/neutral/summary/model/index.d.ts.map +1 -1
  47. package/dist/neutral/summary/primitives/blocks/blocksMaxStep.d.ts +13 -0
  48. package/dist/neutral/summary/primitives/blocks/blocksMaxStep.d.ts.map +1 -0
  49. package/dist/neutral/summary/primitives/blocks/blocksStepSummaryFromRange.d.ts +13 -0
  50. package/dist/neutral/summary/primitives/blocks/blocksStepSummaryFromRange.d.ts.map +1 -0
  51. package/dist/neutral/summary/primitives/blocks/index.d.ts +3 -0
  52. package/dist/neutral/summary/primitives/blocks/index.d.ts.map +1 -0
  53. package/dist/neutral/summary/primitives/index.d.ts +1 -0
  54. package/dist/neutral/summary/primitives/index.d.ts.map +1 -1
  55. package/dist/neutral/test/index.d.ts +1 -0
  56. package/dist/neutral/test/index.d.ts.map +1 -1
  57. package/dist/neutral/test/index.mjs +1164 -1044
  58. package/dist/neutral/test/index.mjs.map +4 -4
  59. package/package.json +19 -20
  60. package/dist/neutral/driver/cache/LruCacheMap.d.ts +0 -15
  61. package/dist/neutral/driver/cache/LruCacheMap.d.ts.map +0 -1
  62. package/dist/neutral/driver/cache/index.d.ts +0 -2
  63. package/dist/neutral/driver/cache/index.d.ts.map +0 -1
  64. package/dist/neutral/driver/index.d.ts +0 -3
  65. package/dist/neutral/driver/index.d.ts.map +0 -1
  66. package/dist/neutral/driver/memory/MemoryMap.d.ts +0 -14
  67. package/dist/neutral/driver/memory/MemoryMap.d.ts.map +0 -1
  68. package/dist/neutral/driver/memory/index.d.ts +0 -2
  69. package/dist/neutral/driver/memory/index.d.ts.map +0 -1
@@ -11,303 +11,843 @@ var __decorateClass = (decorators, target, key, kind) => {
11
11
  };
12
12
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
13
13
 
14
- // src/test/buildRandomTransaction.ts
15
- import { Account } from "@xyo-network/sdk-js";
16
- import { asXL1BlockNumber, isAllowedBlockPayload } from "@xyo-network/xl1-protocol-lib";
17
-
18
- // src/createTransferPayload.ts
19
- import { toHex } from "@xylabs/sdk-js";
20
- import { PayloadBuilder } from "@xyo-network/sdk-js";
21
- import { TransferSchema } from "@xyo-network/xl1-protocol-lib";
22
- function createTransferPayload(from, transfers, context) {
23
- return new PayloadBuilder({ schema: TransferSchema }).fields({
24
- epoch: Date.now(),
25
- from,
26
- transfers: Object.fromEntries(Object.entries(transfers).map(([k, v]) => [k, toHex(v)])),
27
- context
28
- }).build();
29
- }
30
-
31
- // src/transaction/buildTransaction.ts
32
- import { assertEx, toHex as toHex2 } from "@xylabs/sdk-js";
14
+ // src/test/buildRandomChain.ts
15
+ import { asAddress as asAddress2, assertEx as assertEx6 } from "@xylabs/sdk-js";
33
16
  import {
34
- asAnyPayload,
35
- BoundWitnessBuilder,
36
- PayloadBuilder as PayloadBuilder2
17
+ Account as Account3,
18
+ asSchema as asSchema2,
19
+ IdSchema as IdSchema2,
20
+ MemoryArchivist,
21
+ PayloadBuilder as PayloadBuilder8
37
22
  } from "@xyo-network/sdk-js";
38
- import { defaultTransactionFees } from "@xyo-network/xl1-protocol-lib";
39
- async function buildTransaction(chain, onChainPayloads, offChainPayloads, signer, nbf, exp, from, fees = defaultTransactionFees) {
40
- if (from === void 0 && Array.isArray(signer)) {
41
- throw new Error("from is required when signer is an array");
42
- }
43
- const txBoundWitnessFields = {
44
- chain,
45
- fees: {
46
- base: toHex2(fees.base),
47
- gasLimit: toHex2(fees.gasLimit),
48
- gasPrice: toHex2(fees.gasPrice),
49
- priority: toHex2(fees.priority)
50
- },
51
- nbf,
52
- exp
53
- };
54
- const elevatedHashes = await PayloadBuilder2.hashes(onChainPayloads);
55
- const script = [];
56
- for (const elevatedHash of elevatedHashes) {
57
- script.push(`elevate|${elevatedHash}`);
58
- }
59
- const fields = {
60
- ...txBoundWitnessFields,
61
- from: from ?? (Array.isArray(signer) ? assertEx(signer.at(0)?.address) : signer.address)
62
- };
63
- if (script.length > 0) {
64
- fields.script = script;
65
- }
66
- const [tx, txPayloads] = await new BoundWitnessBuilder().fields(fields).meta({ $signatures: [] }).payloads([...onChainPayloads, ...offChainPayloads]).signers(Array.isArray(signer) ? signer : [signer]).build();
67
- return [await PayloadBuilder2.addHashMeta(tx), await PayloadBuilder2.addHashMeta(txPayloads.map((p) => asAnyPayload(p, true)))];
23
+ import {
24
+ asXL1BlockNumber as asXL1BlockNumber6
25
+ } from "@xyo-network/xl1-protocol-lib";
26
+
27
+ // src/block/hydrate/allHashesPresent.ts
28
+ function allHashesPresent(hashes, payloads) {
29
+ const payloadHashes = new Set(payloads.map((p) => p._hash));
30
+ return hashes.every((hash) => payloadHashes.has(hash));
68
31
  }
69
32
 
70
- // src/test/buildRandomTransaction.ts
71
- var buildRandomTransaction = async (chain, payloads, account, nbf = asXL1BlockNumber(0, true), exp = asXL1BlockNumber(nbf + 1e3, true), privatePayloadSchemas = [], receiverAddress) => {
72
- const elevatedPayloads = (payloads ?? []).filter(isAllowedBlockPayload);
73
- const additionalPayloads = (payloads ?? []).filter((payload) => !isAllowedBlockPayload(payload));
74
- const sender = account ?? await Account.random();
75
- if (elevatedPayloads.length === 0) {
76
- const receiver = receiverAddress ?? (await Account.random()).address;
77
- const transferPayload = createTransferPayload(sender.address, { [receiver]: 1n });
78
- elevatedPayloads.push(transferPayload);
79
- }
80
- const hydratedTransaction = await buildTransaction(chain, elevatedPayloads, additionalPayloads, sender, nbf, exp);
81
- return [hydratedTransaction[0], hydratedTransaction[1].filter((payload) => !privatePayloadSchemas.includes(payload.schema))];
33
+ // src/block/hydrate/flattenHydratedBlock.ts
34
+ import { toHydratedBlock } from "@xyo-network/xl1-protocol-lib";
35
+ var flattenHydratedBlock = (hydratedBlock) => {
36
+ const [blk, blkPayloads] = hydratedBlock;
37
+ return [...blkPayloads, blk];
82
38
  };
83
39
 
84
- // src/test/getSimpleBlockViewerLocator.ts
85
- import { XYO_ZERO_ADDRESS as XYO_ZERO_ADDRESS3 } from "@xyo-network/xl1-protocol-lib";
40
+ // src/block/hydrate/flattenHydratedBlocks.ts
41
+ var flattenHydratedBlocks = (hydratedBlocks) => hydratedBlocks.flatMap((blk) => flattenHydratedBlock(blk));
86
42
 
87
- // src/CreatableProvider/AbstractCreatableProvider.ts
43
+ // src/block/hydrate/hydrateBlock.ts
44
+ import { assertEx } from "@xylabs/sdk-js";
45
+ import { asAnyPayload } from "@xyo-network/sdk-js";
46
+ import { asBlockBoundWitnessWithStorageMeta, isTransactionBoundWitnessWithStorageMeta } from "@xyo-network/xl1-protocol-lib";
47
+ var hydrateBlock = async (context, hash, maxDepth = 1, minDepth = maxDepth) => {
48
+ assertEx(maxDepth >= 0, () => "maxDepth must be greater than or equal to 0");
49
+ assertEx(minDepth >= 0, () => "minDepth must be greater than or equal to 0");
50
+ assertEx(maxDepth >= minDepth, () => "maxDepth must be greater than or equal to minDepth");
51
+ const { chainMap } = context;
52
+ const [block] = await chainMap.get([hash]);
53
+ const bw = assertEx(asBlockBoundWitnessWithStorageMeta(
54
+ assertEx(block, () => `block ${hash} not found`)
55
+ ), () => `hash ${hash} is not a BlockBoundWitness`);
56
+ if (maxDepth === 0) return [bw, []];
57
+ const blkPayloads = (await chainMap.get(bw.payload_hashes)).map((p) => asAnyPayload(p, true));
58
+ if (minDepth === 1) assertEx(allHashesPresent(bw.payload_hashes, blkPayloads), () => `Unable to find all payloads for block ${hash}`);
59
+ if (maxDepth === 1) return [bw, blkPayloads];
60
+ const transactions = blkPayloads.filter(isTransactionBoundWitnessWithStorageMeta);
61
+ const transactionsPayloadHashes = transactions.flatMap((tx) => tx.payload_hashes);
62
+ const transactionsPayloads = (await chainMap.get(transactionsPayloadHashes)).map((p) => asAnyPayload(p, true));
63
+ assertEx(allHashesPresent(transactionsPayloadHashes, transactionsPayloads), () => `Unable to find all payloads for transactions in block ${hash}`);
64
+ const allPayloadsHashes = new Set([...blkPayloads, ...transactionsPayloads].flatMap((p) => p._hash));
65
+ const allPayloads = (await chainMap.get([...allPayloadsHashes])).map((p) => asAnyPayload(p, true));
66
+ const allPayloadsFiltered = allPayloads.filter((p) => allPayloadsHashes.has(p._hash));
67
+ if (maxDepth === 2) assertEx(allHashesPresent(
68
+ [...allPayloadsHashes],
69
+ allPayloadsFiltered
70
+ ), () => `Unable to find all payloads for transactions in block ${hash}`);
71
+ return [bw, allPayloadsFiltered];
72
+ };
73
+
74
+ // src/block/primitives/blockFromBlockNumber.ts
88
75
  import {
89
- AbstractCreatable,
90
- assertEx as assertEx3,
91
- IdLogger
76
+ asHash,
77
+ isDefined as isDefined2,
78
+ spanAsync
92
79
  } from "@xylabs/sdk-js";
80
+ import { toSafeJsonString } from "@xylabs/sdk-js";
81
+ import {
82
+ asSignedBlockBoundWitnessWithStorageMeta,
83
+ SignedBlockBoundWitnessWithHashMetaZod,
84
+ StepSizes
85
+ } from "@xyo-network/xl1-protocol-lib";
93
86
 
94
- // src/CreatableProvider/ProviderFactory.ts
95
- import { assertEx as assertEx2 } from "@xylabs/sdk-js";
96
- function providerFactoryDescription(factory, labels) {
97
- return `${factory.providerName}:${factory.defaultMoniker}:${JSON.stringify(labels ?? factory.labels ?? {})}`;
98
- }
99
- var ProviderFactory = class _ProviderFactory {
100
- creatableProvider;
101
- defaultMoniker;
102
- defaultParams;
103
- dependencies;
104
- labels;
105
- monikers;
106
- providerName;
107
- scope;
108
- _uniqueId;
109
- constructor(creatableProvider2, dependencies, params, labels = {}, scope = "context") {
110
- this.creatableProvider = creatableProvider2;
111
- this.defaultParams = params;
112
- this.defaultMoniker = creatableProvider2.defaultMoniker;
113
- this.dependencies = dependencies;
114
- this.monikers = creatableProvider2.monikers;
115
- this.scope = scope;
116
- assertEx2(this.monikers.includes(this.defaultMoniker), () => "defaultMoniker must be in monikers");
117
- this.labels = Object.assign({}, creatableProvider2.labels ?? {}, labels ?? {});
118
- this.providerName = creatableProvider2.name;
119
- this._uniqueId = Symbol(providerFactoryDescription(this));
120
- }
121
- get resolvedMoniker() {
122
- const labels = this.labels ?? {};
123
- const labelString = Object.entries(labels).map(([key, value]) => `${key}=${value}`).join(",");
124
- return labelString.length === 0 ? `${this.defaultMoniker}` : `${this.defaultMoniker}|${labelString}`;
125
- }
126
- get uniqueId() {
127
- return this._uniqueId;
87
+ // src/ChainContextHelpers.ts
88
+ import {
89
+ isDefined,
90
+ isObject,
91
+ isUndefined,
92
+ timeBudget
93
+ } from "@xylabs/sdk-js";
94
+ import { LruCacheMap, MemoryMap } from "@xyo-network/xl1-driver-memory";
95
+ function contextCache(context, name, create) {
96
+ if (!isObject(context.caches)) {
97
+ throw new Error("Context does not have an appropriate caches property");
128
98
  }
129
- static withParams(creatableProvider2, dependencies, params, labels = {}) {
130
- return new _ProviderFactory(creatableProvider2, dependencies, params, labels);
99
+ if (isUndefined(context.caches[name])) {
100
+ context.caches[name] = create?.() ?? new MemoryMap();
131
101
  }
132
- factory(dependencies, params, labels = {}) {
133
- return new _ProviderFactory(this.creatableProvider, dependencies, params, labels);
102
+ return context.caches[name];
103
+ }
104
+ async function withContextCacheResponse(context, name, key, func, { max = 1e4 } = {}) {
105
+ const cache = contextCache(
106
+ context,
107
+ name,
108
+ () => new LruCacheMap({ max })
109
+ );
110
+ const { timeBudgetLimit = 0 } = context;
111
+ const cacheResult = await cache.get(key);
112
+ if (isDefined(cacheResult)) {
113
+ return cacheResult;
134
114
  }
135
- async getInstance(params, { start = true }) {
136
- let scopeObject;
137
- switch (this.scope) {
138
- case "global": {
139
- globalThis.xyoServiceSingletons ??= {};
140
- scopeObject = globalThis.xyoServiceSingletons;
141
- break;
115
+ const result = timeBudgetLimit > 0 ? timeBudget(name, context.logger, func, timeBudgetLimit) : func();
116
+ await cache.set(key, result);
117
+ return result;
118
+ }
119
+
120
+ // src/block/primitives/blockFromBlockNumber.ts
121
+ async function blockFromBlockNumber(context, blockNumber) {
122
+ return await spanAsync("blockFromBlockNumber", async () => {
123
+ const cacheKey = `${blockNumber}`;
124
+ const { chainMap, head } = context;
125
+ return await withContextCacheResponse(context, "blockFromBlockNumber", cacheKey, async () => {
126
+ const [result] = await chainMap.get([head._hash]);
127
+ if (!isDefined2(result)) {
128
+ throw new Error(`Head block not found for hash: ${head._hash}`);
142
129
  }
143
- case "context": {
144
- const context = assertEx2(
145
- params?.context,
146
- () => "Context is required for context-scoped providers"
147
- );
148
- context.singletons ??= {};
149
- scopeObject = context.singletons;
150
- break;
130
+ let currentBlock = asSignedBlockBoundWitnessWithStorageMeta(
131
+ result,
132
+ () => `Found Payload is not a Signed<BlockBoundWitness>: ${JSON.stringify(result, null, 2)}`
133
+ );
134
+ if (currentBlock.block < blockNumber) {
135
+ throw new Error(`Block number ${blockNumber} is greater than head ${currentBlock.block}.`);
151
136
  }
152
- default: {
153
- scopeObject = {};
154
- break;
137
+ while (currentBlock.block > blockNumber) {
138
+ let jumpHash = currentBlock.previous;
139
+ let jumpBlockNumber = currentBlock.block - 1;
140
+ for (const [step, stepSize3] of StepSizes.entries()) {
141
+ const possibleJumpBlockNumber = currentBlock.block - currentBlock.block % stepSize3 - 1;
142
+ if (possibleJumpBlockNumber >= blockNumber && possibleJumpBlockNumber <= jumpBlockNumber) {
143
+ jumpBlockNumber = possibleJumpBlockNumber;
144
+ jumpHash = asHash(currentBlock.step_hashes?.at(step), () => `Step hash not found for step ${step} in block ${currentBlock.block}`);
145
+ }
146
+ }
147
+ const [newBlock] = await chainMap.get([
148
+ asHash(jumpHash, () => `Jump hash not found for block number [${blockNumber}]: ${jumpBlockNumber} ${toSafeJsonString(currentBlock, 10)}`)
149
+ ]);
150
+ if (!isDefined2(newBlock)) {
151
+ throw new Error(`Block not found for jump hash: ${jumpHash}`);
152
+ }
153
+ currentBlock = asSignedBlockBoundWitnessWithStorageMeta(
154
+ newBlock,
155
+ () => {
156
+ const result2 = SignedBlockBoundWitnessWithHashMetaZod.safeParse(newBlock);
157
+ return `Found Payload [jump hash] is not a Signed<BlockBoundWitness>: ${result2.error}`;
158
+ }
159
+ );
160
+ if (currentBlock.block === blockNumber) {
161
+ break;
162
+ }
163
+ if (currentBlock.block < blockNumber) {
164
+ throw new Error(`Block number ${blockNumber} is not a valid step block number for block ${head._hash}.`);
165
+ }
155
166
  }
167
+ return currentBlock;
168
+ });
169
+ }, { ...context, timeBudgetLimit: 500 });
170
+ }
171
+
172
+ // src/block/primitives/frames/calculateFramesFromRange.ts
173
+ import { asXL1BlockNumber, stepSize } from "@xyo-network/xl1-protocol-lib";
174
+ function calculateFramesFromRange(range, step) {
175
+ const size = stepSize(step);
176
+ let start = Math.trunc(range[0] / size) * size;
177
+ const fitted = [];
178
+ const remaining = [];
179
+ if (start !== range[0]) {
180
+ start += size;
181
+ remaining.push([range[0], asXL1BlockNumber(Math.min(start - 1, range[1]), true)]);
182
+ }
183
+ for (let i = start; i <= range[1]; i += size) {
184
+ if (i + size - 1 <= range[1]) {
185
+ fitted.push([
186
+ asXL1BlockNumber(i, { name: "calculateFramesFromRange A" }),
187
+ asXL1BlockNumber(Math.min(i + size - 1, range[1]), { name: "calculateFramesFromRange B" })
188
+ ]);
189
+ } else {
190
+ remaining.push([asXL1BlockNumber(i, { name: "calculateFramesFromRange C" }), range[1]]);
156
191
  }
157
- const mergedParams = {
158
- ...this.defaultParams,
159
- ...params
160
- };
161
- const resultPromise = scopeObject[this.resolvedMoniker] ?? this.creatableProvider.create(mergedParams);
162
- scopeObject[this.resolvedMoniker] = resultPromise;
163
- const result = await resultPromise;
164
- if (start) {
165
- assertEx2(await result.start(), () => `Failed to start provider instance [${this.resolvedMoniker}]`);
192
+ }
193
+ return [fitted, remaining];
194
+ }
195
+
196
+ // src/block/primitives/frames/deepCalculateFramesFromRange.ts
197
+ import { StepSizes as StepSizes2 } from "@xyo-network/xl1-protocol-lib";
198
+ function deepCalculateFramesFromRange(range, startingStep = StepSizes2.length - 1) {
199
+ const fitted = [];
200
+ let remaining = [range];
201
+ const actualStartingStep = Math.min(startingStep, StepSizes2.length - 1);
202
+ for (let step = actualStartingStep; step >= 0; step--) {
203
+ const newRemaining = [];
204
+ for (const range2 of remaining) {
205
+ const [newFittedFrames, newRemainingFrames] = calculateFramesFromRange(range2, step);
206
+ fitted.push(...newFittedFrames);
207
+ newRemaining.push(...newRemainingFrames);
166
208
  }
167
- return result;
209
+ remaining = newRemaining;
168
210
  }
169
- async tryGetInstance(params, options) {
170
- try {
171
- return await this.getInstance(params, options);
172
- } catch {
173
- return;
211
+ for (const range2 of remaining) {
212
+ for (let i = range2[0]; i <= range2[1]; i++) {
213
+ fitted.push([i, i]);
174
214
  }
175
215
  }
176
- };
216
+ return fitted.toSorted((a, b) => a[0] - b[0]);
217
+ }
177
218
 
178
- // src/CreatableProvider/AbstractCreatableProvider.ts
179
- var AbstractCreatableProvider = class extends AbstractCreatable {
180
- dependencies = {};
181
- _contextCache;
182
- _logger;
183
- get logger() {
184
- if (this._logger === void 0) {
185
- const providedLogger = this.params.logger ?? this.context.logger;
186
- this._logger = providedLogger ? new IdLogger(providedLogger, () => `${this.moniker} [${this.constructor.name}]`) : null;
219
+ // src/block/primitives/validateTransactionOpcodes.ts
220
+ import {
221
+ assertEx as assertEx2,
222
+ isHash,
223
+ toSafeJsonString as toSafeJsonString2
224
+ } from "@xylabs/sdk-js";
225
+ import {
226
+ PayloadBuilder
227
+ } from "@xyo-network/sdk-js";
228
+ import { isExecutable } from "@xyo-network/xl1-protocol-lib";
229
+ async function validateTransactionsOpcodes(txs) {
230
+ const txElevatedPayloads = [];
231
+ for (const [txBw, txPayloads] of txs) {
232
+ if (isExecutable(txBw)) {
233
+ const operations = txBw.script.map((op) => op.split("|"));
234
+ for (const [opCode, ...args] of operations) {
235
+ switch (opCode) {
236
+ case "elevate": {
237
+ const [hash, ...rest] = args;
238
+ const txPayloadsWithStorageMeta = await PayloadBuilder.addStorageMeta(txPayloads);
239
+ assertEx2(rest.length === 0, () => `Invalid elevate operation ${opCode} ${args.join(", ")} - Too many Arguments`);
240
+ if (isHash(hash)) {
241
+ assertEx2(
242
+ txBw.payload_hashes.includes(hash),
243
+ () => `Invalid elevate operation ${opCode} ${args.join(", ")} - Hash not in payload hashes => ${toSafeJsonString2(txBw, 20)}`
244
+ );
245
+ const txPayload = assertEx2(
246
+ txPayloadsWithStorageMeta.find((p) => p._hash === hash),
247
+ () => `Invalid elevate operation ${opCode} ${args.join(", ")} - Payload not found`
248
+ );
249
+ txElevatedPayloads.push(txPayload);
250
+ } else {
251
+ throw new Error(`Invalid elevate operation ${opCode} ${args.join(", ")} - Invalid hash`);
252
+ }
253
+ break;
254
+ }
255
+ default: {
256
+ throw new Error(`Invalid opCode ${opCode}`);
257
+ }
258
+ }
259
+ }
187
260
  }
188
- return this._logger ?? void 0;
189
- }
190
- get meter() {
191
- return this.context.meterProvider?.getMeter(this.name) ?? super.meter;
192
261
  }
193
- get tracer() {
194
- return this.context.traceProvider?.getTracer(this.name) ?? super.tracer;
262
+ return txElevatedPayloads;
263
+ }
264
+
265
+ // src/test/buildNextBlock.ts
266
+ import {
267
+ AttoXL1 as AttoXL12,
268
+ XYO_STEP_REWARD_ADDRESS as XYO_STEP_REWARD_ADDRESS2
269
+ } from "@xyo-network/xl1-protocol-lib";
270
+
271
+ // src/test/buildBlock.ts
272
+ import { assertEx as assertEx3, isDefined as isDefined3 } from "@xylabs/sdk-js";
273
+ import {
274
+ asAnyPayload as asAnyPayload2,
275
+ BoundWitnessBuilder,
276
+ PayloadBuilder as PayloadBuilder3
277
+ } from "@xyo-network/sdk-js";
278
+ import {
279
+ asXL1BlockNumber as asXL1BlockNumber2,
280
+ AttoXL1,
281
+ isBlockBoundWitness,
282
+ rewardAddressFromStepIdentity,
283
+ StepRewardFractions,
284
+ StepSizes as StepSizes3,
285
+ XL1_PROTOCOL_VERSION,
286
+ XYO_STEP_REWARD_ADDRESS,
287
+ XYO_ZERO_ADDRESS
288
+ } from "@xyo-network/xl1-protocol-lib";
289
+
290
+ // src/createTransferPayload.ts
291
+ import { toHex } from "@xylabs/sdk-js";
292
+ import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk-js";
293
+ import { TransferSchema } from "@xyo-network/xl1-protocol-lib";
294
+ function createTransferPayload(from, transfers, context) {
295
+ return new PayloadBuilder2({ schema: TransferSchema }).fields({
296
+ epoch: Date.now(),
297
+ from,
298
+ transfers: Object.fromEntries(Object.entries(transfers).map(([k, v]) => [k, toHex(v)])),
299
+ context
300
+ }).build();
301
+ }
302
+
303
+ // src/test/BuildBlockOptions.ts
304
+ import {
305
+ isAddress,
306
+ isArray,
307
+ isHash as isHash2,
308
+ isNumber,
309
+ isObject as isObject2
310
+ } from "@xylabs/sdk-js";
311
+ var isBaseBuildBlockOptions = (value) => {
312
+ if (!isObject2(value)) {
313
+ return false;
195
314
  }
196
- get config() {
197
- return this.context.config;
315
+ const typedValue = value;
316
+ if (!isArray(typedValue.blockPayloads) || !isAddress(typedValue.chainId) || !isArray(typedValue.signers) || !isArray(typedValue.txs)) {
317
+ return false;
198
318
  }
199
- get context() {
200
- return this.params.context;
319
+ return true;
320
+ };
321
+ var isBuildGenesisBlockOptions = (value) => {
322
+ if (!isBaseBuildBlockOptions(value)) {
323
+ return false;
201
324
  }
202
- get locator() {
203
- return this.context.locator;
325
+ const typedValue = value;
326
+ if (typedValue.previousBlockHash !== null) {
327
+ return false;
204
328
  }
205
- static factory(dependencies, params) {
206
- const factory = ProviderFactory.withParams(this, dependencies, params);
207
- return factory;
329
+ if (typedValue.previousBlockNumber !== void 0) {
330
+ return false;
208
331
  }
209
- static async paramsHandler(params = {}) {
210
- const context = assertEx3(params.context, () => new Error("Context is required"));
211
- const config = assertEx3(context.config, () => new Error("Context config is required"));
212
- const locator = assertEx3(context.locator, () => new Error("Context locator is required"));
213
- return await super.paramsHandler({
214
- ...params,
215
- statusReporter: params.statusReporter ?? context.statusReporter,
216
- context: {
217
- ...context,
218
- config,
219
- locator
220
- },
221
- name: params.name ?? this.defaultMoniker,
222
- logger: params.logger ?? context.logger
223
- });
332
+ return true;
333
+ };
334
+ var isBuildNextBlockOptions = (value) => {
335
+ if (!isBaseBuildBlockOptions(value)) {
336
+ return false;
224
337
  }
225
- async createHandler() {
226
- await super.createHandler();
227
- if (this.tracer === void 0) {
228
- this.logger?.warn("No tracer available in context");
229
- }
230
- if (this.meter === void 0) {
231
- this.logger?.warn("No meter available in context");
232
- }
338
+ const typedValue = value;
339
+ if (!isHash2(typedValue.previousBlockHash)) {
340
+ return false;
233
341
  }
234
- async locateAndCreate(moniker) {
235
- return await this.locator.getInstance(moniker);
342
+ if (!isNumber(typedValue.previousBlockNumber)) {
343
+ return false;
236
344
  }
237
- async tryLocateAndCreate(moniker) {
238
- return await this.locator.tryGetInstance(moniker);
345
+ if (!isArray(typedValue.previousStepHashes)) {
346
+ return false;
239
347
  }
348
+ return true;
240
349
  };
241
350
 
242
- // src/CreatableProvider/CreatableProvider.ts
243
- function creatableProvider() {
244
- return (constructor) => {
245
- constructor;
246
- };
351
+ // src/test/buildBlock.ts
352
+ function calculateCompletedStepReward(step, balance) {
353
+ return AttoXL1(StepRewardFractions[step][0] * balance / StepRewardFractions[step][1]);
247
354
  }
248
-
249
- // src/CreatableProvider/CreatableProviderRegistry.ts
250
- import { isTruthy } from "@xylabs/sdk-js";
251
- var buildProviderFactory = (provider, defaultParams, labels) => {
252
- const factory = {
253
- monikers: provider.monikers,
254
- uniqueId: Symbol(providerFactoryDescription(provider, labels)),
255
- // Merge module & supplied labels
256
- labels: { ...provider.labels, ...labels },
257
- creatableProvider: provider.creatableProvider,
258
- dependencies: provider.dependencies,
259
- resolvedMoniker: provider.resolvedMoniker,
260
- providerName: provider.providerName,
261
- scope: provider.scope,
262
- defaultParams,
263
- getInstance: provider.getInstance.bind(provider),
264
- tryGetInstance: provider.tryGetInstance?.bind(provider),
265
- defaultMoniker: provider.defaultMoniker,
266
- factory: provider.factory.bind(provider)
267
- };
268
- return factory;
269
- };
270
- var registerCreatableProviderFactory = (registry, factory, labels, primary = false) => {
271
- const primaryMonikers = primary !== true && isTruthy(primary) ? Array.isArray(primary) ? primary : [primary] : [];
272
- for (const primaryMoniker of primaryMonikers) {
273
- if (!factory.monikers.includes(primaryMoniker)) {
274
- throw new Error(`Primary moniker ${String(primaryMoniker)} not found in factory monikers`);
355
+ async function buildBlock(options) {
356
+ const previousBlockNumber = isBuildGenesisBlockOptions(options) ? -1 : options.previousBlockNumber;
357
+ const blockNumber = asXL1BlockNumber2(previousBlockNumber + 1, true);
358
+ const inStepHashes = isBuildNextBlockOptions(options) ? options.previousStepHashes : [];
359
+ const previousBlockHash = isBuildNextBlockOptions(options) ? options.previousBlockHash : void 0;
360
+ const stepRewardPoolBalance = isBuildNextBlockOptions(options) ? options.stepRewardPoolBalance : AttoXL1(0n);
361
+ const {
362
+ chainId,
363
+ txs,
364
+ chainStepRewardAddress = XYO_STEP_REWARD_ADDRESS,
365
+ blockPayloads,
366
+ protocol = XL1_PROTOCOL_VERSION,
367
+ signers
368
+ } = options;
369
+ const step_hashes = [];
370
+ for (const [tx] of txs) {
371
+ if (tx.nbf > blockNumber) {
372
+ throw new Error(`Transaction ${await PayloadBuilder3.hash(tx)} not valid for block ${blockNumber} - NBF is ${tx.nbf}`);
373
+ }
374
+ if (tx.exp < blockNumber) {
375
+ throw new Error(`Transaction ${await PayloadBuilder3.hash(tx)} not valid for block ${blockNumber} - EXP is ${tx.exp}`);
275
376
  }
276
377
  }
277
- const isPrimaryForMoniker = (moniker) => {
278
- switch (typeof primary) {
279
- case "boolean": {
280
- return primary;
281
- }
282
- case "string": {
283
- return moniker === primary;
378
+ const completedStepRewardTransfers = [];
379
+ for (const [i, step] of StepSizes3.entries()) {
380
+ if (blockNumber < step) {
381
+ break;
382
+ }
383
+ if (blockNumber % step === 0) {
384
+ if (StepRewardFractions[i][0] > 0 && chainStepRewardAddress !== XYO_ZERO_ADDRESS) {
385
+ const completedStepRewardHolderAddress = rewardAddressFromStepIdentity({ block: blockNumber, step });
386
+ const completedStepReward = calculateCompletedStepReward(i, stepRewardPoolBalance);
387
+ completedStepRewardTransfers.push(createTransferPayload(chainStepRewardAddress, { [completedStepRewardHolderAddress]: completedStepReward }));
284
388
  }
285
- case "object": {
286
- if (Array.isArray(primary)) {
287
- return primary.includes(moniker);
288
- }
389
+ step_hashes.push(assertEx3(previousBlockHash, () => `Previous block hash is required for step ${step} at block ${blockNumber}`));
390
+ } else {
391
+ if (isDefined3(inStepHashes.at(i))) {
392
+ step_hashes.push(inStepHashes[i]);
289
393
  }
290
394
  }
291
- throw new Error(`Invalid primary value: ${String(primary)}`);
292
- };
293
- const factoryClone = buildProviderFactory(factory, factory.defaultParams, labels);
294
- registry[factoryClone.defaultMoniker] = [factoryClone, ...registry[factoryClone.defaultMoniker] ?? []];
295
- for (const moniker of factoryClone.monikers) {
296
- if (moniker === factoryClone.defaultMoniker) continue;
297
- registry[moniker] = isPrimaryForMoniker(moniker) ? [factoryClone, ...registry[moniker] ?? []] : [...registry[moniker] ?? [], factoryClone];
298
395
  }
299
- };
300
-
301
- // src/CreatableProvider/LabeledCreatableProviderFactory.ts
302
- var hasLabels = (factory) => {
303
- return factory.labels !== void 0;
304
- };
396
+ const previous = previousBlockHash ?? null;
397
+ const block = blockNumber;
398
+ const txElevatedPayloads = await validateTransactionsOpcodes(txs);
399
+ const payloads = [
400
+ ...txs.map(([tx]) => tx),
401
+ ...blockPayloads,
402
+ ...txElevatedPayloads,
403
+ ...completedStepRewardTransfers
404
+ ];
405
+ const [bw, txPayloads] = await new BoundWitnessBuilder().fields({
406
+ block,
407
+ chain: chainId,
408
+ previous,
409
+ step_hashes,
410
+ protocol
411
+ }).meta({ $epoch: Date.now(), $signatures: [] }).signers(signers).payloads(await PayloadBuilder3.addStorageMeta(payloads)).build();
412
+ assertEx3(isBlockBoundWitness(bw), () => "Build of BlockBoundWitness failed");
413
+ return [await PayloadBuilder3.addStorageMeta(bw), txPayloads.map((p) => asAnyPayload2(p, true))];
414
+ }
305
415
 
306
- // src/CreatableProvider/ProviderFactoryLocator.ts
307
- import { hasAllLabels } from "@xylabs/sdk-js";
308
- import { assertEx as assertEx4 } from "@xylabs/sdk-js";
309
- var ProviderFactoryLocator = class _ProviderFactoryLocator {
310
- _context;
416
+ // src/test/buildNextBlock.ts
417
+ async function buildNextBlock(previousBlock, txs, blockPayloads, signers, chainStepRewardAddress = XYO_STEP_REWARD_ADDRESS2, stepRewardPoolBalance = AttoXL12(0n), protocol, chainId) {
418
+ return await buildBlock({
419
+ chainId: chainId ?? previousBlock.chain,
420
+ previousBlockNumber: previousBlock.block,
421
+ previousStepHashes: previousBlock.step_hashes ?? [],
422
+ previousBlockHash: previousBlock._hash,
423
+ txs,
424
+ blockPayloads,
425
+ signers,
426
+ protocol,
427
+ chainStepRewardAddress,
428
+ stepRewardPoolBalance
429
+ });
430
+ }
431
+
432
+ // src/test/buildRandomGenesisBlock.ts
433
+ import { asAddress, assertEx as assertEx5 } from "@xylabs/sdk-js";
434
+ import {
435
+ Account as Account2,
436
+ asAnyPayload as asAnyPayload4,
437
+ asSchema,
438
+ IdSchema,
439
+ PayloadBuilder as PayloadBuilder5
440
+ } from "@xyo-network/sdk-js";
441
+ import {
442
+ asXL1BlockNumber as asXL1BlockNumber4
443
+ } from "@xyo-network/xl1-protocol-lib";
444
+
445
+ // src/test/buildGenesisBlock.ts
446
+ import { XYO_ZERO_ADDRESS as XYO_ZERO_ADDRESS2 } from "@xyo-network/xl1-protocol-lib";
447
+ async function buildGenesisBlock(chainId, txs, blockPayloads, signers, chainStepRewardAddress = XYO_ZERO_ADDRESS2, protocol) {
448
+ return await buildBlock({
449
+ previousBlockHash: null,
450
+ chainId,
451
+ txs,
452
+ blockPayloads,
453
+ signers,
454
+ chainStepRewardAddress,
455
+ protocol
456
+ });
457
+ }
458
+
459
+ // src/test/buildRandomTransaction.ts
460
+ import { Account } from "@xyo-network/sdk-js";
461
+ import { asXL1BlockNumber as asXL1BlockNumber3, isAllowedBlockPayload } from "@xyo-network/xl1-protocol-lib";
462
+
463
+ // src/transaction/buildTransaction.ts
464
+ import { assertEx as assertEx4, toHex as toHex2 } from "@xylabs/sdk-js";
465
+ import {
466
+ asAnyPayload as asAnyPayload3,
467
+ BoundWitnessBuilder as BoundWitnessBuilder2,
468
+ PayloadBuilder as PayloadBuilder4
469
+ } from "@xyo-network/sdk-js";
470
+ import { defaultTransactionFees } from "@xyo-network/xl1-protocol-lib";
471
+ async function buildTransaction(chain, onChainPayloads, offChainPayloads, signer, nbf, exp, from, fees = defaultTransactionFees) {
472
+ if (from === void 0 && Array.isArray(signer)) {
473
+ throw new Error("from is required when signer is an array");
474
+ }
475
+ const txBoundWitnessFields = {
476
+ chain,
477
+ fees: {
478
+ base: toHex2(fees.base),
479
+ gasLimit: toHex2(fees.gasLimit),
480
+ gasPrice: toHex2(fees.gasPrice),
481
+ priority: toHex2(fees.priority)
482
+ },
483
+ nbf,
484
+ exp
485
+ };
486
+ const elevatedHashes = await PayloadBuilder4.hashes(onChainPayloads);
487
+ const script = [];
488
+ for (const elevatedHash of elevatedHashes) {
489
+ script.push(`elevate|${elevatedHash}`);
490
+ }
491
+ const fields = {
492
+ ...txBoundWitnessFields,
493
+ from: from ?? (Array.isArray(signer) ? assertEx4(signer.at(0)?.address) : signer.address)
494
+ };
495
+ if (script.length > 0) {
496
+ fields.script = script;
497
+ }
498
+ const [tx, txPayloads] = await new BoundWitnessBuilder2().fields(fields).meta({ $signatures: [] }).payloads([...onChainPayloads, ...offChainPayloads]).signers(Array.isArray(signer) ? signer : [signer]).build();
499
+ return [await PayloadBuilder4.addHashMeta(tx), await PayloadBuilder4.addHashMeta(txPayloads.map((p) => asAnyPayload3(p, true)))];
500
+ }
501
+
502
+ // src/test/buildRandomTransaction.ts
503
+ var buildRandomTransaction = async (chain, payloads, account, nbf = asXL1BlockNumber3(0, true), exp = asXL1BlockNumber3(nbf + 1e3, true), privatePayloadSchemas = [], receiverAddress) => {
504
+ const elevatedPayloads = (payloads ?? []).filter(isAllowedBlockPayload);
505
+ const additionalPayloads = (payloads ?? []).filter((payload) => !isAllowedBlockPayload(payload));
506
+ const sender = account ?? await Account.random();
507
+ if (elevatedPayloads.length === 0) {
508
+ const receiver = receiverAddress ?? (await Account.random()).address;
509
+ const transferPayload = createTransferPayload(sender.address, { [receiver]: 1n });
510
+ elevatedPayloads.push(transferPayload);
511
+ }
512
+ const hydratedTransaction = await buildTransaction(chain, elevatedPayloads, additionalPayloads, sender, nbf, exp);
513
+ return [hydratedTransaction[0], hydratedTransaction[1].filter((payload) => !privatePayloadSchemas.includes(payload.schema))];
514
+ };
515
+
516
+ // src/test/buildRandomGenesisBlock.ts
517
+ var TestChainId = assertEx5(asAddress("c5fe2e6F6841Cbab12d8C0618Be2DF8C6156cC44"));
518
+
519
+ // src/test/createGenesisBlock.ts
520
+ import { PayloadBuilder as PayloadBuilder7 } from "@xyo-network/sdk-js";
521
+ import {
522
+ BlockBoundWitnessSchemaPayload,
523
+ BlockBoundWitnessWithStorageMetaSchemaPayload,
524
+ ChainStakeIntentPayloadJsonSchemaPayload,
525
+ HashPayloadJsonSchemaPayload,
526
+ TransactionBoundWitnessSchemaPayload,
527
+ TransactionBoundWitnessWithStorageMetaSchemaPayload,
528
+ TransferPayloadJsonSchemaPayload
529
+ } from "@xyo-network/xl1-schema";
530
+
531
+ // src/test/createProducerChainStakeIntentTransaction.ts
532
+ import { PayloadBuilder as PayloadBuilder6 } from "@xyo-network/sdk-js";
533
+ import {
534
+ asXL1BlockNumber as asXL1BlockNumber5,
535
+ ChainStakeIntentSchema,
536
+ defaultTransactionFees as defaultTransactionFees2
537
+ } from "@xyo-network/xl1-protocol-lib";
538
+ async function createProducerChainStakeIntent(from, exp, nbf = 0) {
539
+ return await PayloadBuilder6.addHashMeta(new PayloadBuilder6({ schema: ChainStakeIntentSchema }).fields({
540
+ from,
541
+ exp,
542
+ nbf,
543
+ intent: "producer"
544
+ }).build());
545
+ }
546
+
547
+ // src/test/createGenesisBlock.ts
548
+ var createGenesisBlock = async (initialBlockProducer, nextContractAddress, genesisBlockRewardAmount, genesisBlockRewardAddress) => {
549
+ const blockPayloads = await PayloadBuilder7.addHashMeta([
550
+ TransferPayloadJsonSchemaPayload,
551
+ BlockBoundWitnessSchemaPayload,
552
+ BlockBoundWitnessWithStorageMetaSchemaPayload,
553
+ TransactionBoundWitnessSchemaPayload,
554
+ TransactionBoundWitnessWithStorageMetaSchemaPayload,
555
+ ChainStakeIntentPayloadJsonSchemaPayload,
556
+ HashPayloadJsonSchemaPayload
557
+ ]);
558
+ const intentPayload = await createProducerChainStakeIntent(initialBlockProducer.address, 1, 0);
559
+ blockPayloads.push(intentPayload);
560
+ if (genesisBlockRewardAmount > 0n) {
561
+ blockPayloads.push(await PayloadBuilder7.addHashMeta(createTransferPayload(
562
+ nextContractAddress,
563
+ { [genesisBlockRewardAddress]: genesisBlockRewardAmount }
564
+ )));
565
+ }
566
+ return await buildGenesisBlock(nextContractAddress, [], blockPayloads, [initialBlockProducer]);
567
+ };
568
+
569
+ // src/test/buildRandomChain.ts
570
+ var TestGenesisBlockRewardAddress = assertEx6(asAddress2("fa7f0bb865a4bfff3d5e2c726d3e063297014da9"));
571
+ var buildRandomChain = async (blockProducer, count = 10, previousBlock, chainId, transactionAccount, receiverAddresses) => {
572
+ const chainIdToUse = chainId ?? TestChainId;
573
+ const blocks = [];
574
+ let remaining = count;
575
+ let lastBlock = previousBlock;
576
+ const transactionAccountToUse = transactionAccount ?? await Account3.random();
577
+ if (!lastBlock) {
578
+ const block = await createGenesisBlock(
579
+ blockProducer,
580
+ chainIdToUse,
581
+ 1000000000n * 10n ** 18n,
582
+ transactionAccountToUse.address
583
+ );
584
+ blocks.push(block);
585
+ remaining = remaining - 1;
586
+ lastBlock = block;
587
+ }
588
+ const resolvedReceiverAddresses = receiverAddresses ?? [(await Account3.random()).address];
589
+ let saltCounter = 0;
590
+ while (remaining > 0) {
591
+ saltCounter += 1;
592
+ const payloads = [new PayloadBuilder8({ schema: IdSchema2 }).fields({ salt: `${Date.now()}-${saltCounter}` }).build()];
593
+ saltCounter += 1;
594
+ const additionalPrivatePayloads = remaining % 2 === 0 ? [new PayloadBuilder8({ schema: asSchema2("network.xyo.private", true) }).fields({ salt: `${Date.now()}-${saltCounter}` }).build()] : [];
595
+ const txs = [];
596
+ for (const receiverAddress of resolvedReceiverAddresses) {
597
+ txs.push(await buildRandomTransaction(
598
+ chainIdToUse,
599
+ [...payloads, ...additionalPrivatePayloads],
600
+ transactionAccountToUse,
601
+ asXL1BlockNumber6(Math.max(count - remaining - 1e3, 0), true),
602
+ asXL1BlockNumber6(count - remaining + 1e3, true),
603
+ [asSchema2("network.xyo.private", true)],
604
+ receiverAddress
605
+ ));
606
+ }
607
+ const previousBlock2 = assertEx6(lastBlock?.[0], () => new Error("No last block"));
608
+ const block = await buildNextBlock(previousBlock2, txs, [], [blockProducer], transactionAccountToUse.address);
609
+ blocks.push(block);
610
+ remaining = remaining - 1;
611
+ lastBlock = block;
612
+ }
613
+ return blocks;
614
+ };
615
+ async function buildRandomChainArchivist(count = 20) {
616
+ const producerAccount = await Account3.random();
617
+ const blocks = await buildRandomChain(producerAccount, count);
618
+ const archivist = await MemoryArchivist.create();
619
+ const payloads = flattenHydratedBlocks(blocks);
620
+ await archivist.insert(payloads);
621
+ return archivist;
622
+ }
623
+
624
+ // src/test/getSimpleBlockViewerLocator.ts
625
+ import { XYO_ZERO_ADDRESS as XYO_ZERO_ADDRESS3 } from "@xyo-network/xl1-protocol-lib";
626
+
627
+ // src/CreatableProvider/AbstractCreatableProvider.ts
628
+ import {
629
+ AbstractCreatable,
630
+ assertEx as assertEx8,
631
+ IdLogger
632
+ } from "@xylabs/sdk-js";
633
+
634
+ // src/CreatableProvider/ProviderFactory.ts
635
+ import { assertEx as assertEx7 } from "@xylabs/sdk-js";
636
+ function providerFactoryDescription(factory, labels) {
637
+ return `${factory.providerName}:${factory.defaultMoniker}:${JSON.stringify(labels ?? factory.labels ?? {})}`;
638
+ }
639
+ var ProviderFactory = class _ProviderFactory {
640
+ creatableProvider;
641
+ defaultMoniker;
642
+ defaultParams;
643
+ dependencies;
644
+ labels;
645
+ monikers;
646
+ providerName;
647
+ scope;
648
+ _uniqueId;
649
+ constructor(creatableProvider2, dependencies, params, labels = {}, scope = "context") {
650
+ this.creatableProvider = creatableProvider2;
651
+ this.defaultParams = params;
652
+ this.defaultMoniker = creatableProvider2.defaultMoniker;
653
+ this.dependencies = dependencies;
654
+ this.monikers = creatableProvider2.monikers;
655
+ this.scope = scope;
656
+ assertEx7(this.monikers.includes(this.defaultMoniker), () => "defaultMoniker must be in monikers");
657
+ this.labels = Object.assign({}, creatableProvider2.labels ?? {}, labels ?? {});
658
+ this.providerName = creatableProvider2.name;
659
+ this._uniqueId = Symbol(providerFactoryDescription(this));
660
+ }
661
+ get resolvedMoniker() {
662
+ const labels = this.labels ?? {};
663
+ const labelString = Object.entries(labels).map(([key, value]) => `${key}=${value}`).join(",");
664
+ return labelString.length === 0 ? `${this.defaultMoniker}` : `${this.defaultMoniker}|${labelString}`;
665
+ }
666
+ get uniqueId() {
667
+ return this._uniqueId;
668
+ }
669
+ static withParams(creatableProvider2, dependencies, params, labels = {}) {
670
+ return new _ProviderFactory(creatableProvider2, dependencies, params, labels);
671
+ }
672
+ factory(dependencies, params, labels = {}) {
673
+ return new _ProviderFactory(this.creatableProvider, dependencies, params, labels);
674
+ }
675
+ async getInstance(params, { start = true }) {
676
+ let scopeObject;
677
+ switch (this.scope) {
678
+ case "global": {
679
+ globalThis.xyoServiceSingletons ??= {};
680
+ scopeObject = globalThis.xyoServiceSingletons;
681
+ break;
682
+ }
683
+ case "context": {
684
+ const context = assertEx7(
685
+ params?.context,
686
+ () => "Context is required for context-scoped providers"
687
+ );
688
+ context.singletons ??= {};
689
+ scopeObject = context.singletons;
690
+ break;
691
+ }
692
+ default: {
693
+ scopeObject = {};
694
+ break;
695
+ }
696
+ }
697
+ const mergedParams = {
698
+ ...this.defaultParams,
699
+ ...params
700
+ };
701
+ const resultPromise = scopeObject[this.resolvedMoniker] ?? this.creatableProvider.create(mergedParams);
702
+ scopeObject[this.resolvedMoniker] = resultPromise;
703
+ const result = await resultPromise;
704
+ if (start) {
705
+ assertEx7(await result.start(), () => `Failed to start provider instance [${this.resolvedMoniker}]`);
706
+ }
707
+ return result;
708
+ }
709
+ async tryGetInstance(params, options) {
710
+ try {
711
+ return await this.getInstance(params, options);
712
+ } catch {
713
+ return;
714
+ }
715
+ }
716
+ };
717
+
718
+ // src/CreatableProvider/AbstractCreatableProvider.ts
719
+ var AbstractCreatableProvider = class extends AbstractCreatable {
720
+ dependencies = {};
721
+ _contextCache;
722
+ _logger;
723
+ get logger() {
724
+ if (this._logger === void 0) {
725
+ const providedLogger = this.params.logger ?? this.context.logger;
726
+ this._logger = providedLogger ? new IdLogger(providedLogger, () => `${this.moniker} [${this.constructor.name}]`) : null;
727
+ }
728
+ return this._logger ?? void 0;
729
+ }
730
+ get meter() {
731
+ return this.context.meterProvider?.getMeter(this.name) ?? super.meter;
732
+ }
733
+ get tracer() {
734
+ return this.context.traceProvider?.getTracer(this.name) ?? super.tracer;
735
+ }
736
+ get config() {
737
+ return this.context.config;
738
+ }
739
+ get context() {
740
+ return this.params.context;
741
+ }
742
+ get locator() {
743
+ return this.context.locator;
744
+ }
745
+ static factory(dependencies, params) {
746
+ const factory = ProviderFactory.withParams(this, dependencies, params);
747
+ return factory;
748
+ }
749
+ static async paramsHandler(params = {}) {
750
+ const context = assertEx8(params.context, () => new Error("Context is required"));
751
+ const config = assertEx8(context.config, () => new Error("Context config is required"));
752
+ const locator = assertEx8(context.locator, () => new Error("Context locator is required"));
753
+ return await super.paramsHandler({
754
+ ...params,
755
+ statusReporter: params.statusReporter ?? context.statusReporter,
756
+ context: {
757
+ ...context,
758
+ config,
759
+ locator
760
+ },
761
+ name: params.name ?? this.defaultMoniker,
762
+ logger: params.logger ?? context.logger
763
+ });
764
+ }
765
+ async createHandler() {
766
+ await super.createHandler();
767
+ if (this.tracer === void 0) {
768
+ this.logger?.warn("No tracer available in context");
769
+ }
770
+ if (this.meter === void 0) {
771
+ this.logger?.warn("No meter available in context");
772
+ }
773
+ }
774
+ async locateAndCreate(moniker) {
775
+ return await this.locator.getInstance(moniker);
776
+ }
777
+ async tryLocateAndCreate(moniker) {
778
+ return await this.locator.tryGetInstance(moniker);
779
+ }
780
+ };
781
+
782
+ // src/CreatableProvider/CreatableProvider.ts
783
+ function creatableProvider() {
784
+ return (constructor) => {
785
+ constructor;
786
+ };
787
+ }
788
+
789
+ // src/CreatableProvider/CreatableProviderRegistry.ts
790
+ import { isTruthy } from "@xylabs/sdk-js";
791
+ var buildProviderFactory = (provider, defaultParams, labels) => {
792
+ const factory = {
793
+ monikers: provider.monikers,
794
+ uniqueId: Symbol(providerFactoryDescription(provider, labels)),
795
+ // Merge module & supplied labels
796
+ labels: { ...provider.labels, ...labels },
797
+ creatableProvider: provider.creatableProvider,
798
+ dependencies: provider.dependencies,
799
+ resolvedMoniker: provider.resolvedMoniker,
800
+ providerName: provider.providerName,
801
+ scope: provider.scope,
802
+ defaultParams,
803
+ getInstance: provider.getInstance.bind(provider),
804
+ tryGetInstance: provider.tryGetInstance?.bind(provider),
805
+ defaultMoniker: provider.defaultMoniker,
806
+ factory: provider.factory.bind(provider)
807
+ };
808
+ return factory;
809
+ };
810
+ var registerCreatableProviderFactory = (registry, factory, labels, primary = false) => {
811
+ const primaryMonikers = primary !== true && isTruthy(primary) ? Array.isArray(primary) ? primary : [primary] : [];
812
+ for (const primaryMoniker of primaryMonikers) {
813
+ if (!factory.monikers.includes(primaryMoniker)) {
814
+ throw new Error(`Primary moniker ${String(primaryMoniker)} not found in factory monikers`);
815
+ }
816
+ }
817
+ const isPrimaryForMoniker = (moniker) => {
818
+ switch (typeof primary) {
819
+ case "boolean": {
820
+ return primary;
821
+ }
822
+ case "string": {
823
+ return moniker === primary;
824
+ }
825
+ case "object": {
826
+ if (Array.isArray(primary)) {
827
+ return primary.includes(moniker);
828
+ }
829
+ }
830
+ }
831
+ throw new Error(`Invalid primary value: ${String(primary)}`);
832
+ };
833
+ const factoryClone = buildProviderFactory(factory, factory.defaultParams, labels);
834
+ registry[factoryClone.defaultMoniker] = [factoryClone, ...registry[factoryClone.defaultMoniker] ?? []];
835
+ for (const moniker of factoryClone.monikers) {
836
+ if (moniker === factoryClone.defaultMoniker) continue;
837
+ registry[moniker] = isPrimaryForMoniker(moniker) ? [factoryClone, ...registry[moniker] ?? []] : [...registry[moniker] ?? [], factoryClone];
838
+ }
839
+ };
840
+
841
+ // src/CreatableProvider/LabeledCreatableProviderFactory.ts
842
+ var hasLabels = (factory) => {
843
+ return factory.labels !== void 0;
844
+ };
845
+
846
+ // src/CreatableProvider/ProviderFactoryLocator.ts
847
+ import { hasAllLabels } from "@xylabs/sdk-js";
848
+ import { assertEx as assertEx9 } from "@xylabs/sdk-js";
849
+ var ProviderFactoryLocator = class _ProviderFactoryLocator {
850
+ _context;
311
851
  _registry;
312
852
  _frozen = false;
313
853
  _parent;
@@ -337,7 +877,7 @@ var ProviderFactoryLocator = class _ProviderFactoryLocator {
337
877
  this._frozen = true;
338
878
  }
339
879
  async getInstance(moniker, { start = true, labels } = {}) {
340
- return assertEx4(
880
+ return assertEx9(
341
881
  await this.tryGetInstance(moniker, { start, labels }),
342
882
  () => `No provider instance for the supplied config moniker [${moniker}]${labels ? ` & labels [${JSON.stringify(labels)}]` : ""} could be created`
343
883
  );
@@ -352,7 +892,7 @@ var ProviderFactoryLocator = class _ProviderFactoryLocator {
352
892
  * @returns A provider factory that matches the supplied moniker and labels or throws if one is not found
353
893
  */
354
894
  locate(moniker, labels) {
355
- return assertEx4(
895
+ return assertEx9(
356
896
  this.tryLocate(moniker, labels),
357
897
  () => `No module factory for the supplied config moniker [${moniker}]${labels ? ` & labels [${JSON.stringify(labels)}]` : ""} registered`
358
898
  );
@@ -374,10 +914,10 @@ var ProviderFactoryLocator = class _ProviderFactoryLocator {
374
914
  * @param labels The labels for the module factory
375
915
  */
376
916
  register(factory, labels, primary = false) {
377
- assertEx4(!this._frozen, () => "Cannot register a module factory after the locator has been frozen");
917
+ assertEx9(!this._frozen, () => "Cannot register a module factory after the locator has been frozen");
378
918
  if (this.validateDepsOnRegister) {
379
919
  const missingDeps = factory.dependencies.filter((dep) => !this.registered(dep));
380
- assertEx4(missingDeps.length === 0, () => `Cannot register module factory [${factory.uniqueId.description}] due to missing dependencies: ${missingDeps.join(", ")}`);
920
+ assertEx9(missingDeps.length === 0, () => `Cannot register module factory [${factory.uniqueId.description}] due to missing dependencies: ${missingDeps.join(", ")}`);
381
921
  }
382
922
  registerCreatableProviderFactory(this._registry, factory, labels, primary);
383
923
  return this;
@@ -425,7 +965,7 @@ var ProviderFactoryLocator = class _ProviderFactoryLocator {
425
965
  for (const moniker in this.registry) {
426
966
  for (const factory of this.registry[moniker] ?? []) {
427
967
  const missingDeps = factory.dependencies.filter((dep) => !this.registered(dep));
428
- assertEx4(missingDeps.length === 0, () => `Module factory [${factory.uniqueId.description}] is missing dependencies: ${missingDeps.join(", ")}`);
968
+ assertEx9(missingDeps.length === 0, () => `Module factory [${factory.uniqueId.description}] is missing dependencies: ${missingDeps.join(", ")}`);
429
969
  }
430
970
  }
431
971
  }
@@ -450,10 +990,10 @@ import {
450
990
  zodIsFactory as zodIsFactory2,
451
991
  zodToFactory as zodToFactory2
452
992
  } from "@xylabs/sdk-js";
453
- import { globalRegistry as globalRegistry12, z as z16 } from "zod/mini";
993
+ import { globalRegistry as globalRegistry13, z as z17 } from "zod/mini";
454
994
 
455
995
  // src/config/Base.ts
456
- import { z as z15 } from "zod/mini";
996
+ import { z as z16 } from "zod/mini";
457
997
 
458
998
  // src/config/Chain.ts
459
999
  import { HexZod } from "@xylabs/sdk-js";
@@ -623,7 +1163,7 @@ var RpcRemoteConfigZod = z10.union([HttpRpcRemoteConfigZod, PostMessageRpcRemote
623
1163
  var RemoteConfigZod = z10.object({ rpc: RpcRemoteConfigZod.optional() }).describe("Configuration for remote connections, including RPC");
624
1164
 
625
1165
  // src/config/storage/driver/Mongo.ts
626
- import { isDefined, isUndefined } from "@xylabs/sdk-js";
1166
+ import { isDefined as isDefined4, isUndefined as isUndefined2 } from "@xylabs/sdk-js";
627
1167
  import { globalRegistry as globalRegistry8, z as z11 } from "zod";
628
1168
  var MongoConfigZod = z11.object({
629
1169
  // TODO: Create from other arguments
@@ -654,11 +1194,43 @@ var MongoConfigZod = z11.object({
654
1194
  })
655
1195
  });
656
1196
 
657
- // src/config/storage/Storage.ts
1197
+ // src/config/storage/driver/R2.ts
1198
+ import { isDefined as isDefined5, isUndefined as isUndefined3 } from "@xylabs/sdk-js";
658
1199
  import { globalRegistry as globalRegistry9, z as z12 } from "zod";
659
- var StorageConfigZod = z12.object({
1200
+ var R2ConfigZod = z12.object({
1201
+ accessKeyId: z12.string().nonempty().optional().register(globalRegistry9, {
1202
+ description: "Cloudflare R2 access key id (from an R2 API token)",
1203
+ title: "storage.r2.accessKeyId",
1204
+ type: "string"
1205
+ }),
1206
+ accountId: z12.string().nonempty().optional().register(globalRegistry9, {
1207
+ description: "Cloudflare account id; determines the R2 endpoint https://<accountId>.r2.cloudflarestorage.com",
1208
+ title: "storage.r2.accountId",
1209
+ type: "string"
1210
+ }),
1211
+ bucket: z12.string().nonempty().optional().register(globalRegistry9, {
1212
+ description: "Cloudflare R2 bucket name",
1213
+ title: "storage.r2.bucket",
1214
+ type: "string"
1215
+ }),
1216
+ prefix: z12.string().nonempty().optional().register(globalRegistry9, {
1217
+ description: "Optional key prefix namespacing this store within the bucket",
1218
+ title: "storage.r2.prefix",
1219
+ type: "string"
1220
+ }),
1221
+ secretAccessKey: z12.string().nonempty().optional().register(globalRegistry9, {
1222
+ description: "Cloudflare R2 secret access key (from an R2 API token)",
1223
+ title: "storage.r2.secretAccessKey",
1224
+ type: "string"
1225
+ })
1226
+ });
1227
+
1228
+ // src/config/storage/Storage.ts
1229
+ import { globalRegistry as globalRegistry10, z as z13 } from "zod";
1230
+ var StorageConfigZod = z13.object({
660
1231
  mongo: MongoConfigZod.optional().describe("Configuration for the MongoD storage driver"),
661
- root: z12.string().optional().register(globalRegistry9, {
1232
+ r2: R2ConfigZod.optional().describe("Configuration for the Cloudflare R2 storage driver"),
1233
+ root: z13.string().optional().register(globalRegistry10, {
662
1234
  description: "Root directory for local storage",
663
1235
  title: "storage.root",
664
1236
  type: "string"
@@ -666,30 +1238,30 @@ var StorageConfigZod = z12.object({
666
1238
  }).describe("Storage configuration options");
667
1239
 
668
1240
  // src/config/Telemetry.ts
669
- import { globalRegistry as globalRegistry10, z as z13 } from "zod";
670
- var MetricsScrapeConfigZod = z13.object({
671
- path: z13.string().default("/metrics").register(globalRegistry10, {
1241
+ import { globalRegistry as globalRegistry11, z as z14 } from "zod";
1242
+ var MetricsScrapeConfigZod = z14.object({
1243
+ path: z14.string().default("/metrics").register(globalRegistry11, {
672
1244
  default: "/metrics",
673
1245
  description: "Path for the metrics scrape endpoint",
674
1246
  title: "telemetry.metrics.scrape.path",
675
1247
  type: "string"
676
1248
  }),
677
- port: z13.coerce.number().int().positive().optional().register(globalRegistry10, {
1249
+ port: z14.coerce.number().int().positive().optional().register(globalRegistry11, {
678
1250
  description: "Port for the metrics scrape endpoint",
679
1251
  title: "telemetry.metrics.scrape.port",
680
1252
  type: "number"
681
1253
  })
682
1254
  }).describe("Metrics scrape configuration");
683
- var MetricsConfigZod = z13.object({ scrape: MetricsScrapeConfigZod }).describe("Metrics configuration options");
684
- var OpenTelemetryConfigZod = z13.object({
1255
+ var MetricsConfigZod = z14.object({ scrape: MetricsScrapeConfigZod }).describe("Metrics configuration options");
1256
+ var OpenTelemetryConfigZod = z14.object({
685
1257
  // OpenTelemetry options
686
- otlpEndpoint: z13.url().optional().register(globalRegistry10, {
1258
+ otlpEndpoint: z14.url().optional().register(globalRegistry11, {
687
1259
  description: "OTLP endpoint for exporting telemetry data",
688
1260
  title: "telemetry.otel.otlpEndpoint",
689
1261
  type: "string"
690
1262
  })
691
1263
  });
692
- var TelemetryConfigZod = z13.object({
1264
+ var TelemetryConfigZod = z14.object({
693
1265
  // Metrics configuration
694
1266
  metrics: MetricsConfigZod.optional().describe("Metrics configuration"),
695
1267
  // OpenTelemetry configuration
@@ -698,14 +1270,14 @@ var TelemetryConfigZod = z13.object({
698
1270
 
699
1271
  // src/config/Validation.ts
700
1272
  import { XyoAddressZod as XyoAddressZod2 } from "@xyo-network/address";
701
- import { globalRegistry as globalRegistry11, z as z14 } from "zod";
1273
+ import { globalRegistry as globalRegistry12, z as z15 } from "zod";
702
1274
 
703
1275
  // src/primitives/block/rate/blockRate.ts
704
- import { isDefined as isDefined3, isFalsy } from "@xylabs/sdk-js";
1276
+ import { isDefined as isDefined7, isFalsy } from "@xylabs/sdk-js";
705
1277
  import { asXL1BlockRange } from "@xyo-network/xl1-protocol-lib";
706
1278
 
707
1279
  // src/primitives/block/rate/timeHelpers.ts
708
- import { assertEx as assertEx5, isDefined as isDefined2 } from "@xylabs/sdk-js";
1280
+ import { assertEx as assertEx10, isDefined as isDefined6 } from "@xylabs/sdk-js";
709
1281
  var rateMultipliers = {
710
1282
  millis: 1,
711
1283
  seconds: 1e3,
@@ -723,7 +1295,7 @@ var timeDurations = (timeInMs) => ({
723
1295
  weeks: timeInMs / (1e3 * 60 * 60 * 24 * 7)
724
1296
  });
725
1297
  var getTimeConfigInMilliseconds = (timeConfig) => {
726
- const assertedTimeConfig = assertEx5(isDefined2(timeConfig) ? timeConfig : void 0, () => "Time configuration must be provided");
1298
+ const assertedTimeConfig = assertEx10(isDefined6(timeConfig) ? timeConfig : void 0, () => "Time configuration must be provided");
727
1299
  let totalMilliseconds = 0;
728
1300
  if ("years" in assertedTimeConfig) {
729
1301
  totalMilliseconds += assertedTimeConfig.years * 31536e6;
@@ -762,13 +1334,13 @@ var blockRate = (startBlock, endBlock, timeUnit) => {
762
1334
  throw new Error("Time difference must be greater than 0");
763
1335
  }
764
1336
  const rate = heightDifference / timeDifference;
765
- const timeUnitValue = isDefined3(timeUnit) ? timeUnit : "millis";
766
- const returnedTimeDifference = isDefined3(timeUnit) ? timeDurations(timeDifference)[timeUnit] : timeDifference;
1337
+ const timeUnitValue = isDefined7(timeUnit) ? timeUnit : "millis";
1338
+ const returnedTimeDifference = isDefined7(timeUnit) ? timeDurations(timeDifference)[timeUnit] : timeDifference;
767
1339
  const timePerBlock = returnedTimeDifference / heightDifference;
768
1340
  return {
769
1341
  range: asXL1BlockRange([startingBlock.block, endingBlock.block], true),
770
1342
  span: heightDifference,
771
- rate: isDefined3(timeUnit) ? rate * rateMultipliers[timeUnit] : rate,
1343
+ rate: isDefined7(timeUnit) ? rate * rateMultipliers[timeUnit] : rate,
772
1344
  timeUnit: timeUnitValue,
773
1345
  timeDifference: returnedTimeDifference,
774
1346
  timePerBlock
@@ -789,371 +1361,103 @@ var calculateBlockRate = async (viewer, range, timeUnit) => {
789
1361
  const [startBlockHeight, endBlockHeight] = range;
790
1362
  const { startingBlock, endingBlock } = await getBlockRateBlocks(
791
1363
  viewer,
792
- startBlockHeight,
793
- endBlockHeight
794
- );
795
- return blockRate(startingBlock, endingBlock, timeUnit);
796
- };
797
-
798
- // src/primitives/block/rate/stepRate.ts
799
- import { assertEx as assertEx6 } from "@xylabs/sdk-js";
800
- import {
801
- asXL1BlockRange as asXL1BlockRange2,
802
- isValidStep,
803
- StepSizes
804
- } from "@xyo-network/xl1-protocol-lib";
805
- var stepRate = async (viewer, start, step, count = 1, timeUnit) => {
806
- const end = start + step * count;
807
- const range = asXL1BlockRange2([start, end], true);
808
- return await calculateBlockRate(viewer, range, timeUnit);
809
- };
810
- var calculateStepSizeRate = async (viewer, start, stepIndex, count = 1, timeUnit) => {
811
- assertEx6(isValidStep(stepIndex), () => `Invalid step index: ${stepIndex}`);
812
- const step = StepSizes[stepIndex];
813
- return await stepRate(viewer, start, step, count, timeUnit);
814
- };
815
-
816
- // src/primitives/block/rate/timeRate.ts
817
- import {
818
- assertEx as assertEx7,
819
- isDefined as isDefined4,
820
- isDefinedNotNull
821
- } from "@xylabs/sdk-js";
822
- import { asXL1BlockNumber as asXL1BlockNumber2, asXL1BlockRange as asXL1BlockRange3 } from "@xyo-network/xl1-protocol-lib";
823
- var DEFAULT_TOLERANCE_MS = 3e4;
824
- var DEFAULT_MAX_ATTEMPTS = 10;
825
- var calculateTimeRate = async (viewer, timeConfig, startBlockNumber, timeUnit, toleranceMs = DEFAULT_TOLERANCE_MS, maxAttempts = DEFAULT_MAX_ATTEMPTS) => {
826
- assertEx7(Object.keys(timeConfig ?? {}).length === 1, () => "Only one time unit should be specified in timeConfig");
827
- const startBlock = isDefinedNotNull(startBlockNumber) ? await viewer.blockByNumber(startBlockNumber) : null;
828
- const resolvedStartBlock = isDefinedNotNull(startBlock) ? startBlock[0] : (await viewer.currentBlock())[0];
829
- const timeInMilliseconds = getTimeConfigInMilliseconds(timeConfig);
830
- assertEx7(timeInMilliseconds > 0, () => "Time duration must be greater than zero");
831
- const blocksPerMillisecondRate = 1 / (12 * 1e3);
832
- const initialBlocksInDuration = Math.floor(blocksPerMillisecondRate * timeInMilliseconds);
833
- const endBlockNumber = await findEndBlockRecursive(
834
- viewer,
835
- resolvedStartBlock,
836
- timeInMilliseconds,
837
- initialBlocksInDuration,
838
- toleranceMs,
839
- maxAttempts
840
- );
841
- return await calculateBlockRate(
842
- viewer,
843
- asXL1BlockRange3([endBlockNumber, resolvedStartBlock.block], true),
844
- timeUnit
845
- );
846
- };
847
- var findEndBlockRecursive = async (viewer, startBlock, targetTimeMs, estimatedBlocksBack, toleranceMs, attemptsRemaining) => {
848
- assertEx7(attemptsRemaining >= 0, () => "Maximum attempts reached while searching for end block");
849
- const startBlockEpoch = startBlock.$epoch;
850
- const estimatedEndBlockNumber = asXL1BlockNumber2(startBlock.block - estimatedBlocksBack, true);
851
- if (estimatedEndBlockNumber < 0) {
852
- throw new Error("Estimated end block number is less than zero");
853
- }
854
- const endBlock = await viewer.blockByNumber(estimatedEndBlockNumber);
855
- const resolvedEndBlock = assertEx7(
856
- isDefined4(endBlock?.[0]) ? endBlock[0] : void 0,
857
- () => `Could not retrieve block ${estimatedEndBlockNumber} for time rate calculation`
858
- );
859
- const endBlockEpoch = resolvedEndBlock.$epoch;
860
- if (!Number.isFinite(startBlockEpoch) || !Number.isFinite(endBlockEpoch)) {
861
- throw new TypeError("Block has missing or invalid $epoch");
862
- }
863
- const actualTimeDifference = startBlockEpoch - endBlockEpoch;
864
- if (actualTimeDifference === 0) {
865
- throw new Error("Start and end blocks have identical timestamps");
866
- }
867
- const timeDelta = Math.abs(actualTimeDifference - targetTimeMs);
868
- if (timeDelta <= toleranceMs) {
869
- return resolvedEndBlock.block;
870
- }
871
- let adjustedBlocksBack;
872
- if (actualTimeDifference < targetTimeMs) {
873
- const adjustmentFactor = targetTimeMs / actualTimeDifference;
874
- adjustedBlocksBack = Math.floor(estimatedBlocksBack * adjustmentFactor);
875
- } else {
876
- const adjustmentFactor = actualTimeDifference / targetTimeMs;
877
- adjustedBlocksBack = Math.floor(estimatedBlocksBack / adjustmentFactor);
878
- }
879
- adjustedBlocksBack = Number.isFinite(adjustedBlocksBack) && adjustedBlocksBack >= 1 ? adjustedBlocksBack : 1;
880
- return await findEndBlockRecursive(
881
- viewer,
882
- startBlock,
883
- targetTimeMs,
884
- adjustedBlocksBack,
885
- toleranceMs,
886
- attemptsRemaining - 1
887
- );
888
- };
889
-
890
- // src/ChainContextHelpers.ts
891
- import {
892
- isDefined as isDefined6,
893
- isObject,
894
- isUndefined as isUndefined2,
895
- timeBudget
896
- } from "@xylabs/sdk-js";
897
-
898
- // src/driver/cache/LruCacheMap.ts
899
- import { LRUCache } from "lru-cache";
900
- var LruCacheMap = class {
901
- lruCache;
902
- constructor(options) {
903
- this.lruCache = new LRUCache(options ?? { max: 5e3 });
904
- }
905
- clear() {
906
- this.lruCache.clear();
907
- }
908
- delete(id) {
909
- return this.lruCache.delete(id);
910
- }
911
- get(id) {
912
- return this.lruCache.get(id);
913
- }
914
- getMany(id) {
915
- const results = [];
916
- for (const key of id) {
917
- const value = this.lruCache.get(key);
918
- if (value !== void 0) {
919
- results.push(value);
920
- }
921
- }
922
- return results;
923
- }
924
- has(id) {
925
- return this.lruCache.has(id);
926
- }
927
- set(id, data) {
928
- this.lruCache.set(id, data);
929
- }
930
- setMany(entries) {
931
- for (const [key, value] of entries) {
932
- this.lruCache.set(key, value);
933
- }
934
- }
935
- };
936
-
937
- // src/driver/memory/MemoryMap.ts
938
- import { isDefined as isDefined5 } from "@xylabs/sdk-js";
939
- var MemoryMap = class {
940
- map;
941
- constructor() {
942
- this.map = /* @__PURE__ */ new Map();
943
- }
944
- clear() {
945
- this.map.clear();
946
- }
947
- delete(id) {
948
- return this.map.delete(id);
949
- }
950
- get(id) {
951
- return this.map.get(id);
952
- }
953
- getMany(ids) {
954
- const results = [];
955
- for (const id of ids) {
956
- const data = this.map.get(id);
957
- if (isDefined5(data)) {
958
- results.push(data);
959
- }
960
- }
961
- return results;
962
- }
963
- has(id) {
964
- return this.map.has(id);
965
- }
966
- set(id, data) {
967
- this.map.set(id, data);
968
- }
969
- setMany(entries) {
970
- for (const [key, value] of entries) {
971
- this.map.set(key, value);
972
- }
973
- }
974
- };
975
-
976
- // src/ChainContextHelpers.ts
977
- function contextCache(context, name, create) {
978
- if (!isObject(context.caches)) {
979
- throw new Error("Context does not have an appropriate caches property");
980
- }
981
- if (isUndefined2(context.caches[name])) {
982
- context.caches[name] = create?.() ?? new MemoryMap();
983
- }
984
- return context.caches[name];
985
- }
986
- async function withContextCacheResponse(context, name, key, func, { max = 1e4 } = {}) {
987
- const cache = contextCache(
988
- context,
989
- name,
990
- () => new LruCacheMap({ max })
991
- );
992
- const { timeBudgetLimit = 0 } = context;
993
- const cacheResult = await cache.get(key);
994
- if (isDefined6(cacheResult)) {
995
- return cacheResult;
996
- }
997
- const result = timeBudgetLimit > 0 ? timeBudget(name, context.logger, func, timeBudgetLimit) : func();
998
- await cache.set(key, result);
999
- return result;
1000
- }
1001
-
1002
- // src/block/hydrate/allHashesPresent.ts
1003
- function allHashesPresent(hashes, payloads) {
1004
- const payloadHashes = new Set(payloads.map((p) => p._hash));
1005
- return hashes.every((hash) => payloadHashes.has(hash));
1006
- }
1007
-
1008
- // src/block/hydrate/flattenHydratedBlock.ts
1009
- import { toHydratedBlock } from "@xyo-network/xl1-protocol-lib";
1010
- var flattenHydratedBlock = (hydratedBlock) => {
1011
- const [blk, blkPayloads] = hydratedBlock;
1012
- return [...blkPayloads, blk];
1013
- };
1014
-
1015
- // src/block/hydrate/flattenHydratedBlocks.ts
1016
- var flattenHydratedBlocks = (hydratedBlocks) => hydratedBlocks.flatMap((blk) => flattenHydratedBlock(blk));
1017
-
1018
- // src/block/hydrate/hydrateBlock.ts
1019
- import { assertEx as assertEx8 } from "@xylabs/sdk-js";
1020
- import { asAnyPayload as asAnyPayload2 } from "@xyo-network/sdk-js";
1021
- import { asBlockBoundWitnessWithStorageMeta, isTransactionBoundWitnessWithStorageMeta } from "@xyo-network/xl1-protocol-lib";
1022
- var hydrateBlock = async (context, hash, maxDepth = 1, minDepth = maxDepth) => {
1023
- assertEx8(maxDepth >= 0, () => "maxDepth must be greater than or equal to 0");
1024
- assertEx8(minDepth >= 0, () => "minDepth must be greater than or equal to 0");
1025
- assertEx8(maxDepth >= minDepth, () => "maxDepth must be greater than or equal to minDepth");
1026
- const { chainMap } = context;
1027
- const [block] = await chainMap.get([hash]);
1028
- const bw = assertEx8(asBlockBoundWitnessWithStorageMeta(
1029
- assertEx8(block, () => `block ${hash} not found`)
1030
- ), () => `hash ${hash} is not a BlockBoundWitness`);
1031
- if (maxDepth === 0) return [bw, []];
1032
- const blkPayloads = (await chainMap.get(bw.payload_hashes)).map((p) => asAnyPayload2(p, true));
1033
- if (minDepth === 1) assertEx8(allHashesPresent(bw.payload_hashes, blkPayloads), () => `Unable to find all payloads for block ${hash}`);
1034
- if (maxDepth === 1) return [bw, blkPayloads];
1035
- const transactions = blkPayloads.filter(isTransactionBoundWitnessWithStorageMeta);
1036
- const transactionsPayloadHashes = transactions.flatMap((tx) => tx.payload_hashes);
1037
- const transactionsPayloads = (await chainMap.get(transactionsPayloadHashes)).map((p) => asAnyPayload2(p, true));
1038
- assertEx8(allHashesPresent(transactionsPayloadHashes, transactionsPayloads), () => `Unable to find all payloads for transactions in block ${hash}`);
1039
- const allPayloadsHashes = new Set([...blkPayloads, ...transactionsPayloads].flatMap((p) => p._hash));
1040
- const allPayloads = (await chainMap.get([...allPayloadsHashes])).map((p) => asAnyPayload2(p, true));
1041
- const allPayloadsFiltered = allPayloads.filter((p) => allPayloadsHashes.has(p._hash));
1042
- if (maxDepth === 2) assertEx8(allHashesPresent(
1043
- [...allPayloadsHashes],
1044
- allPayloadsFiltered
1045
- ), () => `Unable to find all payloads for transactions in block ${hash}`);
1046
- return [bw, allPayloadsFiltered];
1047
- };
1048
-
1049
- // src/block/primitives/blockFromBlockNumber.ts
1050
- import {
1051
- asHash,
1052
- isDefined as isDefined7,
1053
- spanAsync
1054
- } from "@xylabs/sdk-js";
1055
- import { toSafeJsonString } from "@xylabs/sdk-js";
1056
- import {
1057
- asSignedBlockBoundWitnessWithStorageMeta,
1058
- SignedBlockBoundWitnessWithHashMetaZod,
1059
- StepSizes as StepSizes2
1060
- } from "@xyo-network/xl1-protocol-lib";
1061
- async function blockFromBlockNumber(context, blockNumber) {
1062
- return await spanAsync("blockFromBlockNumber", async () => {
1063
- const cacheKey = `${blockNumber}`;
1064
- const { chainMap, head } = context;
1065
- return await withContextCacheResponse(context, "blockFromBlockNumber", cacheKey, async () => {
1066
- const [result] = await chainMap.get([head._hash]);
1067
- if (!isDefined7(result)) {
1068
- throw new Error(`Head block not found for hash: ${head._hash}`);
1069
- }
1070
- let currentBlock = asSignedBlockBoundWitnessWithStorageMeta(
1071
- result,
1072
- () => `Found Payload is not a Signed<BlockBoundWitness>: ${JSON.stringify(result, null, 2)}`
1073
- );
1074
- if (currentBlock.block < blockNumber) {
1075
- throw new Error(`Block number ${blockNumber} is greater than head ${currentBlock.block}.`);
1076
- }
1077
- while (currentBlock.block > blockNumber) {
1078
- let jumpHash = currentBlock.previous;
1079
- let jumpBlockNumber = currentBlock.block - 1;
1080
- for (const [step, stepSize] of StepSizes2.entries()) {
1081
- const possibleJumpBlockNumber = currentBlock.block - currentBlock.block % stepSize - 1;
1082
- if (possibleJumpBlockNumber >= blockNumber && possibleJumpBlockNumber <= jumpBlockNumber) {
1083
- jumpBlockNumber = possibleJumpBlockNumber;
1084
- jumpHash = asHash(currentBlock.step_hashes?.at(step), () => `Step hash not found for step ${step} in block ${currentBlock.block}`);
1085
- }
1086
- }
1087
- const [newBlock] = await chainMap.get([
1088
- asHash(jumpHash, () => `Jump hash not found for block number [${blockNumber}]: ${jumpBlockNumber} ${toSafeJsonString(currentBlock, 10)}`)
1089
- ]);
1090
- if (!isDefined7(newBlock)) {
1091
- throw new Error(`Block not found for jump hash: ${jumpHash}`);
1092
- }
1093
- currentBlock = asSignedBlockBoundWitnessWithStorageMeta(
1094
- newBlock,
1095
- () => {
1096
- const result2 = SignedBlockBoundWitnessWithHashMetaZod.safeParse(newBlock);
1097
- return `Found Payload [jump hash] is not a Signed<BlockBoundWitness>: ${result2.error}`;
1098
- }
1099
- );
1100
- if (currentBlock.block === blockNumber) {
1101
- break;
1102
- }
1103
- if (currentBlock.block < blockNumber) {
1104
- throw new Error(`Block number ${blockNumber} is not a valid step block number for block ${head._hash}.`);
1105
- }
1106
- }
1107
- return currentBlock;
1108
- });
1109
- }, { ...context, timeBudgetLimit: 500 });
1110
- }
1364
+ startBlockHeight,
1365
+ endBlockHeight
1366
+ );
1367
+ return blockRate(startingBlock, endingBlock, timeUnit);
1368
+ };
1111
1369
 
1112
- // src/block/primitives/validateTransactionOpcodes.ts
1370
+ // src/primitives/block/rate/stepRate.ts
1371
+ import { assertEx as assertEx11 } from "@xylabs/sdk-js";
1113
1372
  import {
1114
- assertEx as assertEx9,
1115
- isHash,
1116
- toSafeJsonString as toSafeJsonString2
1117
- } from "@xylabs/sdk-js";
1373
+ asXL1BlockRange as asXL1BlockRange2,
1374
+ isValidStep,
1375
+ StepSizes as StepSizes4
1376
+ } from "@xyo-network/xl1-protocol-lib";
1377
+ var stepRate = async (viewer, start, step, count = 1, timeUnit) => {
1378
+ const end = start + step * count;
1379
+ const range = asXL1BlockRange2([start, end], true);
1380
+ return await calculateBlockRate(viewer, range, timeUnit);
1381
+ };
1382
+ var calculateStepSizeRate = async (viewer, start, stepIndex, count = 1, timeUnit) => {
1383
+ assertEx11(isValidStep(stepIndex), () => `Invalid step index: ${stepIndex}`);
1384
+ const step = StepSizes4[stepIndex];
1385
+ return await stepRate(viewer, start, step, count, timeUnit);
1386
+ };
1387
+
1388
+ // src/primitives/block/rate/timeRate.ts
1118
1389
  import {
1119
- PayloadBuilder as PayloadBuilder3
1120
- } from "@xyo-network/sdk-js";
1121
- import { isExecutable } from "@xyo-network/xl1-protocol-lib";
1122
- async function validateTransactionsOpcodes(txs) {
1123
- const txElevatedPayloads = [];
1124
- for (const [txBw, txPayloads] of txs) {
1125
- if (isExecutable(txBw)) {
1126
- const operations = txBw.script.map((op) => op.split("|"));
1127
- for (const [opCode, ...args] of operations) {
1128
- switch (opCode) {
1129
- case "elevate": {
1130
- const [hash, ...rest] = args;
1131
- const txPayloadsWithStorageMeta = await PayloadBuilder3.addStorageMeta(txPayloads);
1132
- assertEx9(rest.length === 0, () => `Invalid elevate operation ${opCode} ${args.join(", ")} - Too many Arguments`);
1133
- if (isHash(hash)) {
1134
- assertEx9(
1135
- txBw.payload_hashes.includes(hash),
1136
- () => `Invalid elevate operation ${opCode} ${args.join(", ")} - Hash not in payload hashes => ${toSafeJsonString2(txBw, 20)}`
1137
- );
1138
- const txPayload = assertEx9(
1139
- txPayloadsWithStorageMeta.find((p) => p._hash === hash),
1140
- () => `Invalid elevate operation ${opCode} ${args.join(", ")} - Payload not found`
1141
- );
1142
- txElevatedPayloads.push(txPayload);
1143
- } else {
1144
- throw new Error(`Invalid elevate operation ${opCode} ${args.join(", ")} - Invalid hash`);
1145
- }
1146
- break;
1147
- }
1148
- default: {
1149
- throw new Error(`Invalid opCode ${opCode}`);
1150
- }
1151
- }
1152
- }
1153
- }
1390
+ assertEx as assertEx12,
1391
+ isDefined as isDefined8,
1392
+ isDefinedNotNull
1393
+ } from "@xylabs/sdk-js";
1394
+ import { asXL1BlockNumber as asXL1BlockNumber7, asXL1BlockRange as asXL1BlockRange3 } from "@xyo-network/xl1-protocol-lib";
1395
+ var DEFAULT_TOLERANCE_MS = 3e4;
1396
+ var DEFAULT_MAX_ATTEMPTS = 10;
1397
+ var calculateTimeRate = async (viewer, timeConfig, startBlockNumber, timeUnit, toleranceMs = DEFAULT_TOLERANCE_MS, maxAttempts = DEFAULT_MAX_ATTEMPTS) => {
1398
+ assertEx12(Object.keys(timeConfig ?? {}).length === 1, () => "Only one time unit should be specified in timeConfig");
1399
+ const startBlock = isDefinedNotNull(startBlockNumber) ? await viewer.blockByNumber(startBlockNumber) : null;
1400
+ const resolvedStartBlock = isDefinedNotNull(startBlock) ? startBlock[0] : (await viewer.currentBlock())[0];
1401
+ const timeInMilliseconds = getTimeConfigInMilliseconds(timeConfig);
1402
+ assertEx12(timeInMilliseconds > 0, () => "Time duration must be greater than zero");
1403
+ const blocksPerMillisecondRate = 1 / (12 * 1e3);
1404
+ const initialBlocksInDuration = Math.floor(blocksPerMillisecondRate * timeInMilliseconds);
1405
+ const endBlockNumber = await findEndBlockRecursive(
1406
+ viewer,
1407
+ resolvedStartBlock,
1408
+ timeInMilliseconds,
1409
+ initialBlocksInDuration,
1410
+ toleranceMs,
1411
+ maxAttempts
1412
+ );
1413
+ return await calculateBlockRate(
1414
+ viewer,
1415
+ asXL1BlockRange3([endBlockNumber, resolvedStartBlock.block], true),
1416
+ timeUnit
1417
+ );
1418
+ };
1419
+ var findEndBlockRecursive = async (viewer, startBlock, targetTimeMs, estimatedBlocksBack, toleranceMs, attemptsRemaining) => {
1420
+ assertEx12(attemptsRemaining >= 0, () => "Maximum attempts reached while searching for end block");
1421
+ const startBlockEpoch = startBlock.$epoch;
1422
+ const estimatedEndBlockNumber = asXL1BlockNumber7(startBlock.block - estimatedBlocksBack, true);
1423
+ if (estimatedEndBlockNumber < 0) {
1424
+ throw new Error("Estimated end block number is less than zero");
1154
1425
  }
1155
- return txElevatedPayloads;
1156
- }
1426
+ const endBlock = await viewer.blockByNumber(estimatedEndBlockNumber);
1427
+ const resolvedEndBlock = assertEx12(
1428
+ isDefined8(endBlock?.[0]) ? endBlock[0] : void 0,
1429
+ () => `Could not retrieve block ${estimatedEndBlockNumber} for time rate calculation`
1430
+ );
1431
+ const endBlockEpoch = resolvedEndBlock.$epoch;
1432
+ if (!Number.isFinite(startBlockEpoch) || !Number.isFinite(endBlockEpoch)) {
1433
+ throw new TypeError("Block has missing or invalid $epoch");
1434
+ }
1435
+ const actualTimeDifference = startBlockEpoch - endBlockEpoch;
1436
+ if (actualTimeDifference === 0) {
1437
+ throw new Error("Start and end blocks have identical timestamps");
1438
+ }
1439
+ const timeDelta = Math.abs(actualTimeDifference - targetTimeMs);
1440
+ if (timeDelta <= toleranceMs) {
1441
+ return resolvedEndBlock.block;
1442
+ }
1443
+ let adjustedBlocksBack;
1444
+ if (actualTimeDifference < targetTimeMs) {
1445
+ const adjustmentFactor = targetTimeMs / actualTimeDifference;
1446
+ adjustedBlocksBack = Math.floor(estimatedBlocksBack * adjustmentFactor);
1447
+ } else {
1448
+ const adjustmentFactor = actualTimeDifference / targetTimeMs;
1449
+ adjustedBlocksBack = Math.floor(estimatedBlocksBack / adjustmentFactor);
1450
+ }
1451
+ adjustedBlocksBack = Number.isFinite(adjustedBlocksBack) && adjustedBlocksBack >= 1 ? adjustedBlocksBack : 1;
1452
+ return await findEndBlockRecursive(
1453
+ viewer,
1454
+ startBlock,
1455
+ targetTimeMs,
1456
+ adjustedBlocksBack,
1457
+ toleranceMs,
1458
+ attemptsRemaining - 1
1459
+ );
1460
+ };
1157
1461
 
1158
1462
  // src/primitives/state/findMostRecentBlock.ts
1159
1463
  import { isSignedBlockBoundWitnessWithStorageMeta } from "@xyo-network/xl1-protocol-lib";
@@ -1183,7 +1487,7 @@ var findMostRecentBlock = async (chainArchivist, nextOptions = DEFAULT_NEXT_OPTI
1183
1487
  };
1184
1488
 
1185
1489
  // src/primitives/state/hydratedBlockByNumber.ts
1186
- import { assertEx as assertEx10, spanAsync as spanAsync2 } from "@xylabs/sdk-js";
1490
+ import { assertEx as assertEx13, spanAsync as spanAsync2 } from "@xylabs/sdk-js";
1187
1491
  async function hydratedBlockByNumber(context, blockNumber) {
1188
1492
  return await spanAsync2("hydratedBlockByNumber", async () => {
1189
1493
  if (blockNumber < 0) throw new Error(`Block number ${blockNumber} is less than 0`);
@@ -1191,7 +1495,7 @@ async function hydratedBlockByNumber(context, blockNumber) {
1191
1495
  if (blockNumber % 1 !== 0) throw new Error(`Block number ${blockNumber} is not an integer`);
1192
1496
  const cacheKey = `${blockNumber}`;
1193
1497
  return await withContextCacheResponse(context, "hydratedBlockByNumber", cacheKey, async () => {
1194
- const block = assertEx10(
1498
+ const block = assertEx13(
1195
1499
  await blockFromBlockNumber(context, blockNumber),
1196
1500
  () => `Could not find block for block number ${blockNumber}`
1197
1501
  );
@@ -1205,24 +1509,24 @@ var DEFAULT_MIN_CANDIDATES = 1;
1205
1509
  var DEFAULT_BACKOFF_MS = 12e4;
1206
1510
 
1207
1511
  // src/config/Validation.ts
1208
- var ValidationConfigZod = z14.object({
1209
- allowedRewardRedeemers: z14.array(XyoAddressZod2).optional().register(globalRegistry11, {
1512
+ var ValidationConfigZod = z15.object({
1513
+ allowedRewardRedeemers: z15.array(XyoAddressZod2).optional().register(globalRegistry12, {
1210
1514
  description: "List of allowed reward redeemer addresses, if undefined anyone can participate",
1211
1515
  title: "allowedRewardRedeemers",
1212
1516
  type: "array"
1213
1517
  }),
1214
- allowedRewardEscrowAccountSigners: z14.array(XyoAddressZod2).optional().register(globalRegistry11, {
1518
+ allowedRewardEscrowAccountSigners: z15.array(XyoAddressZod2).optional().register(globalRegistry12, {
1215
1519
  description: "List of allowed reward escrow account signer addresses, if undefined anyone can participate",
1216
1520
  title: "allowedRewardEscrowAccountSigners",
1217
1521
  type: "array"
1218
1522
  }),
1219
- minCandidates: z14.coerce.number().default(DEFAULT_MIN_CANDIDATES).register(globalRegistry11, {
1523
+ minCandidates: z15.coerce.number().default(DEFAULT_MIN_CANDIDATES).register(globalRegistry12, {
1220
1524
  default: DEFAULT_MIN_CANDIDATES,
1221
1525
  description: "Minimum number of uncle candidates before selecting the best uncle",
1222
1526
  title: "validation.minCandidates",
1223
1527
  type: "number"
1224
1528
  }),
1225
- backoffMs: z14.coerce.number().default(DEFAULT_BACKOFF_MS).register(globalRegistry11, {
1529
+ backoffMs: z15.coerce.number().default(DEFAULT_BACKOFF_MS).register(globalRegistry12, {
1226
1530
  default: DEFAULT_BACKOFF_MS,
1227
1531
  description: "Back-off timeout in ms. If head age exceeds this, minCandidates is ignored",
1228
1532
  title: "validation.backoffMs",
@@ -1231,26 +1535,26 @@ var ValidationConfigZod = z14.object({
1231
1535
  });
1232
1536
 
1233
1537
  // src/config/Base.ts
1234
- var BaseConfigZod = z15.object({
1235
- chain: z15._default(ChainConfigZod, ChainConfigZod.parse({})).check(z15.describe("Configuration for the chain")),
1236
- dataLake: z15.optional(DataLakeConfigZod).check(z15.describe("Configuration for data lakes")),
1237
- evm: z15._default(EvmConfigZod, EvmConfigZod.parse({})).check(z15.describe("Configuration for EVM-backed services")),
1238
- log: z15._default(LogConfigZod, LogConfigZod.parse({})).check(z15.describe("Configuration for logging")),
1239
- providers: z15._default(ProvidersConfigZod, ProvidersConfigZod.parse([])).check(z15.describe("Configuration for providers")),
1240
- remote: z15._default(RemoteConfigZod, RemoteConfigZod.parse({})).check(z15.describe("Configuration for remote services")),
1241
- storage: z15._default(StorageConfigZod, StorageConfigZod.parse({})).check(z15.describe("Configuration for the storage")),
1242
- telemetry: z15._default(TelemetryConfigZod, TelemetryConfigZod.parse({})).check(z15.describe("Configuration for telemetry")),
1243
- validation: z15._default(ValidationConfigZod, ValidationConfigZod.parse({})).check(z15.describe("Configuration for validation"))
1538
+ var BaseConfigZod = z16.object({
1539
+ chain: z16._default(ChainConfigZod, ChainConfigZod.parse({})).check(z16.describe("Configuration for the chain")),
1540
+ dataLake: z16.optional(DataLakeConfigZod).check(z16.describe("Configuration for data lakes")),
1541
+ evm: z16._default(EvmConfigZod, EvmConfigZod.parse({})).check(z16.describe("Configuration for EVM-backed services")),
1542
+ log: z16._default(LogConfigZod, LogConfigZod.parse({})).check(z16.describe("Configuration for logging")),
1543
+ providers: z16._default(ProvidersConfigZod, ProvidersConfigZod.parse([])).check(z16.describe("Configuration for providers")),
1544
+ remote: z16._default(RemoteConfigZod, RemoteConfigZod.parse({})).check(z16.describe("Configuration for remote services")),
1545
+ storage: z16._default(StorageConfigZod, StorageConfigZod.parse({})).check(z16.describe("Configuration for the storage")),
1546
+ telemetry: z16._default(TelemetryConfigZod, TelemetryConfigZod.parse({})).check(z16.describe("Configuration for telemetry")),
1547
+ validation: z16._default(ValidationConfigZod, ValidationConfigZod.parse({})).check(z16.describe("Configuration for validation"))
1244
1548
  });
1245
1549
 
1246
1550
  // src/config/Actor.ts
1247
- var AccountPathZod = z16.string().check(z16.regex(
1551
+ var AccountPathZod = z17.string().check(z17.regex(
1248
1552
  /^(m(\/\d+'?)+|\d+'?(\/\d+'?)*)$/,
1249
1553
  `Invalid BIP-32 derivation path. Use either an absolute path like "m/44'/60'/0'/0/0" or a relative path like "0", "0/1", or "44'/60'/0'/0/0".`
1250
1554
  ));
1251
- var ActorConfigZod = z16.extend(BaseConfigZod, {
1252
- name: z16.string(),
1253
- accountPath: z16.optional(AccountPathZod).register(globalRegistry12, {
1555
+ var ActorConfigZod = z17.extend(BaseConfigZod, {
1556
+ name: z17.string(),
1557
+ accountPath: z17.optional(AccountPathZod).register(globalRegistry13, {
1254
1558
  description: 'BIP-32 derivation path for the actor wallet. Absolute when it starts with "m/"; otherwise relative to the root wallet base path. Each actor must derive to a distinct path.',
1255
1559
  title: "accountPath",
1256
1560
  type: "string"
@@ -1261,39 +1565,123 @@ var asActorConfig = zodAsFactory2(ActorConfigZod, "asActorConfig");
1261
1565
  var toActorConfig = zodToFactory2(ActorConfigZod, "toActorConfig");
1262
1566
 
1263
1567
  // src/config/Actors.ts
1264
- import { z as z17 } from "zod/mini";
1265
- var ActorsConfigZod = z17._default(
1266
- z17.array(z17.looseObject(ActorConfigZod.shape)).check(z17.describe("Actor-specific configurations that override the base configuration when the actor is running")),
1568
+ import { z as z18 } from "zod/mini";
1569
+ var ActorsConfigZod = z18._default(
1570
+ z18.array(z18.looseObject(ActorConfigZod.shape)).check(z18.describe("Actor-specific configurations that override the base configuration when the actor is running")),
1267
1571
  []
1268
1572
  );
1269
1573
 
1270
1574
  // src/config/Config.ts
1271
- import { globalRegistry as globalRegistry13, z as z18 } from "zod/mini";
1272
- var ConfigZod = z18.extend(BaseConfigZod, {
1575
+ import { globalRegistry as globalRegistry14, z as z19 } from "zod/mini";
1576
+ var ConfigZod = z19.extend(BaseConfigZod, {
1273
1577
  actors: ActorsConfigZod,
1274
- healthCheckPort: z18.optional(z18.coerce.number()).register(globalRegistry13, {
1578
+ healthCheckPort: z19.optional(z19.coerce.number()).register(globalRegistry14, {
1275
1579
  description: "Port for the system-wide health, readiness, and liveness endpoints (/healthz, /livez, /readyz). Set to 0 to disable.",
1276
1580
  title: "healthCheckPort",
1277
1581
  type: "number"
1278
1582
  })
1279
- }).check(z18.describe("The complete configuration for the protocol, including global settings and actor-specific overrides"));
1583
+ }).check(z19.describe("The complete configuration for the protocol, including global settings and actor-specific overrides"));
1584
+
1585
+ // src/summary/model/BlocksStepSummary.ts
1586
+ import { AsObjectFactory } from "@xylabs/sdk-js";
1587
+ import {
1588
+ asSchema as asSchema3,
1589
+ isPayloadOfSchemaType,
1590
+ isStorageMeta
1591
+ } from "@xyo-network/sdk-js";
1592
+ var BlocksStepSummarySchema = asSchema3("network.xyo.step.summary.blocks", true);
1593
+ var isBlocksStepSummary = isPayloadOfSchemaType(BlocksStepSummarySchema);
1594
+ var asBlocksStepSummary = AsObjectFactory.create(isBlocksStepSummary);
1595
+ var isBlocksStepSummaryWithStorageMeta = (value) => {
1596
+ return isBlocksStepSummary(value) && isStorageMeta(value);
1597
+ };
1598
+ var asBlocksStepSummaryWithStorageMeta = AsObjectFactory.create(isBlocksStepSummaryWithStorageMeta);
1599
+
1600
+ // src/summary/primitives/blocks/blocksMaxStep.ts
1601
+ var blocksMaxStep = 3;
1602
+
1603
+ // src/summary/primitives/blocks/blocksStepSummaryFromRange.ts
1604
+ import { assertEx as assertEx14, spanRootAsync } from "@xylabs/sdk-js";
1605
+ import { isAnyPayload } from "@xyo-network/sdk-js";
1606
+ import { asXL1BlockNumber as asXL1BlockNumber8, StepSizes as StepSizes5 } from "@xyo-network/xl1-protocol-lib";
1607
+ function blocksStepSummaryKey(frameHeadHash, frameSize) {
1608
+ return `${frameHeadHash}|${frameSize}`;
1609
+ }
1610
+ async function blocksStepSummaryFromRange(context, semaphores, blockViewer, summaryMap, range) {
1611
+ const cacheKey = `${range[0]}|${range[1]}`;
1612
+ return await withContextCacheResponse(context, "blocksStepSummaryFromRange", cacheKey, async () => {
1613
+ return await spanRootAsync("blocksStepSummaryFromRange", async () => {
1614
+ const frameHead = assertEx14(
1615
+ await blockViewer.blockByNumber(range[1]),
1616
+ () => `Block not found for number: ${range[1]}`
1617
+ );
1618
+ const frameHeadHash = frameHead[0]._hash;
1619
+ const frameSize = range[1] - range[0] + 1;
1620
+ let result;
1621
+ if (frameSize === 1) {
1622
+ result = {
1623
+ schema: BlocksStepSummarySchema,
1624
+ hash: frameHeadHash,
1625
+ stepSize: -1,
1626
+ blocks: [frameHead]
1627
+ };
1628
+ } else {
1629
+ const step = StepSizes5.indexOf(asXL1BlockNumber8(frameSize, true));
1630
+ assertEx14(step !== -1, () => `Invalid step size: ${frameSize}. Must be one of ${StepSizes5.join(", ")}`);
1631
+ const key = blocksStepSummaryKey(frameHeadHash, frameSize);
1632
+ const summaryResult = await summaryMap.get(key);
1633
+ if (isAnyPayload(summaryResult)) {
1634
+ result = asBlocksStepSummary(summaryResult, { required: true });
1635
+ } else {
1636
+ await semaphores[step].acquire();
1637
+ try {
1638
+ const subRanges = deepCalculateFramesFromRange(range, step - 1);
1639
+ const subResults = await Promise.all(subRanges.map((subRange) => blocksStepSummaryFromRange(
1640
+ context,
1641
+ semaphores,
1642
+ blockViewer,
1643
+ summaryMap,
1644
+ subRange
1645
+ )));
1646
+ const blocks = subResults.flatMap((subResult) => subResult.blocks);
1647
+ result = {
1648
+ schema: BlocksStepSummarySchema,
1649
+ hash: frameHeadHash,
1650
+ stepSize: frameSize,
1651
+ blocks
1652
+ };
1653
+ await summaryMap.set(key, result);
1654
+ } finally {
1655
+ semaphores[step].release();
1656
+ }
1657
+ }
1658
+ }
1659
+ return result;
1660
+ }, { ...context, timeBudgetLimit: 500 });
1661
+ }, { max: 1e5 });
1662
+ }
1280
1663
 
1281
1664
  // src/simple/block/SimpleBlockViewer.ts
1282
1665
  import {
1283
- assertEx as assertEx11,
1666
+ assertEx as assertEx15,
1284
1667
  exists,
1285
- isUndefined as isUndefined3
1668
+ isUndefined as isUndefined4
1286
1669
  } from "@xylabs/sdk-js";
1670
+ import { LruCacheMap as LruCacheMap2 } from "@xyo-network/xl1-driver-memory";
1287
1671
  import {
1288
1672
  asSignedHydratedBlockWithHashMeta,
1289
1673
  asSignedHydratedBlockWithStorageMeta,
1290
- asXL1BlockNumber as asXL1BlockNumber3,
1674
+ asXL1BlockNumber as asXL1BlockNumber9,
1675
+ asXL1BlockRange as asXL1BlockRange4,
1291
1676
  BlockViewerMoniker,
1292
- FinalizationViewerMoniker
1677
+ FinalizationViewerMoniker,
1678
+ stepSize as stepSize2,
1679
+ StepSizes as StepSizes6
1293
1680
  } from "@xyo-network/xl1-protocol-lib";
1681
+ import { Semaphore } from "async-mutex";
1294
1682
 
1295
1683
  // src/utils/HydratedCache.ts
1296
- import { LRUCache as LRUCache2 } from "lru-cache";
1684
+ import { LRUCache } from "lru-cache";
1297
1685
  var HydratedCache = class {
1298
1686
  cache;
1299
1687
  context;
@@ -1301,7 +1689,7 @@ var HydratedCache = class {
1301
1689
  constructor(context, hydrateFunction, maxCount = 2e3, ttl = Number.MAX_SAFE_INTEGER) {
1302
1690
  this.context = context;
1303
1691
  this.hydrateFunction = hydrateFunction;
1304
- this.cache = new LRUCache2({ max: maxCount, ttl });
1692
+ this.cache = new LRUCache({ max: maxCount, ttl });
1305
1693
  }
1306
1694
  async get(hash) {
1307
1695
  const existing = this.cache.get(hash);
@@ -1321,8 +1709,10 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
1321
1709
  moniker = SimpleBlockViewer.defaultMoniker;
1322
1710
  _store;
1323
1711
  finalizationViewer;
1324
- payloadCache = new LruCacheMap({ max: 1e4 });
1325
- signedHydratedBlockWithHashMetaCache = new LruCacheMap({ max: 2e3, ttl: 1e3 * 60 * 60 });
1712
+ payloadCache = new LruCacheMap2({ max: 1e4 });
1713
+ signedHydratedBlockWithHashMetaCache = new LruCacheMap2({ max: 2e3, ttl: 1e3 * 60 * 60 });
1714
+ _blockStepSemaphores = StepSizes6.map(() => new Semaphore(20));
1715
+ _blocksSummaryMap;
1326
1716
  _headPollHash;
1327
1717
  _headPollInProgress = false;
1328
1718
  _headPollTimer = null;
@@ -1330,6 +1720,10 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
1330
1720
  get finalizedArchivist() {
1331
1721
  return this.params.finalizedArchivist;
1332
1722
  }
1723
+ get blocksSummaryMap() {
1724
+ this._blocksSummaryMap ??= this.params.blocksSummaryMap ?? new LruCacheMap2({ max: 32 });
1725
+ return this._blocksSummaryMap;
1726
+ }
1333
1727
  get headPollIntervalMs() {
1334
1728
  return this.params.headPollIntervalMs;
1335
1729
  }
@@ -1348,11 +1742,12 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
1348
1742
  static async paramsHandler(params) {
1349
1743
  const headPollIntervalMs = params.headPollIntervalMs;
1350
1744
  if (headPollIntervalMs !== void 0) {
1351
- assertEx11(headPollIntervalMs >= MIN_HEAD_POLL_INTERVAL_MS, () => `headPollIntervalMs must be at least ${MIN_HEAD_POLL_INTERVAL_MS}ms`);
1745
+ assertEx15(headPollIntervalMs >= MIN_HEAD_POLL_INTERVAL_MS, () => `headPollIntervalMs must be at least ${MIN_HEAD_POLL_INTERVAL_MS}ms`);
1352
1746
  }
1353
1747
  return {
1354
1748
  ...await super.paramsHandler(params),
1355
- finalizedArchivist: assertEx11(params.finalizedArchivist, () => "finalizedArchivist is required"),
1749
+ blocksSummaryMap: params.blocksSummaryMap,
1750
+ finalizedArchivist: assertEx15(params.finalizedArchivist, () => "finalizedArchivist is required"),
1356
1751
  headPollIntervalMs
1357
1752
  };
1358
1753
  }
@@ -1373,7 +1768,7 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
1373
1768
  async blockByNumber(blockNumber) {
1374
1769
  return await this.spanAsync("blockByNumber", async () => {
1375
1770
  const chainContext = await this.getChainContextRead();
1376
- if (isUndefined3(chainContext.head)) {
1771
+ if (isUndefined4(chainContext.head)) {
1377
1772
  return null;
1378
1773
  }
1379
1774
  return await this.blockByNumberWithContext(chainContext, blockNumber);
@@ -1381,8 +1776,8 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
1381
1776
  }
1382
1777
  async blocksByHash(hash, limit = 50) {
1383
1778
  return await this.spanAsync("blocksByHash", async () => {
1384
- assertEx11(limit > 0, () => "limit must be greater than 0");
1385
- assertEx11(limit <= 100, () => "limit must be less than 100");
1779
+ assertEx15(limit > 0, () => "limit must be greater than 0");
1780
+ assertEx15(limit <= 100, () => "limit must be less than 100");
1386
1781
  const blocks = [];
1387
1782
  let current = await this.blockByHash(hash);
1388
1783
  while (current && blocks.length < limit) {
@@ -1396,10 +1791,10 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
1396
1791
  }
1397
1792
  async blocksByNumber(blockNumber, limit = 50) {
1398
1793
  return await this.spanAsync("blocksByNumber", async () => {
1399
- assertEx11(limit > 0, () => "limit must be greater than 0");
1400
- assertEx11(limit <= 100, () => "limit must be less than 100");
1794
+ assertEx15(limit > 0, () => "limit must be greater than 0");
1795
+ assertEx15(limit <= 100, () => "limit must be less than 100");
1401
1796
  const chainContext = await this.getChainContextRead();
1402
- if (isUndefined3(chainContext.head)) {
1797
+ if (isUndefined4(chainContext.head)) {
1403
1798
  return [];
1404
1799
  }
1405
1800
  const blocks = [];
@@ -1407,15 +1802,39 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
1407
1802
  while (current && blocks.length < limit) {
1408
1803
  blocks.push(current);
1409
1804
  if (current[0].block === 0) break;
1410
- const previousNumber = asXL1BlockNumber3(current[0].block - 1, true);
1805
+ const previousNumber = asXL1BlockNumber9(current[0].block - 1, true);
1411
1806
  current = await this.blockByNumberWithContext(chainContext, previousNumber);
1412
1807
  }
1413
1808
  return blocks.map((b) => asSignedHydratedBlockWithHashMeta(b, true));
1414
1809
  }, this.context);
1415
1810
  }
1811
+ async blocksByStep(stepLevel, stepIndex) {
1812
+ return await this.spanAsync("blocksByStep", async () => {
1813
+ assertEx15(Number.isInteger(stepIndex) && stepIndex >= 0, () => "stepIndex must be a non-negative integer");
1814
+ const size = stepSize2(stepLevel);
1815
+ assertEx15(
1816
+ stepLevel <= blocksMaxStep,
1817
+ () => `blocksByStep does not support step levels above ${blocksMaxStep} (requested ${stepLevel})`
1818
+ );
1819
+ const chainContext = await this.getChainContextRead();
1820
+ if (isUndefined4(chainContext.head)) {
1821
+ return [];
1822
+ }
1823
+ const start = stepIndex * size;
1824
+ const end = Math.min(start + size - 1, chainContext.head.block);
1825
+ if (end < start) {
1826
+ return [];
1827
+ }
1828
+ const range = asXL1BlockRange4([start, end], { name: "blocksByStep" });
1829
+ const frames = deepCalculateFramesFromRange(range, blocksMaxStep);
1830
+ const summaries = await Promise.all(frames.map((frame) => blocksStepSummaryFromRange(this.context, this._blockStepSemaphores, this, this.blocksSummaryMap, frame)));
1831
+ const blocks = summaries.flatMap((summary) => summary.blocks);
1832
+ return blocks.map((b) => asSignedHydratedBlockWithHashMeta(b, true)).toReversed();
1833
+ }, this.context);
1834
+ }
1416
1835
  async chainId(blockNumber = "latest") {
1417
1836
  return await this.spanAsync("chainId", async () => {
1418
- return blockNumber === "latest" ? (await this.finalizationViewer.headBlock()).chain : assertEx11(await this.blockByNumber(blockNumber), () => `Block not found [${blockNumber}]`)[0].chain;
1837
+ return blockNumber === "latest" ? (await this.finalizationViewer.headBlock()).chain : assertEx15(await this.blockByNumber(blockNumber), () => `Block not found [${blockNumber}]`)[0].chain;
1419
1838
  }, this.context);
1420
1839
  }
1421
1840
  async createHandler() {
@@ -1443,9 +1862,9 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
1443
1862
  remainingHashes = remainingHashes.filter((h) => !cachedHashes.has(h));
1444
1863
  const finalizedPayloads = remainingHashes.length > 0 ? await this.finalizedArchivist.get(remainingHashes) : [];
1445
1864
  const resultPayloads = [...cachedPayloads, ...finalizedPayloads.filter(exists)];
1446
- resultPayloads.map((payload) => {
1865
+ for (const payload of resultPayloads) {
1447
1866
  this.payloadCache.set(payload._hash, payload);
1448
- });
1867
+ }
1449
1868
  return resultPayloads;
1450
1869
  }
1451
1870
  async rate(range, timeUnit) {
@@ -1527,7 +1946,7 @@ SimpleBlockViewer = __decorateClass([
1527
1946
  ], SimpleBlockViewer);
1528
1947
 
1529
1948
  // src/simple/chainContractViewer/SimpleChainContractViewer.ts
1530
- import { assertEx as assertEx12 } from "@xylabs/sdk-js";
1949
+ import { assertEx as assertEx16 } from "@xylabs/sdk-js";
1531
1950
  import { ChainContractViewerMoniker, FinalizationViewerMoniker as FinalizationViewerMoniker2 } from "@xyo-network/xl1-protocol-lib";
1532
1951
  var SimpleChainContractViewer = class extends AbstractCreatableProvider {
1533
1952
  moniker = SimpleChainContractViewer.defaultMoniker;
@@ -1544,7 +1963,7 @@ var SimpleChainContractViewer = class extends AbstractCreatableProvider {
1544
1963
  let contractViewer = this;
1545
1964
  let forkedAtBlockNumber = await contractViewer.forkedAtBlockNumber();
1546
1965
  while (forkedAtBlockNumber !== null && blockNumber <= forkedAtBlockNumber) {
1547
- contractViewer = assertEx12(await contractViewer.forkedChainContractViewer());
1966
+ contractViewer = assertEx16(await contractViewer.forkedChainContractViewer());
1548
1967
  forkedAtBlockNumber = await contractViewer.forkedAtBlockNumber();
1549
1968
  chainId = await contractViewer.chainId();
1550
1969
  }
@@ -1585,7 +2004,7 @@ SimpleChainContractViewer = __decorateClass([
1585
2004
  ], SimpleChainContractViewer);
1586
2005
 
1587
2006
  // src/simple/finalization/SimpleFinalizationViewer.ts
1588
- import { assertEx as assertEx13 } from "@xylabs/sdk-js";
2007
+ import { assertEx as assertEx17 } from "@xylabs/sdk-js";
1589
2008
  import {
1590
2009
  asSignedHydratedBlockWithStorageMeta as asSignedHydratedBlockWithStorageMeta2,
1591
2010
  ChainContractViewerMoniker as ChainContractViewerMoniker2,
@@ -1608,370 +2027,68 @@ var SimpleFinalizationViewer = class extends AbstractCreatableProvider {
1608
2027
  }, 200);
1609
2028
  return this._signedHydratedBlockCache;
1610
2029
  }
1611
- get store() {
1612
- return this._store;
1613
- }
1614
- static async paramsHandler(params) {
1615
- return {
1616
- ...await super.paramsHandler(params),
1617
- finalizedArchivist: assertEx13(params.finalizedArchivist, () => "finalizedArchivist is required")
1618
- };
1619
- }
1620
- chainId() {
1621
- return this._chainId;
1622
- }
1623
- async createHandler() {
1624
- await super.createHandler();
1625
- this._chainId = assertEx13(this.config.chain.id ?? (await findMostRecentBlock(this.params.finalizedArchivist))?.chain, () => "chain.id is required if empty archivist");
1626
- this._store = { chainMap: this.params.finalizedArchivist };
1627
- }
1628
- async head() {
1629
- return await this.spanAsync("head", async () => {
1630
- const currentHead = assertEx13(await this.getCurrentHead(), () => "Could not find most recent block [currentBlock]");
1631
- const cache = this.hydratedBlockCache;
1632
- const block = await cache.get(currentHead._hash);
1633
- if (!block) {
1634
- this.logger?.error(`Could not find current block with hash ${currentHead._hash}`);
1635
- }
1636
- return assertEx13(block, () => "Could not find current block");
1637
- }, this.context);
1638
- }
1639
- async headBlock() {
1640
- return (await this.head())[0];
1641
- }
1642
- async headHash() {
1643
- return (await this.headBlock())._hash;
1644
- }
1645
- async headNumber() {
1646
- return (await this.headBlock()).block;
1647
- }
1648
- getBlockContextRead() {
1649
- return {
1650
- ...this.context,
1651
- chainMap: this.store.chainMap
1652
- };
1653
- }
1654
- async getChainContextRead() {
1655
- return {
1656
- ...this.getBlockContextRead(),
1657
- head: (await this.head())[0]
1658
- };
1659
- }
1660
- async getCurrentHead() {
1661
- const chainArchivist = this.finalizedArchivist;
1662
- const result = assertEx13(await findMostRecentBlock(chainArchivist), () => "Could not find most recent block [getCurrentHead]");
1663
- assertEx13(result?.chain === this._chainId, () => "Chain ID does not match head block chain ID");
1664
- return result;
1665
- }
1666
- };
1667
- __publicField(SimpleFinalizationViewer, "defaultMoniker", FinalizationViewerMoniker3);
1668
- __publicField(SimpleFinalizationViewer, "dependencies", [ChainContractViewerMoniker2]);
1669
- __publicField(SimpleFinalizationViewer, "monikers", [FinalizationViewerMoniker3]);
1670
- SimpleFinalizationViewer = __decorateClass([
1671
- creatableProvider()
1672
- ], SimpleFinalizationViewer);
1673
-
1674
- // src/test/buildRandomChain.ts
1675
- import { asAddress as asAddress2, assertEx as assertEx16 } from "@xylabs/sdk-js";
1676
- import {
1677
- Account as Account3,
1678
- asSchema as asSchema2,
1679
- IdSchema as IdSchema2,
1680
- MemoryArchivist,
1681
- PayloadBuilder as PayloadBuilder8
1682
- } from "@xyo-network/sdk-js";
1683
- import {
1684
- asXL1BlockNumber as asXL1BlockNumber7
1685
- } from "@xyo-network/xl1-protocol-lib";
1686
-
1687
- // src/test/buildNextBlock.ts
1688
- import {
1689
- AttoXL1 as AttoXL12,
1690
- XYO_STEP_REWARD_ADDRESS as XYO_STEP_REWARD_ADDRESS2
1691
- } from "@xyo-network/xl1-protocol-lib";
1692
-
1693
- // src/test/buildBlock.ts
1694
- import { assertEx as assertEx14, isDefined as isDefined8 } from "@xylabs/sdk-js";
1695
- import {
1696
- asAnyPayload as asAnyPayload3,
1697
- BoundWitnessBuilder as BoundWitnessBuilder2,
1698
- PayloadBuilder as PayloadBuilder4
1699
- } from "@xyo-network/sdk-js";
1700
- import {
1701
- asXL1BlockNumber as asXL1BlockNumber4,
1702
- AttoXL1,
1703
- isBlockBoundWitness,
1704
- rewardAddressFromStepIdentity,
1705
- StepRewardFractions,
1706
- StepSizes as StepSizes3,
1707
- XL1_PROTOCOL_VERSION,
1708
- XYO_STEP_REWARD_ADDRESS,
1709
- XYO_ZERO_ADDRESS
1710
- } from "@xyo-network/xl1-protocol-lib";
1711
-
1712
- // src/test/BuildBlockOptions.ts
1713
- import {
1714
- isAddress,
1715
- isArray,
1716
- isHash as isHash2,
1717
- isNumber,
1718
- isObject as isObject2
1719
- } from "@xylabs/sdk-js";
1720
- var isBaseBuildBlockOptions = (value) => {
1721
- if (!isObject2(value)) {
1722
- return false;
1723
- }
1724
- const typedValue = value;
1725
- if (!isArray(typedValue.blockPayloads) || !isAddress(typedValue.chainId) || !isArray(typedValue.signers) || !isArray(typedValue.txs)) {
1726
- return false;
1727
- }
1728
- return true;
1729
- };
1730
- var isBuildGenesisBlockOptions = (value) => {
1731
- if (!isBaseBuildBlockOptions(value)) {
1732
- return false;
1733
- }
1734
- const typedValue = value;
1735
- if (typedValue.previousBlockHash !== null) {
1736
- return false;
2030
+ get store() {
2031
+ return this._store;
1737
2032
  }
1738
- if (typedValue.previousBlockNumber !== void 0) {
1739
- return false;
2033
+ static async paramsHandler(params) {
2034
+ return {
2035
+ ...await super.paramsHandler(params),
2036
+ finalizedArchivist: assertEx17(params.finalizedArchivist, () => "finalizedArchivist is required")
2037
+ };
1740
2038
  }
1741
- return true;
1742
- };
1743
- var isBuildNextBlockOptions = (value) => {
1744
- if (!isBaseBuildBlockOptions(value)) {
1745
- return false;
2039
+ chainId() {
2040
+ return this._chainId;
1746
2041
  }
1747
- const typedValue = value;
1748
- if (!isHash2(typedValue.previousBlockHash)) {
1749
- return false;
2042
+ async createHandler() {
2043
+ await super.createHandler();
2044
+ this._chainId = assertEx17(this.config.chain.id ?? (await findMostRecentBlock(this.params.finalizedArchivist))?.chain, () => "chain.id is required if empty archivist");
2045
+ this._store = { chainMap: this.params.finalizedArchivist };
1750
2046
  }
1751
- if (!isNumber(typedValue.previousBlockNumber)) {
1752
- return false;
2047
+ async head() {
2048
+ return await this.spanAsync("head", async () => {
2049
+ const currentHead = assertEx17(await this.getCurrentHead(), () => "Could not find most recent block [currentBlock]");
2050
+ const cache = this.hydratedBlockCache;
2051
+ const block = await cache.get(currentHead._hash);
2052
+ if (!block) {
2053
+ this.logger?.error(`Could not find current block with hash ${currentHead._hash}`);
2054
+ }
2055
+ return assertEx17(block, () => "Could not find current block");
2056
+ }, this.context);
1753
2057
  }
1754
- if (!isArray(typedValue.previousStepHashes)) {
1755
- return false;
2058
+ async headBlock() {
2059
+ return (await this.head())[0];
1756
2060
  }
1757
- return true;
1758
- };
1759
-
1760
- // src/test/buildBlock.ts
1761
- function calculateCompletedStepReward(step, balance) {
1762
- return AttoXL1(StepRewardFractions[step][0] * balance / StepRewardFractions[step][1]);
1763
- }
1764
- async function buildBlock(options) {
1765
- const previousBlockNumber = isBuildGenesisBlockOptions(options) ? -1 : options.previousBlockNumber;
1766
- const blockNumber = asXL1BlockNumber4(previousBlockNumber + 1, true);
1767
- const inStepHashes = isBuildNextBlockOptions(options) ? options.previousStepHashes : [];
1768
- const previousBlockHash = isBuildNextBlockOptions(options) ? options.previousBlockHash : void 0;
1769
- const stepRewardPoolBalance = isBuildNextBlockOptions(options) ? options.stepRewardPoolBalance : AttoXL1(0n);
1770
- const {
1771
- chainId,
1772
- txs,
1773
- chainStepRewardAddress = XYO_STEP_REWARD_ADDRESS,
1774
- blockPayloads,
1775
- protocol = XL1_PROTOCOL_VERSION,
1776
- signers
1777
- } = options;
1778
- const step_hashes = [];
1779
- for (const [tx] of txs) {
1780
- if (tx.nbf > blockNumber) {
1781
- throw new Error(`Transaction ${await PayloadBuilder4.hash(tx)} not valid for block ${blockNumber} - NBF is ${tx.nbf}`);
1782
- }
1783
- if (tx.exp < blockNumber) {
1784
- throw new Error(`Transaction ${await PayloadBuilder4.hash(tx)} not valid for block ${blockNumber} - EXP is ${tx.exp}`);
1785
- }
2061
+ async headHash() {
2062
+ return (await this.headBlock())._hash;
1786
2063
  }
1787
- const completedStepRewardTransfers = [];
1788
- for (const [i, step] of StepSizes3.entries()) {
1789
- if (blockNumber < step) {
1790
- break;
1791
- }
1792
- if (blockNumber % step === 0) {
1793
- if (StepRewardFractions[i][0] > 0 && chainStepRewardAddress !== XYO_ZERO_ADDRESS) {
1794
- const completedStepRewardHolderAddress = rewardAddressFromStepIdentity({ block: blockNumber, step });
1795
- const completedStepReward = calculateCompletedStepReward(i, stepRewardPoolBalance);
1796
- completedStepRewardTransfers.push(createTransferPayload(chainStepRewardAddress, { [completedStepRewardHolderAddress]: completedStepReward }));
1797
- }
1798
- step_hashes.push(assertEx14(previousBlockHash, () => `Previous block hash is required for step ${step} at block ${blockNumber}`));
1799
- } else {
1800
- if (isDefined8(inStepHashes.at(i))) {
1801
- step_hashes.push(inStepHashes[i]);
1802
- }
1803
- }
2064
+ async headNumber() {
2065
+ return (await this.headBlock()).block;
1804
2066
  }
1805
- const previous = previousBlockHash ?? null;
1806
- const block = blockNumber;
1807
- const txElevatedPayloads = await validateTransactionsOpcodes(txs);
1808
- const payloads = [
1809
- ...txs.map(([tx]) => tx),
1810
- ...blockPayloads,
1811
- ...txElevatedPayloads,
1812
- ...completedStepRewardTransfers
1813
- ];
1814
- const [bw, txPayloads] = await new BoundWitnessBuilder2().fields({
1815
- block,
1816
- chain: chainId,
1817
- previous,
1818
- step_hashes,
1819
- protocol
1820
- }).meta({ $epoch: Date.now(), $signatures: [] }).signers(signers).payloads(await PayloadBuilder4.addStorageMeta(payloads)).build();
1821
- assertEx14(isBlockBoundWitness(bw), () => "Build of BlockBoundWitness failed");
1822
- return [await PayloadBuilder4.addStorageMeta(bw), txPayloads.map((p) => asAnyPayload3(p, true))];
1823
- }
1824
-
1825
- // src/test/buildNextBlock.ts
1826
- async function buildNextBlock(previousBlock, txs, blockPayloads, signers, chainStepRewardAddress = XYO_STEP_REWARD_ADDRESS2, stepRewardPoolBalance = AttoXL12(0n), protocol, chainId) {
1827
- return await buildBlock({
1828
- chainId: chainId ?? previousBlock.chain,
1829
- previousBlockNumber: previousBlock.block,
1830
- previousStepHashes: previousBlock.step_hashes ?? [],
1831
- previousBlockHash: previousBlock._hash,
1832
- txs,
1833
- blockPayloads,
1834
- signers,
1835
- protocol,
1836
- chainStepRewardAddress,
1837
- stepRewardPoolBalance
1838
- });
1839
- }
1840
-
1841
- // src/test/buildRandomGenesisBlock.ts
1842
- import { asAddress, assertEx as assertEx15 } from "@xylabs/sdk-js";
1843
- import {
1844
- Account as Account2,
1845
- asAnyPayload as asAnyPayload4,
1846
- asSchema,
1847
- IdSchema,
1848
- PayloadBuilder as PayloadBuilder5
1849
- } from "@xyo-network/sdk-js";
1850
- import {
1851
- asXL1BlockNumber as asXL1BlockNumber5
1852
- } from "@xyo-network/xl1-protocol-lib";
1853
-
1854
- // src/test/buildGenesisBlock.ts
1855
- import { XYO_ZERO_ADDRESS as XYO_ZERO_ADDRESS2 } from "@xyo-network/xl1-protocol-lib";
1856
- async function buildGenesisBlock(chainId, txs, blockPayloads, signers, chainStepRewardAddress = XYO_ZERO_ADDRESS2, protocol) {
1857
- return await buildBlock({
1858
- previousBlockHash: null,
1859
- chainId,
1860
- txs,
1861
- blockPayloads,
1862
- signers,
1863
- chainStepRewardAddress,
1864
- protocol
1865
- });
1866
- }
1867
-
1868
- // src/test/buildRandomGenesisBlock.ts
1869
- var TestChainId = assertEx15(asAddress("c5fe2e6F6841Cbab12d8C0618Be2DF8C6156cC44"));
1870
-
1871
- // src/test/createGenesisBlock.ts
1872
- import { PayloadBuilder as PayloadBuilder7 } from "@xyo-network/sdk-js";
1873
- import {
1874
- BlockBoundWitnessSchemaPayload,
1875
- BlockBoundWitnessWithStorageMetaSchemaPayload,
1876
- ChainStakeIntentPayloadJsonSchemaPayload,
1877
- HashPayloadJsonSchemaPayload,
1878
- TransactionBoundWitnessSchemaPayload,
1879
- TransactionBoundWitnessWithStorageMetaSchemaPayload,
1880
- TransferPayloadJsonSchemaPayload
1881
- } from "@xyo-network/xl1-schema";
1882
-
1883
- // src/test/createProducerChainStakeIntentTransaction.ts
1884
- import { PayloadBuilder as PayloadBuilder6 } from "@xyo-network/sdk-js";
1885
- import {
1886
- asXL1BlockNumber as asXL1BlockNumber6,
1887
- ChainStakeIntentSchema,
1888
- defaultTransactionFees as defaultTransactionFees2
1889
- } from "@xyo-network/xl1-protocol-lib";
1890
- async function createProducerChainStakeIntent(from, exp, nbf = 0) {
1891
- return await PayloadBuilder6.addHashMeta(new PayloadBuilder6({ schema: ChainStakeIntentSchema }).fields({
1892
- from,
1893
- exp,
1894
- nbf,
1895
- intent: "producer"
1896
- }).build());
1897
- }
1898
-
1899
- // src/test/createGenesisBlock.ts
1900
- var createGenesisBlock = async (initialBlockProducer, nextContractAddress, genesisBlockRewardAmount, genesisBlockRewardAddress) => {
1901
- const blockPayloads = await PayloadBuilder7.addHashMeta([
1902
- TransferPayloadJsonSchemaPayload,
1903
- BlockBoundWitnessSchemaPayload,
1904
- BlockBoundWitnessWithStorageMetaSchemaPayload,
1905
- TransactionBoundWitnessSchemaPayload,
1906
- TransactionBoundWitnessWithStorageMetaSchemaPayload,
1907
- ChainStakeIntentPayloadJsonSchemaPayload,
1908
- HashPayloadJsonSchemaPayload
1909
- ]);
1910
- const intentPayload = await createProducerChainStakeIntent(initialBlockProducer.address, 1, 0);
1911
- blockPayloads.push(intentPayload);
1912
- if (genesisBlockRewardAmount > 0n) {
1913
- blockPayloads.push(await PayloadBuilder7.addHashMeta(createTransferPayload(
1914
- nextContractAddress,
1915
- { [genesisBlockRewardAddress]: genesisBlockRewardAmount }
1916
- )));
2067
+ getBlockContextRead() {
2068
+ return {
2069
+ ...this.context,
2070
+ chainMap: this.store.chainMap
2071
+ };
1917
2072
  }
1918
- return await buildGenesisBlock(nextContractAddress, [], blockPayloads, [initialBlockProducer]);
1919
- };
1920
-
1921
- // src/test/buildRandomChain.ts
1922
- var TestGenesisBlockRewardAddress = assertEx16(asAddress2("fa7f0bb865a4bfff3d5e2c726d3e063297014da9"));
1923
- var buildRandomChain = async (blockProducer, count = 10, previousBlock, chainId, transactionAccount, receiverAddresses) => {
1924
- const chainIdToUse = chainId ?? TestChainId;
1925
- const blocks = [];
1926
- let remaining = count;
1927
- let lastBlock = previousBlock;
1928
- const transactionAccountToUse = transactionAccount ?? await Account3.random();
1929
- if (!lastBlock) {
1930
- const block = await createGenesisBlock(
1931
- blockProducer,
1932
- chainIdToUse,
1933
- 1000000000n * 10n ** 18n,
1934
- transactionAccountToUse.address
1935
- );
1936
- blocks.push(block);
1937
- remaining = remaining - 1;
1938
- lastBlock = block;
2073
+ async getChainContextRead() {
2074
+ return {
2075
+ ...this.getBlockContextRead(),
2076
+ head: (await this.head())[0]
2077
+ };
1939
2078
  }
1940
- const resolvedReceiverAddresses = receiverAddresses ?? [(await Account3.random()).address];
1941
- let saltCounter = 0;
1942
- while (remaining > 0) {
1943
- saltCounter += 1;
1944
- const payloads = [new PayloadBuilder8({ schema: IdSchema2 }).fields({ salt: `${Date.now()}-${saltCounter}` }).build()];
1945
- saltCounter += 1;
1946
- const additionalPrivatePayloads = remaining % 2 === 0 ? [new PayloadBuilder8({ schema: asSchema2("network.xyo.private", true) }).fields({ salt: `${Date.now()}-${saltCounter}` }).build()] : [];
1947
- const txs = [];
1948
- for (const receiverAddress of resolvedReceiverAddresses) {
1949
- txs.push(await buildRandomTransaction(
1950
- chainIdToUse,
1951
- [...payloads, ...additionalPrivatePayloads],
1952
- transactionAccountToUse,
1953
- asXL1BlockNumber7(Math.max(count - remaining - 1e3, 0), true),
1954
- asXL1BlockNumber7(count - remaining + 1e3, true),
1955
- [asSchema2("network.xyo.private", true)],
1956
- receiverAddress
1957
- ));
1958
- }
1959
- const previousBlock2 = assertEx16(lastBlock?.[0], () => new Error("No last block"));
1960
- const block = await buildNextBlock(previousBlock2, txs, [], [blockProducer], transactionAccountToUse.address);
1961
- blocks.push(block);
1962
- remaining = remaining - 1;
1963
- lastBlock = block;
2079
+ async getCurrentHead() {
2080
+ const chainArchivist = this.finalizedArchivist;
2081
+ const result = assertEx17(await findMostRecentBlock(chainArchivist), () => "Could not find most recent block [getCurrentHead]");
2082
+ assertEx17(result?.chain === this._chainId, () => "Chain ID does not match head block chain ID");
2083
+ return result;
1964
2084
  }
1965
- return blocks;
1966
2085
  };
1967
- async function buildRandomChainArchivist(count = 20) {
1968
- const producerAccount = await Account3.random();
1969
- const blocks = await buildRandomChain(producerAccount, count);
1970
- const archivist = await MemoryArchivist.create();
1971
- const payloads = flattenHydratedBlocks(blocks);
1972
- await archivist.insert(payloads);
1973
- return archivist;
1974
- }
2086
+ __publicField(SimpleFinalizationViewer, "defaultMoniker", FinalizationViewerMoniker3);
2087
+ __publicField(SimpleFinalizationViewer, "dependencies", [ChainContractViewerMoniker2]);
2088
+ __publicField(SimpleFinalizationViewer, "monikers", [FinalizationViewerMoniker3]);
2089
+ SimpleFinalizationViewer = __decorateClass([
2090
+ creatableProvider()
2091
+ ], SimpleFinalizationViewer);
1975
2092
 
1976
2093
  // src/test/getSimpleBlockViewerLocator.ts
1977
2094
  async function getTestSimpleBlockViewerLocator({
@@ -2000,6 +2117,9 @@ function getTestProviderContext2(config) {
2000
2117
  return getTestProviderContext(config);
2001
2118
  }
2002
2119
  export {
2120
+ TestGenesisBlockRewardAddress,
2121
+ buildRandomChain,
2122
+ buildRandomChainArchivist,
2003
2123
  buildRandomTransaction,
2004
2124
  getTestProviderContext2 as getTestProviderContext,
2005
2125
  getTestSimpleBlockViewerLocator