@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.
- package/README.md +3 -6
- package/dist/neutral/ChainContextHelpers.d.ts.map +1 -1
- package/dist/neutral/CreatableProvider/AbstractCreatableProvider.d.ts +8 -1
- package/dist/neutral/CreatableProvider/AbstractCreatableProvider.d.ts.map +1 -1
- package/dist/neutral/config/Actor.d.ts +48 -6
- package/dist/neutral/config/Actor.d.ts.map +1 -1
- package/dist/neutral/config/Actors.d.ts +8 -1
- package/dist/neutral/config/Actors.d.ts.map +1 -1
- package/dist/neutral/config/Base.d.ts +8 -1
- package/dist/neutral/config/Base.d.ts.map +1 -1
- package/dist/neutral/config/Config.d.ts +32 -4
- package/dist/neutral/config/Config.d.ts.map +1 -1
- package/dist/neutral/config/HostActor.d.ts +48 -6
- package/dist/neutral/config/HostActor.d.ts.map +1 -1
- package/dist/neutral/config/Log.d.ts +1 -1
- package/dist/neutral/config/index.d.ts +1 -1
- package/dist/neutral/config/index.d.ts.map +1 -1
- package/dist/neutral/config/storage/Storage.d.ts +7 -0
- package/dist/neutral/config/storage/Storage.d.ts.map +1 -1
- package/dist/neutral/config/storage/driver/R2.d.ts +25 -0
- package/dist/neutral/config/storage/driver/R2.d.ts.map +1 -0
- package/dist/neutral/config/storage/driver/index.d.ts +1 -0
- package/dist/neutral/config/storage/driver/index.d.ts.map +1 -1
- package/dist/neutral/context/Actor.d.ts +48 -6
- package/dist/neutral/context/Actor.d.ts.map +1 -1
- package/dist/neutral/context/HostActor.d.ts +48 -6
- package/dist/neutral/context/HostActor.d.ts.map +1 -1
- package/dist/neutral/getFileConfig.d.ts +16 -2
- package/dist/neutral/getFileConfig.d.ts.map +1 -1
- package/dist/neutral/getFileConfig.mjs +76 -44
- package/dist/neutral/getFileConfig.mjs.map +4 -4
- package/dist/neutral/index.d.ts +2 -1
- package/dist/neutral/index.d.ts.map +1 -1
- package/dist/neutral/index.mjs +820 -358
- package/dist/neutral/index.mjs.map +4 -4
- package/dist/neutral/model/CreatableProviderContext.zod.d.ts +48 -6
- package/dist/neutral/model/CreatableProviderContext.zod.d.ts.map +1 -1
- package/dist/neutral/simple/block/SimpleBlockViewer.d.ts +13 -2
- package/dist/neutral/simple/block/SimpleBlockViewer.d.ts.map +1 -1
- package/dist/neutral/simple/mempool/SimpleMempoolRunner.d.ts.map +1 -1
- package/dist/neutral/simple/windowedBlock/SimpleWindowedBlockViewer.d.ts +33 -0
- package/dist/neutral/simple/windowedBlock/SimpleWindowedBlockViewer.d.ts.map +1 -1
- package/dist/neutral/summary/model/BlocksStepSummary.d.ts +26 -0
- package/dist/neutral/summary/model/BlocksStepSummary.d.ts.map +1 -0
- package/dist/neutral/summary/model/index.d.ts +1 -0
- package/dist/neutral/summary/model/index.d.ts.map +1 -1
- package/dist/neutral/summary/primitives/blocks/blocksMaxStep.d.ts +13 -0
- package/dist/neutral/summary/primitives/blocks/blocksMaxStep.d.ts.map +1 -0
- package/dist/neutral/summary/primitives/blocks/blocksStepSummaryFromRange.d.ts +13 -0
- package/dist/neutral/summary/primitives/blocks/blocksStepSummaryFromRange.d.ts.map +1 -0
- package/dist/neutral/summary/primitives/blocks/index.d.ts +3 -0
- package/dist/neutral/summary/primitives/blocks/index.d.ts.map +1 -0
- package/dist/neutral/summary/primitives/index.d.ts +1 -0
- package/dist/neutral/summary/primitives/index.d.ts.map +1 -1
- package/dist/neutral/test/index.d.ts +1 -0
- package/dist/neutral/test/index.d.ts.map +1 -1
- package/dist/neutral/test/index.mjs +1164 -1044
- package/dist/neutral/test/index.mjs.map +4 -4
- package/package.json +19 -20
- package/dist/neutral/driver/cache/LruCacheMap.d.ts +0 -15
- package/dist/neutral/driver/cache/LruCacheMap.d.ts.map +0 -1
- package/dist/neutral/driver/cache/index.d.ts +0 -2
- package/dist/neutral/driver/cache/index.d.ts.map +0 -1
- package/dist/neutral/driver/index.d.ts +0 -3
- package/dist/neutral/driver/index.d.ts.map +0 -1
- package/dist/neutral/driver/memory/MemoryMap.d.ts +0 -14
- package/dist/neutral/driver/memory/MemoryMap.d.ts.map +0 -1
- package/dist/neutral/driver/memory/index.d.ts +0 -2
- 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/
|
|
15
|
-
import {
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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 {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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/
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
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/
|
|
85
|
-
|
|
40
|
+
// src/block/hydrate/flattenHydratedBlocks.ts
|
|
41
|
+
var flattenHydratedBlocks = (hydratedBlocks) => hydratedBlocks.flatMap((blk) => flattenHydratedBlock(blk));
|
|
86
42
|
|
|
87
|
-
// src/
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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/
|
|
95
|
-
import {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
130
|
-
|
|
99
|
+
if (isUndefined(context.caches[name])) {
|
|
100
|
+
context.caches[name] = create?.() ?? new MemoryMap();
|
|
131
101
|
}
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
209
|
+
remaining = newRemaining;
|
|
168
210
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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/
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
-
|
|
194
|
-
|
|
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
|
-
|
|
197
|
-
|
|
315
|
+
const typedValue = value;
|
|
316
|
+
if (!isArray(typedValue.blockPayloads) || !isAddress(typedValue.chainId) || !isArray(typedValue.signers) || !isArray(typedValue.txs)) {
|
|
317
|
+
return false;
|
|
198
318
|
}
|
|
199
|
-
|
|
200
|
-
|
|
319
|
+
return true;
|
|
320
|
+
};
|
|
321
|
+
var isBuildGenesisBlockOptions = (value) => {
|
|
322
|
+
if (!isBaseBuildBlockOptions(value)) {
|
|
323
|
+
return false;
|
|
201
324
|
}
|
|
202
|
-
|
|
203
|
-
|
|
325
|
+
const typedValue = value;
|
|
326
|
+
if (typedValue.previousBlockHash !== null) {
|
|
327
|
+
return false;
|
|
204
328
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
return factory;
|
|
329
|
+
if (typedValue.previousBlockNumber !== void 0) {
|
|
330
|
+
return false;
|
|
208
331
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
return
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
-
|
|
235
|
-
return
|
|
342
|
+
if (!isNumber(typedValue.previousBlockNumber)) {
|
|
343
|
+
return false;
|
|
236
344
|
}
|
|
237
|
-
|
|
238
|
-
return
|
|
345
|
+
if (!isArray(typedValue.previousStepHashes)) {
|
|
346
|
+
return false;
|
|
239
347
|
}
|
|
348
|
+
return true;
|
|
240
349
|
};
|
|
241
350
|
|
|
242
|
-
// src/
|
|
243
|
-
function
|
|
244
|
-
return (
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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/
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
993
|
+
import { globalRegistry as globalRegistry13, z as z17 } from "zod/mini";
|
|
454
994
|
|
|
455
995
|
// src/config/Base.ts
|
|
456
|
-
import { z as
|
|
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/
|
|
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
|
|
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
|
-
|
|
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
|
|
670
|
-
var MetricsScrapeConfigZod =
|
|
671
|
-
path:
|
|
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:
|
|
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 =
|
|
684
|
-
var OpenTelemetryConfigZod =
|
|
1255
|
+
var MetricsConfigZod = z14.object({ scrape: MetricsScrapeConfigZod }).describe("Metrics configuration options");
|
|
1256
|
+
var OpenTelemetryConfigZod = z14.object({
|
|
685
1257
|
// OpenTelemetry options
|
|
686
|
-
otlpEndpoint:
|
|
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 =
|
|
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
|
|
1273
|
+
import { globalRegistry as globalRegistry12, z as z15 } from "zod";
|
|
702
1274
|
|
|
703
1275
|
// src/primitives/block/rate/blockRate.ts
|
|
704
|
-
import { isDefined as
|
|
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
|
|
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 =
|
|
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 =
|
|
766
|
-
const returnedTimeDifference =
|
|
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:
|
|
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/
|
|
1370
|
+
// src/primitives/block/rate/stepRate.ts
|
|
1371
|
+
import { assertEx as assertEx11 } from "@xylabs/sdk-js";
|
|
1113
1372
|
import {
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
} from "@
|
|
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
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
1209
|
-
allowedRewardRedeemers:
|
|
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:
|
|
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:
|
|
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:
|
|
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 =
|
|
1235
|
-
chain:
|
|
1236
|
-
dataLake:
|
|
1237
|
-
evm:
|
|
1238
|
-
log:
|
|
1239
|
-
providers:
|
|
1240
|
-
remote:
|
|
1241
|
-
storage:
|
|
1242
|
-
telemetry:
|
|
1243
|
-
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 =
|
|
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 =
|
|
1252
|
-
name:
|
|
1253
|
-
accountPath:
|
|
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
|
|
1265
|
-
var ActorsConfigZod =
|
|
1266
|
-
|
|
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
|
|
1272
|
-
var ConfigZod =
|
|
1575
|
+
import { globalRegistry as globalRegistry14, z as z19 } from "zod/mini";
|
|
1576
|
+
var ConfigZod = z19.extend(BaseConfigZod, {
|
|
1273
1577
|
actors: ActorsConfigZod,
|
|
1274
|
-
healthCheckPort:
|
|
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(
|
|
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
|
|
1666
|
+
assertEx as assertEx15,
|
|
1284
1667
|
exists,
|
|
1285
|
-
isUndefined as
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1325
|
-
signedHydratedBlockWithHashMetaCache = new
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
1385
|
-
|
|
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
|
-
|
|
1400
|
-
|
|
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 (
|
|
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 =
|
|
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 :
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
1739
|
-
return
|
|
2033
|
+
static async paramsHandler(params) {
|
|
2034
|
+
return {
|
|
2035
|
+
...await super.paramsHandler(params),
|
|
2036
|
+
finalizedArchivist: assertEx17(params.finalizedArchivist, () => "finalizedArchivist is required")
|
|
2037
|
+
};
|
|
1740
2038
|
}
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
var isBuildNextBlockOptions = (value) => {
|
|
1744
|
-
if (!isBaseBuildBlockOptions(value)) {
|
|
1745
|
-
return false;
|
|
2039
|
+
chainId() {
|
|
2040
|
+
return this._chainId;
|
|
1746
2041
|
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
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
|
-
|
|
1752
|
-
return
|
|
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
|
-
|
|
1755
|
-
return
|
|
2058
|
+
async headBlock() {
|
|
2059
|
+
return (await this.head())[0];
|
|
1756
2060
|
}
|
|
1757
|
-
|
|
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
|
-
|
|
1788
|
-
|
|
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
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
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
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
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
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
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
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
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
|