@xyo-network/service-kit-xl1 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -0
- package/dist/browser/createFleetAuthority.d.ts +97 -0
- package/dist/browser/createFleetAuthority.d.ts.map +1 -0
- package/dist/browser/fleetControl.d.ts +16 -0
- package/dist/browser/fleetControl.d.ts.map +1 -0
- package/dist/browser/fleetForeign.d.ts +5 -0
- package/dist/browser/fleetForeign.d.ts.map +1 -0
- package/dist/browser/fleetHistory.d.ts +37 -0
- package/dist/browser/fleetHistory.d.ts.map +1 -0
- package/dist/browser/fleetHistoryCache.d.ts +22 -0
- package/dist/browser/fleetHistoryCache.d.ts.map +1 -0
- package/dist/browser/fleetMeter.d.ts +26 -0
- package/dist/browser/fleetMeter.d.ts.map +1 -0
- package/dist/browser/fleetPage.d.ts +5 -0
- package/dist/browser/fleetPage.d.ts.map +1 -0
- package/dist/browser/fleetProfile.d.ts +13 -0
- package/dist/browser/fleetProfile.d.ts.map +1 -0
- package/dist/browser/fleetProjection.d.ts +36 -0
- package/dist/browser/fleetProjection.d.ts.map +1 -0
- package/dist/browser/fleetQuery.d.ts +8 -0
- package/dist/browser/fleetQuery.d.ts.map +1 -0
- package/dist/browser/fleetQuerySelection.d.ts +3 -0
- package/dist/browser/fleetQuerySelection.d.ts.map +1 -0
- package/dist/browser/fleetReaders.d.ts +10 -0
- package/dist/browser/fleetReaders.d.ts.map +1 -0
- package/dist/browser/fleetRequests.d.ts +3 -0
- package/dist/browser/fleetRequests.d.ts.map +1 -0
- package/dist/browser/fleetScope.d.ts +4 -0
- package/dist/browser/fleetScope.d.ts.map +1 -0
- package/dist/browser/fleetSelectedPayloadSource.d.ts +4 -0
- package/dist/browser/fleetSelectedPayloadSource.d.ts.map +1 -0
- package/dist/browser/index.d.ts +7 -0
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.mjs +1189 -4
- package/dist/browser/index.mjs.map +4 -4
- package/dist/node/createFleetAuthority.d.ts +97 -0
- package/dist/node/createFleetAuthority.d.ts.map +1 -0
- package/dist/node/fleetControl.d.ts +16 -0
- package/dist/node/fleetControl.d.ts.map +1 -0
- package/dist/node/fleetForeign.d.ts +5 -0
- package/dist/node/fleetForeign.d.ts.map +1 -0
- package/dist/node/fleetHistory.d.ts +37 -0
- package/dist/node/fleetHistory.d.ts.map +1 -0
- package/dist/node/fleetHistoryCache.d.ts +22 -0
- package/dist/node/fleetHistoryCache.d.ts.map +1 -0
- package/dist/node/fleetMeter.d.ts +26 -0
- package/dist/node/fleetMeter.d.ts.map +1 -0
- package/dist/node/fleetPage.d.ts +5 -0
- package/dist/node/fleetPage.d.ts.map +1 -0
- package/dist/node/fleetProfile.d.ts +13 -0
- package/dist/node/fleetProfile.d.ts.map +1 -0
- package/dist/node/fleetProjection.d.ts +36 -0
- package/dist/node/fleetProjection.d.ts.map +1 -0
- package/dist/node/fleetQuery.d.ts +8 -0
- package/dist/node/fleetQuery.d.ts.map +1 -0
- package/dist/node/fleetQuerySelection.d.ts +3 -0
- package/dist/node/fleetQuerySelection.d.ts.map +1 -0
- package/dist/node/fleetReaders.d.ts +10 -0
- package/dist/node/fleetReaders.d.ts.map +1 -0
- package/dist/node/fleetRequests.d.ts +3 -0
- package/dist/node/fleetRequests.d.ts.map +1 -0
- package/dist/node/fleetScope.d.ts +4 -0
- package/dist/node/fleetScope.d.ts.map +1 -0
- package/dist/node/fleetSelectedPayloadSource.d.ts +4 -0
- package/dist/node/fleetSelectedPayloadSource.d.ts.map +1 -0
- package/dist/node/index.d.ts +7 -0
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.mjs +1189 -4
- package/dist/node/index.mjs.map +4 -4
- package/package.json +19 -15
package/dist/browser/index.mjs
CHANGED
|
@@ -1,3 +1,1184 @@
|
|
|
1
|
+
// src/createFleetAuthority.ts
|
|
2
|
+
import {
|
|
3
|
+
foldFleetControls,
|
|
4
|
+
resolveFleetPayload,
|
|
5
|
+
verifyFleetPayload
|
|
6
|
+
} from "@xyo-network/service-kit-protocol";
|
|
7
|
+
import {
|
|
8
|
+
AddressZod as AddressZod4,
|
|
9
|
+
FleetControlSchema,
|
|
10
|
+
FleetMemberSchema,
|
|
11
|
+
FleetPublicationScopeSchema,
|
|
12
|
+
FleetPublicationScopeZod,
|
|
13
|
+
FleetSchema,
|
|
14
|
+
FleetZod,
|
|
15
|
+
HashZod as HashZod5
|
|
16
|
+
} from "@xyo-network/service-kit-schemas";
|
|
17
|
+
import {
|
|
18
|
+
createXl1FinalizedPublicationEvidence
|
|
19
|
+
} from "@xyo-network/xl1-sdk/protocol-sdk/finalized-publication";
|
|
20
|
+
|
|
21
|
+
// src/fleetControl.ts
|
|
22
|
+
var abortedDescriptor = Object.getOwnPropertyDescriptor(AbortSignal.prototype, "aborted");
|
|
23
|
+
var abortedGetter = Reflect.get(abortedDescriptor ?? {}, "get");
|
|
24
|
+
var nativeEvents = EventTarget.prototype;
|
|
25
|
+
var addListener = nativeEvents.addEventListener;
|
|
26
|
+
var removeListener = nativeEvents.removeEventListener;
|
|
27
|
+
var apply = Reflect.apply;
|
|
28
|
+
var now = performance.now.bind(performance);
|
|
29
|
+
function captureSignal(value) {
|
|
30
|
+
if (value === void 0) return;
|
|
31
|
+
if (typeof abortedGetter !== "function") throw new TypeError("Native AbortSignal is required");
|
|
32
|
+
apply(abortedGetter, value, []);
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
function aborted(signal) {
|
|
36
|
+
if (typeof abortedGetter !== "function") throw new TypeError("Native AbortSignal is required");
|
|
37
|
+
return apply(abortedGetter, signal, []);
|
|
38
|
+
}
|
|
39
|
+
function listenAbort(signal, listener) {
|
|
40
|
+
if (signal === void 0) return () => {
|
|
41
|
+
};
|
|
42
|
+
apply(addListener, signal, ["abort", listener, { once: true }]);
|
|
43
|
+
return () => {
|
|
44
|
+
apply(removeListener, signal, ["abort", listener]);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
var FleetAuthorityError = class extends Error {
|
|
48
|
+
code;
|
|
49
|
+
status;
|
|
50
|
+
constructor(status, code) {
|
|
51
|
+
super(code);
|
|
52
|
+
this.name = "FleetAuthorityError";
|
|
53
|
+
this.status = status;
|
|
54
|
+
this.code = code;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
function operationControl(signal, timeoutMs, startedAt) {
|
|
58
|
+
const controller = new AbortController();
|
|
59
|
+
const deadline = startedAt + timeoutMs;
|
|
60
|
+
let terminal;
|
|
61
|
+
const stop = (status) => {
|
|
62
|
+
terminal ??= new FleetAuthorityError(status, status);
|
|
63
|
+
controller.abort();
|
|
64
|
+
};
|
|
65
|
+
const unlisten = listenAbort(signal, () => stop("cancelled"));
|
|
66
|
+
if (signal !== void 0 && aborted(signal)) stop("cancelled");
|
|
67
|
+
const timer = setTimeout(() => stop("deadline"), Math.max(1, Math.ceil(deadline - now())));
|
|
68
|
+
return {
|
|
69
|
+
signal: controller.signal,
|
|
70
|
+
assertActive() {
|
|
71
|
+
if (now() >= deadline) stop("deadline");
|
|
72
|
+
if (terminal !== void 0) throw terminal;
|
|
73
|
+
},
|
|
74
|
+
remainingMs: () => Math.max(1, Math.ceil(deadline - now())),
|
|
75
|
+
dispose() {
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
unlisten();
|
|
78
|
+
controller.abort();
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
var fleetNow = now;
|
|
83
|
+
|
|
84
|
+
// src/fleetHistory.ts
|
|
85
|
+
function historicalPublisherCandidates(controls) {
|
|
86
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
87
|
+
for (const fact of controls) {
|
|
88
|
+
const payload = fact.payload;
|
|
89
|
+
if (payload.operation !== "grant-publisher" || candidates.has(fact.root)) continue;
|
|
90
|
+
candidates.set(fact.root, Object.freeze({
|
|
91
|
+
controlRoot: fact.root,
|
|
92
|
+
controlBlock: fact.block,
|
|
93
|
+
fleetRoot: payload.fleetRoot,
|
|
94
|
+
memberRoot: payload.memberRoot,
|
|
95
|
+
scopeRoot: payload.scopeRoot,
|
|
96
|
+
publisherAddress: payload.publisherAddress,
|
|
97
|
+
...payload.expiresAtBlock !== void 0 && { expiresAtBlock: payload.expiresAtBlock }
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
return Object.freeze(candidates.values().toArray());
|
|
101
|
+
}
|
|
102
|
+
function historicalPublisherResult(result, controls, fleetRoot) {
|
|
103
|
+
const context2 = {
|
|
104
|
+
anchor: result.anchor,
|
|
105
|
+
assurance: result.assurance,
|
|
106
|
+
chainId: result.chainId,
|
|
107
|
+
genesisRoot: result.genesisRoot,
|
|
108
|
+
historyScope: result.historyScope,
|
|
109
|
+
network: result.network,
|
|
110
|
+
owner: result.owner,
|
|
111
|
+
selection: "historical-ever-granted-discovery-only",
|
|
112
|
+
...result.resources !== void 0 && { resources: result.resources },
|
|
113
|
+
...fleetRoot !== void 0 && { fleetRoot }
|
|
114
|
+
};
|
|
115
|
+
return result.status === "complete" ? Object.freeze({
|
|
116
|
+
...context2,
|
|
117
|
+
...result.scopeCompleteness !== void 0 && { scopeCompleteness: result.scopeCompleteness },
|
|
118
|
+
status: "complete",
|
|
119
|
+
correspondence: result.correspondence,
|
|
120
|
+
coveredRange: result.coveredRange,
|
|
121
|
+
history: result.history,
|
|
122
|
+
candidates: historicalPublisherCandidates(controls)
|
|
123
|
+
}) : Object.freeze({
|
|
124
|
+
...context2,
|
|
125
|
+
status: result.status,
|
|
126
|
+
code: result.code
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/fleetMeter.ts
|
|
131
|
+
var encoder = new TextEncoder();
|
|
132
|
+
function spend(budget, bytes) {
|
|
133
|
+
budget.bytes += bytes;
|
|
134
|
+
if (budget.bytes > budget.maximum) throw new RangeError("Declaration response exceeds its reserved allowance");
|
|
135
|
+
}
|
|
136
|
+
function text(budget, value) {
|
|
137
|
+
if (value.length > budget.maximum - budget.bytes) throw new RangeError("Declaration text exceeds its reserved allowance");
|
|
138
|
+
spend(budget, encoder.encode(JSON.stringify(value)).byteLength);
|
|
139
|
+
}
|
|
140
|
+
function compositeSnapshot(value, budget, depth) {
|
|
141
|
+
const array = Array.isArray(value);
|
|
142
|
+
if (Object.getPrototypeOf(value) !== (array ? Array.prototype : Object.prototype)) throw new TypeError("Declaration response requires plain JSON");
|
|
143
|
+
if (array && value.length > budget.limits.maxNodes - budget.nodes) throw new RangeError("Declaration response exceeds node bounds");
|
|
144
|
+
const keys = Reflect.ownKeys(value);
|
|
145
|
+
const expected = array ? Array.from({ length: value.length }, (_, index) => String(index)) : keys;
|
|
146
|
+
if (array && (keys.length !== value.length + 1 || keys.at(-1) !== "length")) throw new TypeError("Declaration arrays require dense own slots");
|
|
147
|
+
if (expected.length > budget.limits.maxNodes - budget.nodes) throw new RangeError("Declaration response exceeds node bounds");
|
|
148
|
+
spend(budget, 2);
|
|
149
|
+
const entries = expected.map((key, index) => {
|
|
150
|
+
if (typeof key !== "string" || key === "__proto__") throw new TypeError("Declaration keys require plain strings");
|
|
151
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
152
|
+
if (descriptor?.enumerable !== true || !("value" in descriptor)) throw new TypeError("Declaration accessors are unsupported");
|
|
153
|
+
if (index > 0) spend(budget, 1);
|
|
154
|
+
if (!array) {
|
|
155
|
+
text(budget, key);
|
|
156
|
+
spend(budget, 1);
|
|
157
|
+
}
|
|
158
|
+
return [key, jsonSnapshot(descriptor.value, budget, depth + 1)];
|
|
159
|
+
});
|
|
160
|
+
return Object.freeze(array ? entries.map(([, item]) => item) : Object.fromEntries(entries));
|
|
161
|
+
}
|
|
162
|
+
function jsonSnapshot(value, budget, depth = 0) {
|
|
163
|
+
if (++budget.nodes > budget.limits.maxNodes || depth > budget.limits.maxDepth) throw new RangeError("Declaration response exceeds structure bounds");
|
|
164
|
+
if (value === null || typeof value === "boolean" || typeof value === "number") {
|
|
165
|
+
if (typeof value === "number" && !Number.isFinite(value)) throw new TypeError("Declaration response requires finite JSON");
|
|
166
|
+
spend(budget, JSON.stringify(value).length);
|
|
167
|
+
return value;
|
|
168
|
+
}
|
|
169
|
+
if (typeof value === "string") {
|
|
170
|
+
text(budget, value);
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
if (typeof value !== "object" || budget.ancestors.has(value)) throw new TypeError("Declaration response requires acyclic own-data JSON");
|
|
174
|
+
budget.ancestors.add(value);
|
|
175
|
+
try {
|
|
176
|
+
return compositeSnapshot(value, budget, depth);
|
|
177
|
+
} finally {
|
|
178
|
+
budget.ancestors.delete(value);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function logicalJsonSnapshot(value, maximum, limits) {
|
|
182
|
+
const budget = {
|
|
183
|
+
bytes: 0,
|
|
184
|
+
nodes: 0,
|
|
185
|
+
maximum,
|
|
186
|
+
limits,
|
|
187
|
+
ancestors: /* @__PURE__ */ new WeakSet()
|
|
188
|
+
};
|
|
189
|
+
const snapshot = jsonSnapshot(value, budget);
|
|
190
|
+
return { value: snapshot, bytes: budget.bytes };
|
|
191
|
+
}
|
|
192
|
+
var FleetMeter = class {
|
|
193
|
+
#ceiling;
|
|
194
|
+
#closed = false;
|
|
195
|
+
#declarations = 0;
|
|
196
|
+
#limits;
|
|
197
|
+
#native = 0;
|
|
198
|
+
#reserved = 0;
|
|
199
|
+
constructor(ceiling, limits) {
|
|
200
|
+
this.#ceiling = ceiling;
|
|
201
|
+
this.#limits = limits;
|
|
202
|
+
}
|
|
203
|
+
close() {
|
|
204
|
+
this.#closed = true;
|
|
205
|
+
}
|
|
206
|
+
native(bytes) {
|
|
207
|
+
if (bytes === void 0 || !Number.isSafeInteger(bytes) || bytes < 0) throw new FleetAuthorityError("conflict", "native-resources");
|
|
208
|
+
this.#native += bytes;
|
|
209
|
+
if (this.#native + this.#declarations + this.#reserved > this.#ceiling) throw new FleetAuthorityError("resource-limit", "aggregate-bytes");
|
|
210
|
+
}
|
|
211
|
+
async read(get, roots, options) {
|
|
212
|
+
const allowance = Math.min(options?.maxBodyBytes ?? this.#limits.maxBodyBytes, this.remaining());
|
|
213
|
+
this.#reserved += allowance;
|
|
214
|
+
const response = await get(roots, {
|
|
215
|
+
...options,
|
|
216
|
+
signal: options?.signal ?? new AbortController().signal,
|
|
217
|
+
maxBodyBytes: allowance
|
|
218
|
+
});
|
|
219
|
+
if (this.#closed || options?.signal !== void 0 && aborted(options.signal)) throw new FleetAuthorityError("incomplete", "declaration-late");
|
|
220
|
+
if (!Array.isArray(response) || response.length > this.#limits.maxCandidatesPerSeed) throw new FleetAuthorityError("resource-limit", "declaration-response");
|
|
221
|
+
const budget = {
|
|
222
|
+
bytes: 0,
|
|
223
|
+
nodes: 0,
|
|
224
|
+
maximum: allowance,
|
|
225
|
+
limits: this.#limits,
|
|
226
|
+
ancestors: /* @__PURE__ */ new WeakSet()
|
|
227
|
+
};
|
|
228
|
+
const snapshot = jsonSnapshot(response, budget);
|
|
229
|
+
this.#reserved -= allowance;
|
|
230
|
+
this.#declarations += budget.bytes;
|
|
231
|
+
return snapshot;
|
|
232
|
+
}
|
|
233
|
+
remaining() {
|
|
234
|
+
const remaining = this.#ceiling - this.#native - this.#declarations - this.#reserved;
|
|
235
|
+
if (this.#closed || remaining <= 0) throw new FleetAuthorityError("resource-limit", "aggregate-bytes");
|
|
236
|
+
return remaining;
|
|
237
|
+
}
|
|
238
|
+
resources() {
|
|
239
|
+
const decodedBytes = this.#native + this.#declarations;
|
|
240
|
+
return Object.freeze({
|
|
241
|
+
decodedBytes,
|
|
242
|
+
chargedBytes: decodedBytes + this.#reserved,
|
|
243
|
+
nativeDecodedBytes: this.#native,
|
|
244
|
+
declarationDecodedBytes: this.#declarations,
|
|
245
|
+
declarationReservedBytes: this.#reserved
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
function chargeNativeResources(meter, resources) {
|
|
250
|
+
meter?.native(resources?.decodedBytes);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/fleetHistoryCache.ts
|
|
254
|
+
function snapshotFleetVerifiedHistory(input) {
|
|
255
|
+
if (input === void 0) return;
|
|
256
|
+
if (input === null || typeof input !== "object" || Object.getPrototypeOf(input) !== Object.prototype || Reflect.ownKeys(input).length !== 2) throw new TypeError("Select strict verified owner-history bounds");
|
|
257
|
+
const values = Object.fromEntries(["maxBytes", "maxOwners"].map((key) => {
|
|
258
|
+
const slot = Object.getOwnPropertyDescriptor(input, key);
|
|
259
|
+
if (slot?.enumerable !== true || !("value" in slot) || typeof slot.value !== "number" || !Number.isSafeInteger(slot.value) || slot.value <= 0) throw new TypeError("Select positive own-data history bounds");
|
|
260
|
+
return [key, slot.value];
|
|
261
|
+
}));
|
|
262
|
+
if (values.maxOwners > 16 || values.maxBytes > 128 * 1024 * 1024) throw new RangeError("Verified history storage exceeds its bounded profile");
|
|
263
|
+
return Object.freeze(values);
|
|
264
|
+
}
|
|
265
|
+
var encoder2 = new TextEncoder();
|
|
266
|
+
var decoder = new TextDecoder("utf-8", { fatal: true });
|
|
267
|
+
var VerifiedFleetHistory = class {
|
|
268
|
+
#bytes = 0;
|
|
269
|
+
#entries = /* @__PURE__ */ new Map();
|
|
270
|
+
#limits;
|
|
271
|
+
#maxDepth;
|
|
272
|
+
constructor(limits, maxDepth) {
|
|
273
|
+
this.#limits = limits;
|
|
274
|
+
this.#maxDepth = maxDepth;
|
|
275
|
+
}
|
|
276
|
+
get(owner) {
|
|
277
|
+
const entry = this.#entries.get(owner);
|
|
278
|
+
if (entry === void 0) return;
|
|
279
|
+
this.#entries.delete(owner);
|
|
280
|
+
this.#entries.set(owner, entry);
|
|
281
|
+
const decoded = JSON.parse(decoder.decode(entry.data));
|
|
282
|
+
return logicalJsonSnapshot(decoded, this.#limits.maxBytes, { maxDepth: this.#maxDepth, maxNodes: this.#limits.maxBytes }).value;
|
|
283
|
+
}
|
|
284
|
+
publish(input) {
|
|
285
|
+
const prior = this.#entries.get(input.owner);
|
|
286
|
+
if (prior !== void 0) {
|
|
287
|
+
if (prior.anchor.blockNumber > input.anchor.blockNumber) return;
|
|
288
|
+
if (prior.anchor.blockNumber === input.anchor.blockNumber && prior.anchor.blockRoot !== input.anchor.blockRoot) throw new FleetAuthorityError("conflict", "history-anchor");
|
|
289
|
+
}
|
|
290
|
+
let snapshot;
|
|
291
|
+
try {
|
|
292
|
+
snapshot = logicalJsonSnapshot(input, this.#limits.maxBytes, { maxDepth: this.#maxDepth, maxNodes: this.#limits.maxBytes });
|
|
293
|
+
} catch {
|
|
294
|
+
throw new FleetAuthorityError("resource-limit", "history-bytes");
|
|
295
|
+
}
|
|
296
|
+
while (this.#bytes + snapshot.bytes > this.#limits.maxBytes || this.#entries.size >= this.#limits.maxOwners) {
|
|
297
|
+
const oldest = this.#entries.keys().next().value;
|
|
298
|
+
if (oldest === void 0) throw new FleetAuthorityError("resource-limit", "history-bytes");
|
|
299
|
+
this.#bytes -= this.#entries.get(oldest).data.byteLength;
|
|
300
|
+
this.#entries.delete(oldest);
|
|
301
|
+
}
|
|
302
|
+
const data = encoder2.encode(JSON.stringify(snapshot.value));
|
|
303
|
+
if (data.byteLength !== snapshot.bytes) throw new FleetAuthorityError("conflict", "history-size");
|
|
304
|
+
const replacing = this.#entries.get(input.owner);
|
|
305
|
+
if (replacing !== void 0) this.#bytes -= replacing.data.byteLength;
|
|
306
|
+
this.#entries.set(input.owner, { anchor: input.anchor, data });
|
|
307
|
+
this.#bytes += data.byteLength;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// src/fleetScope.ts
|
|
312
|
+
import { HashZod as HashZod3 } from "@xyo-network/service-kit-schemas";
|
|
313
|
+
|
|
314
|
+
// src/fleetForeign.ts
|
|
315
|
+
import { AddressZod, HashZod } from "@xyo-network/service-kit-schemas";
|
|
316
|
+
|
|
317
|
+
// src/fleetProfile.ts
|
|
318
|
+
import {
|
|
319
|
+
snapshotFinalizedForeignTransactions,
|
|
320
|
+
snapshotFinalizedForkLineage,
|
|
321
|
+
snapshotFinalizedVerifiedPrefix
|
|
322
|
+
} from "@xyo-network/xl1-sdk/protocol-sdk/finalized-publication";
|
|
323
|
+
|
|
324
|
+
// src/fleetQuerySelection.ts
|
|
325
|
+
import { snapshotFinalizedQuerySelection } from "@xyo-network/xl1-sdk/protocol-sdk/finalized-publication";
|
|
326
|
+
function snapshotFleetQuerySelection(input) {
|
|
327
|
+
const selection = snapshotFinalizedQuerySelection(input);
|
|
328
|
+
if (selection !== input) throw new TypeError("Native query selection snapshot must preserve the exact policy");
|
|
329
|
+
return selection;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/fleetSelectedPayloadSource.ts
|
|
333
|
+
import { snapshotFinalizedSelectedPayloadSource } from "@xyo-network/xl1-sdk/protocol-sdk/finalized-publication";
|
|
334
|
+
function snapshotFleetSelectedPayloadSource(input, maxSourceUrlBytes) {
|
|
335
|
+
const captured = snapshotFinalizedSelectedPayloadSource(input, maxSourceUrlBytes);
|
|
336
|
+
if (input !== void 0 && captured === void 0) throw new TypeError("Selected payload source snapshot must preserve the requested selection");
|
|
337
|
+
return captured;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// src/fleetProfile.ts
|
|
341
|
+
function ownRecord(input, required, optional = []) {
|
|
342
|
+
if (input === null || typeof input !== "object" || Object.getPrototypeOf(input) !== Object.prototype) throw new TypeError("Use a strict own-data profile/request");
|
|
343
|
+
const keys = Reflect.ownKeys(input);
|
|
344
|
+
if (keys.some((key) => typeof key !== "string" || ![...required, ...optional].includes(key)) || required.some((key) => !keys.includes(key))) throw new TypeError("Unexpected or missing profile/request fields");
|
|
345
|
+
return Object.fromEntries(keys.map((key) => {
|
|
346
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
347
|
+
if (descriptor?.enumerable !== true || !("value" in descriptor)) throw new TypeError("Profile/request accessors are unsupported");
|
|
348
|
+
return [key, descriptor.value];
|
|
349
|
+
}));
|
|
350
|
+
}
|
|
351
|
+
function finiteProfile(input, keys, largeBytes = false) {
|
|
352
|
+
const values = ownRecord(input, keys);
|
|
353
|
+
if (Object.entries(values).some(([key, value]) => typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0 || value > 2147483647 && !(largeBytes && key === "maxAggregateBytes"))) throw new RangeError("Every finite positive bound is required");
|
|
354
|
+
return Object.freeze(values);
|
|
355
|
+
}
|
|
356
|
+
function pinProfile(input) {
|
|
357
|
+
const profile = ownRecord(input, ["evidence", "foldLimits", "limits", "resolutionLimits", "seeds"], ["verifiedHistory"]);
|
|
358
|
+
const evidence = ownRecord(profile.evidence, ["assurance", "chainId", "genesisRoot", "limits", "network", "source"], ["forkLineage", "verifiedPrefix", "foreignTransactions", "querySelection"]);
|
|
359
|
+
const source = ownRecord(evidence.source, ["bodyBaseUrl", "finalizedBaseUrl", "headUrl"], ["fetch", "blockFrames", "selectedPayloadSource"]);
|
|
360
|
+
const forkLineage = snapshotFinalizedForkLineage(evidence.forkLineage, evidence.chainId);
|
|
361
|
+
const blockFrames = source.blockFrames === void 0 ? void 0 : pinBlockFrames(source.blockFrames);
|
|
362
|
+
const verifiedPrefix = pinVerifiedPrefix(evidence.verifiedPrefix);
|
|
363
|
+
const foreignTransactions = snapshotFinalizedForeignTransactions(evidence.foreignTransactions);
|
|
364
|
+
if (foreignTransactions !== void 0 && (forkLineage === void 0 || blockFrames === void 0 || verifiedPrefix === void 0)) {
|
|
365
|
+
throw new TypeError("Foreign transaction exclusion requires explicit fork, frame and verified-prefix profiles");
|
|
366
|
+
}
|
|
367
|
+
if (verifiedPrefix !== void 0 && (forkLineage === void 0 || blockFrames === void 0)) throw new TypeError("Verified native prefix requires explicit fork and original-block frame profiles");
|
|
368
|
+
const querySelection = snapshotFleetQuerySelection(evidence.querySelection);
|
|
369
|
+
const verifiedHistory = snapshotFleetVerifiedHistory(profile.verifiedHistory);
|
|
370
|
+
if (verifiedHistory !== void 0 && verifiedPrefix === void 0) throw new TypeError("Verified owner history requires native verified-prefix support");
|
|
371
|
+
const evidenceLimits = finiteProfile(evidence.limits, [
|
|
372
|
+
"maxAggregateBytes",
|
|
373
|
+
"maxBlocks",
|
|
374
|
+
"maxBodies",
|
|
375
|
+
"maxConcurrentReads",
|
|
376
|
+
"maxDecodedDepth",
|
|
377
|
+
"maxDecodedNodes",
|
|
378
|
+
"maxLineageBlocks",
|
|
379
|
+
"maxResponseBytes",
|
|
380
|
+
"maxRoots",
|
|
381
|
+
"maxSourceUrlBytes",
|
|
382
|
+
"perCallTimeoutMs",
|
|
383
|
+
"totalTimeoutMs"
|
|
384
|
+
], verifiedPrefix !== void 0);
|
|
385
|
+
const selectedPayloadSource = snapshotFleetSelectedPayloadSource(source.selectedPayloadSource, evidenceLimits.maxSourceUrlBytes);
|
|
386
|
+
const fixedEvidence = Object.freeze({
|
|
387
|
+
...evidence,
|
|
388
|
+
limits: evidenceLimits,
|
|
389
|
+
...forkLineage !== void 0 && { forkLineage },
|
|
390
|
+
...verifiedPrefix !== void 0 && { verifiedPrefix },
|
|
391
|
+
...foreignTransactions !== void 0 && { foreignTransactions },
|
|
392
|
+
...querySelection !== void 0 && { querySelection },
|
|
393
|
+
source: Object.freeze({
|
|
394
|
+
...source,
|
|
395
|
+
...blockFrames !== void 0 && { blockFrames },
|
|
396
|
+
...selectedPayloadSource !== void 0 && { selectedPayloadSource }
|
|
397
|
+
})
|
|
398
|
+
});
|
|
399
|
+
const limits = finiteProfile(profile.limits, [
|
|
400
|
+
"maxBlocks",
|
|
401
|
+
"maxConcurrentCalls",
|
|
402
|
+
"maxConcurrentReads",
|
|
403
|
+
"maxFleets",
|
|
404
|
+
"maxOccurrences",
|
|
405
|
+
"maxPages",
|
|
406
|
+
"maxRootReads",
|
|
407
|
+
"totalTimeoutMs"
|
|
408
|
+
]);
|
|
409
|
+
const foldLimits = finiteProfile(profile.foldLimits, ["maxBodyBytes", "maxControls", "maxDeclarations", "maxDepth", "maxGrants", "maxMembers", "maxNodes"]);
|
|
410
|
+
const resolutionLimits = finiteProfile(profile.resolutionLimits, [
|
|
411
|
+
"attemptTimeoutMs",
|
|
412
|
+
"maxBodyBytes",
|
|
413
|
+
"maxCandidatesPerSeed",
|
|
414
|
+
"maxDepth",
|
|
415
|
+
"maxNodes",
|
|
416
|
+
"maxSeeds",
|
|
417
|
+
"totalTimeoutMs"
|
|
418
|
+
]);
|
|
419
|
+
return {
|
|
420
|
+
evidence: fixedEvidence,
|
|
421
|
+
limits,
|
|
422
|
+
foldLimits,
|
|
423
|
+
resolutionLimits,
|
|
424
|
+
verifiedHistory,
|
|
425
|
+
seeds: profile.seeds
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
function pinBlockFrames(input) {
|
|
429
|
+
const frames = ownRecord(input, ["indexBaseUrl", "maxStep"]);
|
|
430
|
+
if (typeof frames.indexBaseUrl !== "string" || frames.indexBaseUrl.length === 0 || typeof frames.maxStep !== "number" || !Number.isSafeInteger(frames.maxStep) || frames.maxStep < 0 || frames.maxStep > 3) throw new TypeError("Select a bounded original-block frame source");
|
|
431
|
+
return Object.freeze({ indexBaseUrl: frames.indexBaseUrl, maxStep: frames.maxStep });
|
|
432
|
+
}
|
|
433
|
+
function pinVerifiedPrefix(input) {
|
|
434
|
+
if (input === void 0) return snapshotFinalizedVerifiedPrefix(input);
|
|
435
|
+
const fields = ownRecord(input, ["maxEntries", "maxBytes"], ["shareKey"]);
|
|
436
|
+
const captured = snapshotFinalizedVerifiedPrefix(fields);
|
|
437
|
+
if (captured === void 0 || captured.maxEntries !== fields.maxEntries || captured.maxBytes !== fields.maxBytes || Reflect.get(captured, "shareKey") !== fields.shareKey) throw new TypeError("Native verified-prefix snapshot must preserve its exact selection");
|
|
438
|
+
return captured;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// src/fleetForeign.ts
|
|
442
|
+
function field(input, key) {
|
|
443
|
+
if (input === null || typeof input !== "object") throw new FleetAuthorityError("conflict", "scan-foreign-header");
|
|
444
|
+
const slot = Object.getOwnPropertyDescriptor(input, key);
|
|
445
|
+
if (slot?.enumerable !== true || !("value" in slot)) throw new FleetAuthorityError("conflict", "scan-foreign-header");
|
|
446
|
+
return slot.value;
|
|
447
|
+
}
|
|
448
|
+
function position(value) {
|
|
449
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
450
|
+
}
|
|
451
|
+
function validateSlots(header) {
|
|
452
|
+
const hashes = field(header.transaction, "payload_hashes");
|
|
453
|
+
const schemas = field(header.transaction, "payload_schemas");
|
|
454
|
+
if (!Array.isArray(hashes) || !Array.isArray(schemas) || !Array.isArray(header.payloads) || hashes.length !== schemas.length || hashes.length !== header.payloads.length) throw new FleetAuthorityError("conflict", "scan-foreign-slots");
|
|
455
|
+
for (let index = 0; index < hashes.length; index++) {
|
|
456
|
+
const hash = field(hashes, String(index));
|
|
457
|
+
const schema = field(schemas, String(index));
|
|
458
|
+
const slot = ownRecord(field(header.payloads, String(index)), ["payloadOrdinal", "payloadRoot", "schema", "selected"]);
|
|
459
|
+
if (typeof schema !== "string" || schema.length === 0 || !HashZod.safeParse(hash).success || slot.payloadOrdinal !== index || slot.payloadRoot !== hash || slot.schema !== schema || slot.selected !== false) throw new FleetAuthorityError("conflict", "scan-foreign-slots");
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function validateDomain(header, profile) {
|
|
463
|
+
const ancestors = profile.evidence.forkLineage?.map((edge) => edge.parentChainId) ?? [];
|
|
464
|
+
if (header.network !== profile.evidence.network || header.genesisRoot !== profile.evidence.genesisRoot || header.carryingChainId !== profile.evidence.chainId || header.chainId === profile.evidence.chainId || !ancestors.includes(header.chainId) || header.reason !== "verified-ancestor-domain-not-authority" || field(header.transaction, "chain") !== header.chainId || field(header.transaction, "from") !== header.signer || !AddressZod.safeParse(header.signer).success || !HashZod.safeParse(header.blockRoot).success || !HashZod.safeParse(header.transactionRoot).success) throw new FleetAuthorityError("conflict", "scan-foreign-domain");
|
|
465
|
+
}
|
|
466
|
+
function validateHeader(input, page, profile, from, to) {
|
|
467
|
+
const header = ownRecord(input, [
|
|
468
|
+
"network",
|
|
469
|
+
"chainId",
|
|
470
|
+
"genesisRoot",
|
|
471
|
+
"blockNumber",
|
|
472
|
+
"blockRoot",
|
|
473
|
+
"transactionRoot",
|
|
474
|
+
"transactionIndex",
|
|
475
|
+
"transactionPayloadOrdinal",
|
|
476
|
+
"signer",
|
|
477
|
+
"transaction",
|
|
478
|
+
"payloads",
|
|
479
|
+
"carryingChainId",
|
|
480
|
+
"reason"
|
|
481
|
+
]);
|
|
482
|
+
validateDomain(header, profile);
|
|
483
|
+
if (!position(header.blockNumber) || header.blockNumber < from || header.blockNumber > to || !position(header.transactionIndex) || !position(header.transactionPayloadOrdinal) || header.transactionPayloadOrdinal < header.transactionIndex) throw new FleetAuthorityError("conflict", "scan-foreign-position");
|
|
484
|
+
if (page.blockClocks.every((clock) => !(clock.blockNumber === header.blockNumber && clock.blockRoot === header.blockRoot && clock.chainId === header.carryingChainId)) || page.headers.some((ordinary) => ordinary.blockNumber === header.blockNumber && ordinary.transactionIndex === header.transactionIndex)) {
|
|
485
|
+
throw new FleetAuthorityError("conflict", "scan-foreign-correspondence");
|
|
486
|
+
}
|
|
487
|
+
validateSlots(header);
|
|
488
|
+
return {
|
|
489
|
+
block: header.blockNumber,
|
|
490
|
+
index: header.transactionIndex,
|
|
491
|
+
ordinal: header.transactionPayloadOrdinal
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
function validateForeignHeaders(page, profile, from, to) {
|
|
495
|
+
const result = page;
|
|
496
|
+
if (profile.evidence.foreignTransactions === void 0) {
|
|
497
|
+
if (result.foreignTransactionHeaders !== void 0) throw new FleetAuthorityError("conflict", "scan-foreign-profile");
|
|
498
|
+
return 0;
|
|
499
|
+
}
|
|
500
|
+
if (!Array.isArray(result.foreignTransactionHeaders) || result.foreignTransactionHeaders.length > profile.evidence.limits.maxRoots) throw new FleetAuthorityError("conflict", "scan-foreign-headers");
|
|
501
|
+
let previous;
|
|
502
|
+
for (let index = 0; index < result.foreignTransactionHeaders.length; index++) {
|
|
503
|
+
const header = validateHeader(field(result.foreignTransactionHeaders, String(index)), page, profile, from, to);
|
|
504
|
+
if (previous !== void 0 && (header.block < previous.block || header.block === previous.block && (header.index <= previous.index || header.ordinal <= previous.ordinal))) throw new FleetAuthorityError("conflict", "scan-foreign-order");
|
|
505
|
+
previous = header;
|
|
506
|
+
}
|
|
507
|
+
return result.foreignTransactionHeaders.length;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// src/fleetQuery.ts
|
|
511
|
+
import { AddressZod as AddressZod2, HashZod as HashZod2 } from "@xyo-network/service-kit-schemas";
|
|
512
|
+
var grade = "verified-block-committed-query-selection";
|
|
513
|
+
var encoder3 = new TextEncoder();
|
|
514
|
+
function fail(code = "scan-query-exclusion") {
|
|
515
|
+
throw new FleetAuthorityError("conflict", code);
|
|
516
|
+
}
|
|
517
|
+
function spend2(budget, nodes, bytes = 0) {
|
|
518
|
+
budget.nodes += nodes;
|
|
519
|
+
budget.bytes += bytes;
|
|
520
|
+
if (budget.nodes > budget.profile.evidence.limits.maxDecodedNodes || budget.bytes > budget.profile.evidence.limits.maxAggregateBytes) {
|
|
521
|
+
throw new FleetAuthorityError("resource-limit", "scan-query-metadata");
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
function field2(input, key) {
|
|
525
|
+
const slot = input !== null && typeof input === "object" ? Object.getOwnPropertyDescriptor(input, key) : void 0;
|
|
526
|
+
return slot?.enumerable === true && "value" in slot ? slot.value : fail();
|
|
527
|
+
}
|
|
528
|
+
function position2(input) {
|
|
529
|
+
return typeof input === "number" && Number.isSafeInteger(input) && input >= 0;
|
|
530
|
+
}
|
|
531
|
+
function dense(input, maximum, budget) {
|
|
532
|
+
if (!Array.isArray(input) || input.length > maximum || Reflect.ownKeys(input).length !== input.length + 1) return fail();
|
|
533
|
+
spend2(budget, input.length + 1);
|
|
534
|
+
for (let i = 0; i < input.length; i++) field2(input, String(i));
|
|
535
|
+
return input;
|
|
536
|
+
}
|
|
537
|
+
function strings(input, budget, address = false) {
|
|
538
|
+
const values = dense(input, budget.profile.evidence.limits.maxRoots, budget);
|
|
539
|
+
for (const value of values) {
|
|
540
|
+
if (typeof value !== "string" || value.length === 0 || value.length > budget.profile.evidence.limits.maxResponseBytes || address && !AddressZod2.safeParse(value).success) return fail();
|
|
541
|
+
spend2(budget, 0, encoder3.encode(value).byteLength);
|
|
542
|
+
}
|
|
543
|
+
return values;
|
|
544
|
+
}
|
|
545
|
+
function scopeMatches(input, expected, budget) {
|
|
546
|
+
const keys = ["authorizers", "chainIds", "schemas"].filter((key) => expected[key] !== void 0);
|
|
547
|
+
const snapshot = ownRecord(input, keys);
|
|
548
|
+
for (const key of keys) {
|
|
549
|
+
const selected = snapshot[key];
|
|
550
|
+
if (!Array.isArray(selected) || selected.length !== expected[key].length) fail("scan-query-request");
|
|
551
|
+
const values = strings(selected, budget, key !== "schemas");
|
|
552
|
+
if (values.some((value, index) => value !== expected[key][index])) fail("scan-query-request");
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function chainAt(profile, block) {
|
|
556
|
+
let chain = profile.evidence.chainId;
|
|
557
|
+
const lineage = profile.evidence.forkLineage ?? [];
|
|
558
|
+
for (const edge of lineage) {
|
|
559
|
+
if (block > edge.forkedAtBlockNumber) break;
|
|
560
|
+
chain = edge.parentChainId;
|
|
561
|
+
}
|
|
562
|
+
return chain;
|
|
563
|
+
}
|
|
564
|
+
function occupiedPositions(page, budget) {
|
|
565
|
+
const occupied = /* @__PURE__ */ new Set();
|
|
566
|
+
for (const rows of [page.headers, page.occurrences, page.foreignTransactionHeaders ?? []]) {
|
|
567
|
+
for (const row of dense(rows, budget.profile.evidence.limits.maxRoots, budget)) {
|
|
568
|
+
const block = field2(row, "blockNumber");
|
|
569
|
+
const index = field2(row, "transactionIndex");
|
|
570
|
+
const ordinal = field2(row, "transactionPayloadOrdinal");
|
|
571
|
+
if (!position2(block) || !position2(index) || !position2(ordinal)) fail();
|
|
572
|
+
occupied.add(`${block}:index:${index}`);
|
|
573
|
+
occupied.add(`${block}:ordinal:${ordinal}`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return occupied;
|
|
577
|
+
}
|
|
578
|
+
function clockRows(page, budget) {
|
|
579
|
+
const clocks = /* @__PURE__ */ new Map();
|
|
580
|
+
for (const row of dense(page.blockClocks, budget.profile.evidence.limits.maxBlocks, budget)) {
|
|
581
|
+
const block = field2(row, "blockNumber");
|
|
582
|
+
if (!position2(block) || clocks.has(block)) fail("scan-query-clock");
|
|
583
|
+
clocks.set(block, row);
|
|
584
|
+
}
|
|
585
|
+
return clocks;
|
|
586
|
+
}
|
|
587
|
+
function validateClock(row, clocks, profile) {
|
|
588
|
+
const clock = clocks.get(row.blockNumber);
|
|
589
|
+
if (clock === void 0 || field2(clock, "network") !== profile.evidence.network || field2(clock, "genesisRoot") !== profile.evidence.genesisRoot || field2(clock, "blockRoot") !== row.blockRoot || field2(clock, "chainId") !== row.carryingChainId) fail("scan-query-clock");
|
|
590
|
+
const time = field2(clock, "time");
|
|
591
|
+
if (field2(time, "status") === "authenticated" && (field2(time, "payloadOrdinal") === row.transactionPayloadOrdinal || field2(time, "payloadRoot") === row.transactionRoot)) fail("scan-query-time");
|
|
592
|
+
}
|
|
593
|
+
function validatePosition(row, profile, from, to) {
|
|
594
|
+
if (!position2(row.blockNumber) || row.blockNumber < from || row.blockNumber > to || !position2(row.transactionIndex) || !position2(row.transactionPayloadOrdinal) || row.transactionPayloadOrdinal < row.transactionIndex || row.carryingChainId !== chainAt(profile, row.blockNumber) || !AddressZod2.safeParse(row.declaredChainId).success || !AddressZod2.safeParse(row.declaredFrom).success || !HashZod2.safeParse(row.blockRoot).success || !HashZod2.safeParse(row.transactionRoot).success) fail();
|
|
595
|
+
}
|
|
596
|
+
function validateRecord(input, expected, profile, from, to, clocks, occupied, budget) {
|
|
597
|
+
const row = ownRecord(input, [
|
|
598
|
+
"blockNumber",
|
|
599
|
+
"blockRoot",
|
|
600
|
+
"carryingChainId",
|
|
601
|
+
"transactionIndex",
|
|
602
|
+
"transactionPayloadOrdinal",
|
|
603
|
+
"transactionRoot",
|
|
604
|
+
"declaredChainId",
|
|
605
|
+
"declaredFrom",
|
|
606
|
+
"declaredAddresses",
|
|
607
|
+
"declaredPayloadSchemas",
|
|
608
|
+
"reason",
|
|
609
|
+
"requestSnapshot"
|
|
610
|
+
]);
|
|
611
|
+
spend2(budget, 12);
|
|
612
|
+
validatePosition(row, profile, from, to);
|
|
613
|
+
const addresses = strings(row.declaredAddresses, budget, true);
|
|
614
|
+
const schemas = strings(row.declaredPayloadSchemas, budget);
|
|
615
|
+
if (addresses.length === 0 || new Set(addresses).size !== addresses.length) fail();
|
|
616
|
+
scopeMatches(row.requestSnapshot, expected, budget);
|
|
617
|
+
const claimed = /* @__PURE__ */ new Set([row.declaredFrom, ...addresses]);
|
|
618
|
+
const noAuthorizer = expected.authorizers?.every((value) => !claimed.has(value)) === true;
|
|
619
|
+
const noSchema = expected.schemas?.every((value) => !schemas.includes(value)) === true;
|
|
620
|
+
const reason = noAuthorizer ? "no-requested-authorizer" : noSchema ? "no-requested-schema" : void 0;
|
|
621
|
+
if (reason === void 0 || row.reason !== reason) fail("scan-query-reason");
|
|
622
|
+
const indexKey = `${row.blockNumber}:index:${row.transactionIndex}`;
|
|
623
|
+
const ordinalKey = `${row.blockNumber}:ordinal:${row.transactionPayloadOrdinal}`;
|
|
624
|
+
if (occupied.has(indexKey) || occupied.has(ordinalKey)) fail("scan-query-overlap");
|
|
625
|
+
occupied.add(indexKey);
|
|
626
|
+
occupied.add(ordinalKey);
|
|
627
|
+
if (pageExcluded(profile, row.blockNumber, from, to)) fail("scan-query-excluded-chain");
|
|
628
|
+
validateClock(row, clocks, profile);
|
|
629
|
+
return {
|
|
630
|
+
block: row.blockNumber,
|
|
631
|
+
index: row.transactionIndex,
|
|
632
|
+
ordinal: row.transactionPayloadOrdinal
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
function pageExcluded(profile, block, from, to) {
|
|
636
|
+
return profile.evidence.verifiedPrefix !== void 0 && profile.evidence.forkLineage?.some((edge) => block >= from && block <= to && block <= edge.forkedAtBlockNumber) === true;
|
|
637
|
+
}
|
|
638
|
+
function validateQueryExclusions(page, profile, from, to, expectedScope) {
|
|
639
|
+
const result = page;
|
|
640
|
+
if (profile.evidence.querySelection === void 0) {
|
|
641
|
+
if (result.blockCommittedQueryExclusions !== void 0 || result.scopeCompleteness === grade) fail("scan-query-profile");
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
try {
|
|
645
|
+
if (expectedScope === void 0 || expectedScope.headersOnly !== void 0 || expectedScope.authorizers === void 0 && expectedScope.schemas === void 0 || [expectedScope.authorizers, expectedScope.chainIds, expectedScope.schemas].some((values) => values?.length === 0) || result.scopeCompleteness !== grade) fail("scan-query-grade");
|
|
646
|
+
const budget = {
|
|
647
|
+
nodes: 0,
|
|
648
|
+
bytes: 0,
|
|
649
|
+
profile
|
|
650
|
+
};
|
|
651
|
+
scopeMatches(page.scope, expectedScope, budget);
|
|
652
|
+
const rows = dense(result.blockCommittedQueryExclusions, profile.evidence.limits.maxRoots, budget);
|
|
653
|
+
const occupied = occupiedPositions(page, budget);
|
|
654
|
+
const clocks = clockRows(page, budget);
|
|
655
|
+
let previous;
|
|
656
|
+
for (const row of rows) {
|
|
657
|
+
const current = validateRecord(row, expectedScope, profile, from, to, clocks, occupied, budget);
|
|
658
|
+
if (previous !== void 0 && (current.block < previous.block || current.block === previous.block && (current.index <= previous.index || current.ordinal <= previous.ordinal))) fail("scan-query-order");
|
|
659
|
+
previous = current;
|
|
660
|
+
}
|
|
661
|
+
return grade;
|
|
662
|
+
} catch (error) {
|
|
663
|
+
if (error instanceof FleetAuthorityError) throw error;
|
|
664
|
+
return fail();
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// src/fleetScope.ts
|
|
669
|
+
function validateRange(input, expected, profile) {
|
|
670
|
+
const range = ownRecord(input, ["chainId", "fromBlockNumber", "fromBlockRoot", "toBlockNumber", "toBlockRoot"]);
|
|
671
|
+
const {
|
|
672
|
+
edge,
|
|
673
|
+
first,
|
|
674
|
+
last
|
|
675
|
+
} = expected;
|
|
676
|
+
if (range.chainId !== edge.parentChainId || range.chainId === profile.evidence.chainId || range.fromBlockNumber !== first || range.toBlockNumber !== last || !HashZod3.safeParse(range.fromBlockRoot).success || !HashZod3.safeParse(range.toBlockRoot).success || first === 0 && range.fromBlockRoot !== profile.evidence.genesisRoot || last === edge.forkedAtBlockNumber && range.toBlockRoot !== edge.forkedAtBlockRoot || first === last && range.fromBlockRoot !== range.toBlockRoot) throw new FleetAuthorityError("conflict", "scan-exclusions");
|
|
677
|
+
}
|
|
678
|
+
function validateGrade(actual, query, foreign) {
|
|
679
|
+
if (query !== void 0) return;
|
|
680
|
+
if (actual !== "verified-native-header-selection-with-domain-exclusions" && foreign > 0) throw new FleetAuthorityError("conflict", "scan-foreign-grade");
|
|
681
|
+
const legacy = ["verified-native-header-selection", "verified-native-header-selection-with-chain-exclusions", "verified-native-header-selection-with-domain-exclusions"];
|
|
682
|
+
if (!legacy.includes(actual)) throw new FleetAuthorityError("conflict", "scan-scope-mode");
|
|
683
|
+
}
|
|
684
|
+
function validateScopeMode(page, profile, from, to, expectedScope) {
|
|
685
|
+
const query = validateQueryExclusions(page, profile, from, to, expectedScope);
|
|
686
|
+
const foreign = validateForeignHeaders(page, profile, from, to);
|
|
687
|
+
const result = page;
|
|
688
|
+
validateGrade(result.scopeCompleteness, query, foreign);
|
|
689
|
+
if (result.scopeCompleteness === "verified-native-header-selection" || query !== void 0 && (profile.evidence.forkLineage === void 0 || profile.evidence.verifiedPrefix === void 0)) {
|
|
690
|
+
if (result.excludedChainRanges !== void 0 && result.excludedChainRanges.length > 0) throw new FleetAuthorityError("conflict", "scan-exclusions");
|
|
691
|
+
return query;
|
|
692
|
+
}
|
|
693
|
+
const lineage = profile.evidence.forkLineage;
|
|
694
|
+
if (lineage === void 0 || profile.evidence.verifiedPrefix === void 0 || !Array.isArray(result.excludedChainRanges)) throw new FleetAuthorityError("conflict", "scan-scope-mode");
|
|
695
|
+
const expected = lineage.map((edge, index) => ({
|
|
696
|
+
edge,
|
|
697
|
+
first: Math.max(from, (lineage[index + 1]?.forkedAtBlockNumber ?? -1) + 1),
|
|
698
|
+
last: Math.min(to, edge.forkedAtBlockNumber)
|
|
699
|
+
})).filter(({ first, last }) => first <= last).toReversed();
|
|
700
|
+
if (query === void 0 && (result.scopeCompleteness === "verified-native-header-selection-with-domain-exclusions" ? foreign : expected.length) === 0 || result.excludedChainRanges.length !== expected.length) throw new FleetAuthorityError("conflict", "scan-exclusion-coverage");
|
|
701
|
+
for (const [index, range] of result.excludedChainRanges.entries()) validateRange(range, expected[index], profile);
|
|
702
|
+
return query;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// src/fleetPage.ts
|
|
706
|
+
function nativeFailure(page) {
|
|
707
|
+
const statuses = ["cancelled", "deadline", "conflict", "unsupported", "resource-limit"];
|
|
708
|
+
const status = statuses.includes(page.status) ? page.status : "incomplete";
|
|
709
|
+
return new FleetAuthorityError(status, `native-${page.issues[0]?.code ?? page.status}`);
|
|
710
|
+
}
|
|
711
|
+
function validateForkPage(page, profile, request) {
|
|
712
|
+
const clock = page.anchorClock;
|
|
713
|
+
if (page.scope.chainIds?.length !== 1 || page.scope.chainIds[0] !== profile.evidence.chainId || clock?.chainId !== profile.evidence.chainId || clock.network !== profile.evidence.network || clock.genesisRoot !== profile.evidence.genesisRoot || clock.blockNumber !== request.anchor.blockNumber || clock.blockRoot !== request.anchor.blockRoot) throw new FleetAuthorityError("conflict", "scan-current-chain");
|
|
714
|
+
}
|
|
715
|
+
function validateFleetPage(page, profile, request, from, to, scope) {
|
|
716
|
+
const actual = [
|
|
717
|
+
page.network,
|
|
718
|
+
page.chainId,
|
|
719
|
+
page.genesisRoot,
|
|
720
|
+
page.anchor.blockNumber,
|
|
721
|
+
page.anchor.blockRoot,
|
|
722
|
+
page.assurance,
|
|
723
|
+
page.requestedRange.fromBlockNumber,
|
|
724
|
+
page.requestedRange.toBlockNumber
|
|
725
|
+
];
|
|
726
|
+
const expected = [
|
|
727
|
+
profile.evidence.network,
|
|
728
|
+
profile.evidence.chainId,
|
|
729
|
+
profile.evidence.genesisRoot,
|
|
730
|
+
request.anchor.blockNumber,
|
|
731
|
+
request.anchor.blockRoot,
|
|
732
|
+
"source-trusted-finalized-replay",
|
|
733
|
+
from,
|
|
734
|
+
to
|
|
735
|
+
];
|
|
736
|
+
if (actual.some((value, index) => value !== expected[index])) throw new FleetAuthorityError("conflict", "scan-binding");
|
|
737
|
+
if (profile.evidence.querySelection !== void 0 && page.status !== "complete") throw nativeFailure(page);
|
|
738
|
+
const basis = validateScopeMode(page, profile, from, to, scope);
|
|
739
|
+
if (page.scope.authorizers?.length !== 1 || page.scope.authorizers[0] !== request.owner || page.scope.schemas?.length !== scope.schemas.length || page.scope.schemas.some((family, index) => family !== scope.schemas[index])) throw new FleetAuthorityError("conflict", "scan-scope");
|
|
740
|
+
if (page.status !== "complete") throw nativeFailure(page);
|
|
741
|
+
if (profile.evidence.forkLineage !== void 0) validateForkPage(page, profile, request);
|
|
742
|
+
if (page.coveredRange?.fromBlockNumber !== from || page.coveredRange.toBlockNumber !== to || page.continuation !== void 0 || page.issues.length > 0) {
|
|
743
|
+
throw new FleetAuthorityError("incomplete", "scan-coverage");
|
|
744
|
+
}
|
|
745
|
+
return basis;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// src/fleetProjection.ts
|
|
749
|
+
function nextPublisherProjection(result) {
|
|
750
|
+
const { publicationBlock: projectionBlock, ...original } = result;
|
|
751
|
+
const context2 = {
|
|
752
|
+
...original,
|
|
753
|
+
projection: "pending-N+1",
|
|
754
|
+
projectionBlock
|
|
755
|
+
};
|
|
756
|
+
if (result.status === "authorized" || result.status === "absent") {
|
|
757
|
+
return Object.freeze({
|
|
758
|
+
...context2,
|
|
759
|
+
status: result.status === "authorized" ? "projected-granted" : "projected-absent",
|
|
760
|
+
coveredRange: Object.freeze({ fromBlockNumber: 0, toBlockNumber: result.anchor.blockNumber })
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
return Object.freeze(context2);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// src/fleetReaders.ts
|
|
767
|
+
function pinReaders(seeds, profile) {
|
|
768
|
+
if (!Array.isArray(seeds) || seeds.length === 0 || seeds.length > profile.resolutionLimits.maxSeeds) throw new RangeError("Explicit bounded root readers required");
|
|
769
|
+
const ids = /* @__PURE__ */ new Set();
|
|
770
|
+
return Object.freeze(Array.from({ length: seeds.length }, (_, index) => {
|
|
771
|
+
const slot = Object.getOwnPropertyDescriptor(seeds, String(index));
|
|
772
|
+
if (slot?.enumerable !== true || !("value" in slot)) throw new TypeError("Readers require dense own data slots");
|
|
773
|
+
const seed = ownRecord(slot.value, ["id", "reader"]);
|
|
774
|
+
if (typeof seed.id !== "string" || seed.id.length === 0 || seed.id.length > 128 || seed.id.trim() !== seed.id || ids.has(seed.id)) throw new TypeError("Readers require unique bounded IDs");
|
|
775
|
+
ids.add(seed.id);
|
|
776
|
+
const reader = ownRecord(seed.reader, ["get"]);
|
|
777
|
+
if (typeof reader.get !== "function") throw new TypeError("Readers require an own get method");
|
|
778
|
+
const get = reader.get.bind(seed.reader);
|
|
779
|
+
return Object.freeze({ id: seed.id, reader: Object.freeze({ get }) });
|
|
780
|
+
}));
|
|
781
|
+
}
|
|
782
|
+
function capacityReaders(seeds, state, maximum, capacity, meter) {
|
|
783
|
+
return Object.freeze(seeds.map((seed) => Object.freeze({
|
|
784
|
+
id: seed.id,
|
|
785
|
+
reader: Object.freeze({
|
|
786
|
+
get: async (...args) => {
|
|
787
|
+
if (state.active >= maximum) {
|
|
788
|
+
capacity.limited = true;
|
|
789
|
+
throw new FleetAuthorityError("resource-limit", "reader-capacity");
|
|
790
|
+
}
|
|
791
|
+
state.active++;
|
|
792
|
+
try {
|
|
793
|
+
return await (meter === void 0 ? seed.reader.get(...args) : meter.read(seed.reader.get.bind(seed.reader), ...args));
|
|
794
|
+
} finally {
|
|
795
|
+
state.active--;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
})
|
|
799
|
+
})));
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// src/fleetRequests.ts
|
|
803
|
+
import { AddressZod as AddressZod3, HashZod as HashZod4 } from "@xyo-network/service-kit-schemas";
|
|
804
|
+
function pinRequest(input, next = false) {
|
|
805
|
+
const values = ownRecord(input, ["anchor", "owner", "publicationBlock"], ["fleetRoot", "signal", "maxAggregateBytes"]);
|
|
806
|
+
const anchor = ownRecord(values.anchor, ["blockNumber", "blockRoot"]);
|
|
807
|
+
HashZod4.parse(anchor.blockRoot);
|
|
808
|
+
AddressZod3.parse(values.owner);
|
|
809
|
+
if (values.maxAggregateBytes !== void 0 && (typeof values.maxAggregateBytes !== "number" || !Number.isSafeInteger(values.maxAggregateBytes) || values.maxAggregateBytes <= 0)) throw new RangeError("Select a finite positive aggregate request ceiling");
|
|
810
|
+
if (values.fleetRoot !== void 0) HashZod4.parse(values.fleetRoot);
|
|
811
|
+
if (!Number.isSafeInteger(anchor.blockNumber) || anchor.blockNumber < 0 || anchor.blockNumber >= Number.MAX_SAFE_INTEGER || typeof values.publicationBlock !== "number" || !Number.isSafeInteger(values.publicationBlock) || values.publicationBlock < 0 || (next ? values.publicationBlock !== anchor.blockNumber + 1 : values.publicationBlock > anchor.blockNumber)) throw new RangeError("Select an exact publication height within the anchor");
|
|
812
|
+
return Object.freeze({
|
|
813
|
+
...values,
|
|
814
|
+
anchor: Object.freeze(anchor),
|
|
815
|
+
signal: captureSignal(values.signal)
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// src/createFleetAuthority.ts
|
|
820
|
+
var b4Families = Object.freeze([FleetSchema, FleetMemberSchema, FleetPublicationScopeSchema, FleetControlSchema]);
|
|
821
|
+
function context(profile, request) {
|
|
822
|
+
return Object.freeze({
|
|
823
|
+
assurance: "source-trusted-finalized-replay",
|
|
824
|
+
historyScope: "verified-native-owner-and-B4-families",
|
|
825
|
+
network: profile.evidence.network,
|
|
826
|
+
chainId: profile.evidence.chainId,
|
|
827
|
+
genesisRoot: profile.evidence.genesisRoot,
|
|
828
|
+
anchor: request.anchor,
|
|
829
|
+
owner: request.owner,
|
|
830
|
+
publicationBlock: request.publicationBlock
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
function positionAfter(left, right) {
|
|
834
|
+
return left.blockNumber > right.blockNumber || left.blockNumber === right.blockNumber && (left.transactionIndex > right.transactionIndex || left.transactionIndex === right.transactionIndex && left.payloadOrdinal > right.payloadOrdinal);
|
|
835
|
+
}
|
|
836
|
+
function scanCeiling(meter, maximum) {
|
|
837
|
+
return meter === void 0 ? {} : { maxAggregateBytes: Math.min(maximum, meter.remaining()) };
|
|
838
|
+
}
|
|
839
|
+
function createFleetAuthority(input) {
|
|
840
|
+
const profile = pinProfile(input);
|
|
841
|
+
const evidence = createXl1FinalizedPublicationEvidence(profile.evidence);
|
|
842
|
+
const readState = { active: 0 };
|
|
843
|
+
const seeds = pinReaders(profile.seeds, profile);
|
|
844
|
+
let activeCalls = 0;
|
|
845
|
+
const historyDepth = Math.min(2147483647, Math.max(profile.evidence.limits.maxDecodedDepth, profile.resolutionLimits.maxDepth) + 8);
|
|
846
|
+
const history = profile.verifiedHistory === void 0 ? void 0 : new VerifiedFleetHistory(profile.verifiedHistory, historyDepth);
|
|
847
|
+
async function resolved(root, family, work) {
|
|
848
|
+
work.control.assertActive();
|
|
849
|
+
const cached = work.roots.get(root);
|
|
850
|
+
if (cached !== void 0) {
|
|
851
|
+
if (cached.schema !== family) throw new FleetAuthorityError("unsupported", "declaration-family");
|
|
852
|
+
return cached;
|
|
853
|
+
}
|
|
854
|
+
if (work.roots.size >= profile.limits.maxRootReads) throw new FleetAuthorityError("resource-limit", "root-reads");
|
|
855
|
+
const result = await resolveFleetPayload(root, family, {
|
|
856
|
+
seeds: work.seeds,
|
|
857
|
+
signal: work.control.signal,
|
|
858
|
+
limits: { ...profile.resolutionLimits, totalTimeoutMs: Math.min(profile.resolutionLimits.totalTimeoutMs, work.control.remainingMs()) }
|
|
859
|
+
});
|
|
860
|
+
work.control.assertActive();
|
|
861
|
+
if (work.capacity.limited) throw new FleetAuthorityError("resource-limit", "reader-capacity");
|
|
862
|
+
if (result.status !== "verified") {
|
|
863
|
+
if (result.status === "aborted") throw new FleetAuthorityError("cancelled", "root-cancelled");
|
|
864
|
+
if (result.reason === "resource-limit") throw new FleetAuthorityError("resource-limit", "root-resource-limit");
|
|
865
|
+
if (result.reason === "deadline") throw new FleetAuthorityError("deadline", "root-deadline");
|
|
866
|
+
if (result.attempts.some((attempt) => attempt.status === "unsupported")) throw new FleetAuthorityError("unsupported", "root-definition");
|
|
867
|
+
throw new FleetAuthorityError("incomplete", "root-unavailable");
|
|
868
|
+
}
|
|
869
|
+
work.roots.set(root, result.payload);
|
|
870
|
+
if (family !== FleetControlSchema) work.declarations.set(root, Object.freeze({ root, payload: result.payload }));
|
|
871
|
+
return result.payload;
|
|
872
|
+
}
|
|
873
|
+
async function scan(request, work, fromBlockNumber = 0) {
|
|
874
|
+
const { control, meter } = work;
|
|
875
|
+
if (request.anchor.blockNumber + 1 > profile.limits.maxBlocks) throw new FleetAuthorityError("resource-limit", "history-blocks");
|
|
876
|
+
const occurrences = [];
|
|
877
|
+
for (let from = fromBlockNumber; from <= request.anchor.blockNumber; ) {
|
|
878
|
+
control.assertActive();
|
|
879
|
+
if (++work.pages.count > profile.limits.maxPages) throw new FleetAuthorityError("resource-limit", "scan-pages");
|
|
880
|
+
const to = Math.min(request.anchor.blockNumber, from + profile.evidence.limits.maxBlocks - 1);
|
|
881
|
+
const scope = Object.freeze({
|
|
882
|
+
authorizers: Object.freeze([request.owner]),
|
|
883
|
+
schemas: b4Families,
|
|
884
|
+
...profile.evidence.forkLineage !== void 0 && { chainIds: Object.freeze([profile.evidence.chainId]) }
|
|
885
|
+
});
|
|
886
|
+
const page = await evidence.scanScoped({
|
|
887
|
+
anchor: request.anchor,
|
|
888
|
+
fromBlockNumber: from,
|
|
889
|
+
toBlockNumber: to,
|
|
890
|
+
signal: control.signal,
|
|
891
|
+
...scanCeiling(meter, profile.evidence.limits.maxAggregateBytes),
|
|
892
|
+
scope
|
|
893
|
+
});
|
|
894
|
+
chargeNativeResources(meter, page.resources);
|
|
895
|
+
control.assertActive();
|
|
896
|
+
const basis = validateFleetPage(page, profile, request, from, to, scope);
|
|
897
|
+
if (basis !== void 0) work.queryBasis.scopeCompleteness = basis;
|
|
898
|
+
for (const fact of page.occurrences) {
|
|
899
|
+
const previous = occurrences.at(-1);
|
|
900
|
+
if (fact.network !== profile.evidence.network || fact.chainId !== profile.evidence.chainId || fact.genesisRoot !== profile.evidence.genesisRoot || fact.signer !== request.owner || !b4Families.includes(fact.schema) || fact.blockNumber < from || fact.blockNumber > to || previous !== void 0 && !positionAfter(fact, previous)) throw new FleetAuthorityError("conflict", "occurrence-binding-order");
|
|
901
|
+
if (occurrences.length >= profile.limits.maxOccurrences) throw new FleetAuthorityError("resource-limit", "occurrences");
|
|
902
|
+
occurrences.push(fact);
|
|
903
|
+
}
|
|
904
|
+
from = to + 1;
|
|
905
|
+
}
|
|
906
|
+
return occurrences;
|
|
907
|
+
}
|
|
908
|
+
async function original(fact, family, control) {
|
|
909
|
+
const checked = await verifyFleetPayload(fact.payloadRoot, family, fact.body, profile.foldLimits);
|
|
910
|
+
control.assertActive();
|
|
911
|
+
if (checked.status !== "verified") throw new FleetAuthorityError(checked.status === "unsupported" ? "unsupported" : "incomplete", "owner-definition");
|
|
912
|
+
return checked.payload;
|
|
913
|
+
}
|
|
914
|
+
async function discoverFleet(fact, request, work, roots) {
|
|
915
|
+
if (fact.schema !== FleetSchema || request.fleetRoot !== void 0) return;
|
|
916
|
+
const checked = await verifyFleetPayload(fact.payloadRoot, FleetSchema, fact.body, profile.foldLimits);
|
|
917
|
+
work.control.assertActive();
|
|
918
|
+
if (checked.status !== "verified") {
|
|
919
|
+
if (fact.signer === request.owner) throw new FleetAuthorityError(checked.status === "unsupported" ? "unsupported" : "incomplete", "owner-declaration");
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
if (FleetZod.parse(checked.payload).owner === request.owner) roots.add(fact.payloadRoot);
|
|
923
|
+
}
|
|
924
|
+
async function collect(request, work, occurrences) {
|
|
925
|
+
const roots = new Set(request.fleetRoot === void 0 ? [] : [request.fleetRoot]);
|
|
926
|
+
const controls = [];
|
|
927
|
+
for (const fact of occurrences) {
|
|
928
|
+
work.control.assertActive();
|
|
929
|
+
if (fact.blockNumber > request.publicationBlock) continue;
|
|
930
|
+
await discoverFleet(fact, request, work, roots);
|
|
931
|
+
if (fact.schema !== FleetControlSchema || fact.signer !== request.owner || fact.blockNumber === request.publicationBlock) continue;
|
|
932
|
+
const payload = await original(fact, FleetControlSchema, work.control);
|
|
933
|
+
if (request.fleetRoot !== void 0 && payload.fleetRoot !== request.fleetRoot) continue;
|
|
934
|
+
const fleet = FleetZod.parse(await resolved(payload.fleetRoot, FleetSchema, work));
|
|
935
|
+
if (fleet.owner !== request.owner) continue;
|
|
936
|
+
roots.add(payload.fleetRoot);
|
|
937
|
+
await resolved(fact.payloadRoot, FleetControlSchema, work);
|
|
938
|
+
controls.push(Object.freeze({
|
|
939
|
+
root: fact.payloadRoot,
|
|
940
|
+
payload,
|
|
941
|
+
authorizer: fact.signer,
|
|
942
|
+
block: fact.blockNumber,
|
|
943
|
+
chainId: fact.chainId,
|
|
944
|
+
transactionIndex: fact.transactionIndex,
|
|
945
|
+
payloadIndex: fact.payloadOrdinal
|
|
946
|
+
}));
|
|
947
|
+
if ("memberRoot" in payload) await resolved(payload.memberRoot, FleetMemberSchema, work);
|
|
948
|
+
if ("scopeRoot" in payload) await resolved(payload.scopeRoot, FleetPublicationScopeSchema, work);
|
|
949
|
+
if (roots.size > profile.limits.maxFleets) throw new FleetAuthorityError("resource-limit", "fleets");
|
|
950
|
+
}
|
|
951
|
+
if (roots.size > profile.limits.maxFleets) throw new FleetAuthorityError("resource-limit", "fleets");
|
|
952
|
+
return { roots, controls };
|
|
953
|
+
}
|
|
954
|
+
async function foldWork(request, work, occurrences) {
|
|
955
|
+
const { roots, controls } = await collect(request, work, occurrences);
|
|
956
|
+
const views = [];
|
|
957
|
+
for (const root of roots) {
|
|
958
|
+
await resolved(root, FleetSchema, work);
|
|
959
|
+
const selected = controls.filter((fact) => fact.payload.fleetRoot === root);
|
|
960
|
+
const needed = /* @__PURE__ */ new Set([root]);
|
|
961
|
+
for (const fact of selected) {
|
|
962
|
+
if ("memberRoot" in fact.payload) needed.add(fact.payload.memberRoot);
|
|
963
|
+
if ("scopeRoot" in fact.payload) needed.add(fact.payload.scopeRoot);
|
|
964
|
+
}
|
|
965
|
+
const folded = foldFleetControls({
|
|
966
|
+
owner: request.owner,
|
|
967
|
+
fleetRoot: root,
|
|
968
|
+
chainId: profile.evidence.chainId,
|
|
969
|
+
genesisRoot: profile.evidence.genesisRoot,
|
|
970
|
+
publicationBlock: request.publicationBlock,
|
|
971
|
+
controls: selected,
|
|
972
|
+
declarations: [...needed].map((key) => {
|
|
973
|
+
const declaration = work.declarations.get(key);
|
|
974
|
+
if (declaration === void 0) throw new FleetAuthorityError("incomplete", "missing-declaration");
|
|
975
|
+
return declaration;
|
|
976
|
+
}),
|
|
977
|
+
limits: profile.foldLimits,
|
|
978
|
+
signal: work.control.signal
|
|
979
|
+
});
|
|
980
|
+
work.control.assertActive();
|
|
981
|
+
if (folded.status !== "folded") {
|
|
982
|
+
const status = folded.status === "aborted" ? "cancelled" : folded.reason === "resource-limit" ? "resource-limit" : folded.status;
|
|
983
|
+
throw new FleetAuthorityError(status, `fold-${folded.reason}`);
|
|
984
|
+
}
|
|
985
|
+
views.push(Object.freeze({
|
|
986
|
+
...folded,
|
|
987
|
+
status: "complete",
|
|
988
|
+
assurance: "source-trusted-finalized-replay"
|
|
989
|
+
}));
|
|
990
|
+
}
|
|
991
|
+
const basis = work.queryBasis.scopeCompleteness;
|
|
992
|
+
if (profile.evidence.querySelection === void 0 !== (basis === void 0)) throw new FleetAuthorityError("conflict", "history-query-basis");
|
|
993
|
+
const result = Object.freeze({
|
|
994
|
+
...basis !== void 0 && { scopeCompleteness: basis },
|
|
995
|
+
...context(profile, request),
|
|
996
|
+
status: "complete",
|
|
997
|
+
correspondence: "native-sdk-verified",
|
|
998
|
+
history: "complete-genesis-to-anchor",
|
|
999
|
+
coveredRange: Object.freeze({ fromBlockNumber: 0, toBlockNumber: request.anchor.blockNumber }),
|
|
1000
|
+
views: Object.freeze(views)
|
|
1001
|
+
});
|
|
1002
|
+
return { result, controls };
|
|
1003
|
+
}
|
|
1004
|
+
function restore(entry, work) {
|
|
1005
|
+
const expected = profile.evidence.querySelection === void 0 ? void 0 : "verified-block-committed-query-selection";
|
|
1006
|
+
if (entry.scopeCompleteness !== expected) throw new FleetAuthorityError("conflict", "history-query-policy");
|
|
1007
|
+
if (entry.scopeCompleteness !== void 0) work.queryBasis.scopeCompleteness = entry.scopeCompleteness;
|
|
1008
|
+
for (const [root, payload] of entry.roots) {
|
|
1009
|
+
if (!work.roots.has(root) && work.roots.size >= profile.limits.maxRootReads) throw new FleetAuthorityError("resource-limit", "root-reads");
|
|
1010
|
+
work.roots.set(root, payload);
|
|
1011
|
+
if (payload.schema !== FleetControlSchema) work.declarations.set(root, Object.freeze({ root, payload }));
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
async function replayWork(request, work) {
|
|
1015
|
+
const prior = history?.get(request.owner);
|
|
1016
|
+
let occurrences;
|
|
1017
|
+
if (prior === void 0) occurrences = await scan(request, work);
|
|
1018
|
+
else {
|
|
1019
|
+
restore(prior, work);
|
|
1020
|
+
const sameHeight = request.anchor.blockNumber === prior.anchor.blockNumber;
|
|
1021
|
+
if (sameHeight && request.anchor.blockRoot !== prior.anchor.blockRoot) throw new FleetAuthorityError("conflict", "history-anchor");
|
|
1022
|
+
if (sameHeight) occurrences = prior.occurrences;
|
|
1023
|
+
else if (request.anchor.blockNumber < prior.anchor.blockNumber) {
|
|
1024
|
+
await scan(request, work, request.anchor.blockNumber);
|
|
1025
|
+
occurrences = prior.occurrences.filter((fact) => fact.blockNumber <= request.anchor.blockNumber);
|
|
1026
|
+
} else {
|
|
1027
|
+
await scan({ ...request, anchor: prior.anchor }, work, prior.anchor.blockNumber);
|
|
1028
|
+
occurrences = [...prior.occurrences, ...await scan(request, work, prior.anchor.blockNumber + 1)];
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
if (occurrences.length > profile.limits.maxOccurrences) throw new FleetAuthorityError("resource-limit", "occurrences");
|
|
1032
|
+
if (history !== void 0 && (prior === void 0 || request.anchor.blockNumber > prior.anchor.blockNumber)) {
|
|
1033
|
+
const completeRequest = {
|
|
1034
|
+
...request,
|
|
1035
|
+
fleetRoot: void 0,
|
|
1036
|
+
publicationBlock: request.anchor.blockNumber + 1
|
|
1037
|
+
};
|
|
1038
|
+
const complete = await foldWork(completeRequest, work, occurrences);
|
|
1039
|
+
work.control.assertActive();
|
|
1040
|
+
history.publish({
|
|
1041
|
+
owner: request.owner,
|
|
1042
|
+
anchor: request.anchor,
|
|
1043
|
+
occurrences,
|
|
1044
|
+
roots: work.roots.entries().toArray(),
|
|
1045
|
+
...complete.result.scopeCompleteness !== void 0 && { scopeCompleteness: complete.result.scopeCompleteness }
|
|
1046
|
+
});
|
|
1047
|
+
if (request.fleetRoot === void 0 && request.publicationBlock === completeRequest.publicationBlock) return complete;
|
|
1048
|
+
}
|
|
1049
|
+
return await foldWork(request, work, occurrences);
|
|
1050
|
+
}
|
|
1051
|
+
async function enumerateWork(request, work) {
|
|
1052
|
+
const replay = await replayWork(request, work);
|
|
1053
|
+
return replay.result;
|
|
1054
|
+
}
|
|
1055
|
+
async function execute(request, startedAt, operation) {
|
|
1056
|
+
const control = operationControl(request.signal, profile.limits.totalTimeoutMs, startedAt);
|
|
1057
|
+
let admitted = false;
|
|
1058
|
+
let meter;
|
|
1059
|
+
try {
|
|
1060
|
+
const bound = BigInt(profile.limits.maxPages) * BigInt(profile.evidence.limits.maxAggregateBytes) + BigInt(profile.limits.maxRootReads) * BigInt(profile.resolutionLimits.maxSeeds) * BigInt(profile.resolutionLimits.maxBodyBytes);
|
|
1061
|
+
if (request.maxAggregateBytes !== void 0 || profile.evidence.verifiedPrefix !== void 0) {
|
|
1062
|
+
meter = new FleetMeter(request.maxAggregateBytes ?? Number(bound > BigInt(Number.MAX_SAFE_INTEGER) ? BigInt(Number.MAX_SAFE_INTEGER) : bound), profile.resolutionLimits);
|
|
1063
|
+
}
|
|
1064
|
+
if (request.maxAggregateBytes !== void 0 && BigInt(request.maxAggregateBytes) > bound) throw new FleetAuthorityError("resource-limit", "aggregate-ceiling");
|
|
1065
|
+
control.assertActive();
|
|
1066
|
+
if (activeCalls >= profile.limits.maxConcurrentCalls) throw new FleetAuthorityError("resource-limit", "composition-capacity");
|
|
1067
|
+
activeCalls++;
|
|
1068
|
+
admitted = true;
|
|
1069
|
+
const capacity = { limited: false };
|
|
1070
|
+
const result = await operation({
|
|
1071
|
+
control,
|
|
1072
|
+
...meter !== void 0 && { meter },
|
|
1073
|
+
roots: /* @__PURE__ */ new Map(),
|
|
1074
|
+
pages: { count: 0 },
|
|
1075
|
+
queryBasis: {},
|
|
1076
|
+
declarations: /* @__PURE__ */ new Map(),
|
|
1077
|
+
capacity,
|
|
1078
|
+
seeds: capacityReaders(seeds, readState, profile.limits.maxConcurrentReads, capacity, meter)
|
|
1079
|
+
});
|
|
1080
|
+
return meter === void 0 ? result : Object.freeze({ ...result, resources: meter.resources() });
|
|
1081
|
+
} catch (error) {
|
|
1082
|
+
const failure = error instanceof FleetAuthorityError ? error : new FleetAuthorityError("incomplete", "composition-source");
|
|
1083
|
+
return Object.freeze({
|
|
1084
|
+
...context(profile, request),
|
|
1085
|
+
status: failure.status,
|
|
1086
|
+
code: failure.code,
|
|
1087
|
+
...meter !== void 0 && { resources: meter.resources() }
|
|
1088
|
+
});
|
|
1089
|
+
} finally {
|
|
1090
|
+
if (admitted) activeCalls--;
|
|
1091
|
+
meter?.close();
|
|
1092
|
+
control.dispose();
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
async function publisherWork(request, scopeRoot, publisherAddress, work) {
|
|
1096
|
+
const retained = history?.get(request.owner);
|
|
1097
|
+
if (retained !== void 0) restore(retained, work);
|
|
1098
|
+
const scope = FleetPublicationScopeZod.parse(await resolved(scopeRoot, FleetPublicationScopeSchema, work));
|
|
1099
|
+
const result = await enumerateWork({ ...request, fleetRoot: scope.fleetRoot }, work);
|
|
1100
|
+
const basis = result.scopeCompleteness === void 0 ? {} : { scopeCompleteness: result.scopeCompleteness };
|
|
1101
|
+
const view = result.views[0];
|
|
1102
|
+
const matches = view?.fleetActive ? view.grants.filter((grant2) => grant2.scopeRoot === scopeRoot && grant2.publisherAddress === publisherAddress) : [];
|
|
1103
|
+
if (matches.length > 1) throw new FleetAuthorityError("conflict", "publisher-ambiguity");
|
|
1104
|
+
const grant = matches[0];
|
|
1105
|
+
return grant === void 0 ? Object.freeze({
|
|
1106
|
+
...context(profile, request),
|
|
1107
|
+
...basis,
|
|
1108
|
+
status: "absent",
|
|
1109
|
+
correspondence: "native-sdk-verified",
|
|
1110
|
+
history: "complete-genesis-to-anchor",
|
|
1111
|
+
scopeRoot,
|
|
1112
|
+
publisherAddress
|
|
1113
|
+
}) : Object.freeze({
|
|
1114
|
+
...context(profile, request),
|
|
1115
|
+
...basis,
|
|
1116
|
+
status: "authorized",
|
|
1117
|
+
correspondence: "native-sdk-verified",
|
|
1118
|
+
history: "complete-genesis-to-anchor",
|
|
1119
|
+
fleetRoot: scope.fleetRoot,
|
|
1120
|
+
memberRoot: grant.memberRoot,
|
|
1121
|
+
controlRoot: grant.controlRoot,
|
|
1122
|
+
scopeRoot,
|
|
1123
|
+
publisherAddress
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
return Object.freeze({
|
|
1127
|
+
async enumerate(inputRequest) {
|
|
1128
|
+
const startedAt = fleetNow();
|
|
1129
|
+
const request = pinRequest(inputRequest);
|
|
1130
|
+
return await execute(request, startedAt, (work) => enumerateWork(request, work));
|
|
1131
|
+
},
|
|
1132
|
+
async enumerateHistoricalPublishers(inputRequest) {
|
|
1133
|
+
const startedAt = fleetNow();
|
|
1134
|
+
const values = ownRecord(inputRequest, ["anchor", "owner"], ["fleetRoot", "signal", "maxAggregateBytes"]);
|
|
1135
|
+
const anchor = ownRecord(values.anchor, ["blockNumber", "blockRoot"]);
|
|
1136
|
+
const request = pinRequest({
|
|
1137
|
+
...values,
|
|
1138
|
+
anchor,
|
|
1139
|
+
publicationBlock: anchor.blockNumber + 1
|
|
1140
|
+
}, true);
|
|
1141
|
+
let controls = [];
|
|
1142
|
+
const result = await execute(request, startedAt, async (work) => {
|
|
1143
|
+
const replay = await replayWork(request, work);
|
|
1144
|
+
controls = replay.controls;
|
|
1145
|
+
return replay.result;
|
|
1146
|
+
});
|
|
1147
|
+
return historicalPublisherResult(result, controls, request.fleetRoot);
|
|
1148
|
+
},
|
|
1149
|
+
async resolvePublisher(inputRequest) {
|
|
1150
|
+
const startedAt = fleetNow();
|
|
1151
|
+
const values = ownRecord(inputRequest, ["anchor", "owner", "publicationBlock", "publisherAddress", "scopeRoot"], ["signal", "maxAggregateBytes"]);
|
|
1152
|
+
const publisherAddress = AddressZod4.parse(values.publisherAddress);
|
|
1153
|
+
const scopeRoot = HashZod5.parse(values.scopeRoot);
|
|
1154
|
+
const request = pinRequest({
|
|
1155
|
+
anchor: values.anchor,
|
|
1156
|
+
owner: values.owner,
|
|
1157
|
+
publicationBlock: values.publicationBlock,
|
|
1158
|
+
...values.signal !== void 0 && { signal: values.signal },
|
|
1159
|
+
...values.maxAggregateBytes !== void 0 && { maxAggregateBytes: values.maxAggregateBytes }
|
|
1160
|
+
});
|
|
1161
|
+
return await execute(request, startedAt, (work) => publisherWork(request, scopeRoot, publisherAddress, work));
|
|
1162
|
+
},
|
|
1163
|
+
async projectNextPublisher(inputRequest) {
|
|
1164
|
+
const startedAt = fleetNow();
|
|
1165
|
+
const values = ownRecord(inputRequest, ["anchor", "owner", "publisherAddress", "scopeRoot"], ["signal", "maxAggregateBytes"]);
|
|
1166
|
+
const anchor = ownRecord(values.anchor, ["blockNumber", "blockRoot"]);
|
|
1167
|
+
const publisherAddress = AddressZod4.parse(values.publisherAddress);
|
|
1168
|
+
const scopeRoot = HashZod5.parse(values.scopeRoot);
|
|
1169
|
+
const request = pinRequest({
|
|
1170
|
+
anchor,
|
|
1171
|
+
owner: values.owner,
|
|
1172
|
+
publicationBlock: anchor.blockNumber + 1,
|
|
1173
|
+
...values.signal !== void 0 && { signal: values.signal },
|
|
1174
|
+
...values.maxAggregateBytes !== void 0 && { maxAggregateBytes: values.maxAggregateBytes }
|
|
1175
|
+
}, true);
|
|
1176
|
+
const result = await execute(request, startedAt, (work) => publisherWork(request, scopeRoot, publisherAddress, work));
|
|
1177
|
+
return nextPublisherProjection(result);
|
|
1178
|
+
}
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1
1182
|
// src/createXl1DataLakeSeed.ts
|
|
2
1183
|
import { createRestDataLakeViewer } from "@xyo-network/xl1-sdk/providers";
|
|
3
1184
|
|
|
@@ -52,18 +1233,18 @@ function endpointPolicy(value) {
|
|
|
52
1233
|
return value;
|
|
53
1234
|
}
|
|
54
1235
|
function parsedEndpoint(value, policyValue) {
|
|
55
|
-
const
|
|
1236
|
+
const text2 = endpointText(value);
|
|
56
1237
|
const policy = endpointPolicy(policyValue);
|
|
57
1238
|
let parsed;
|
|
58
1239
|
try {
|
|
59
|
-
parsed = new URL(
|
|
1240
|
+
parsed = new URL(text2);
|
|
60
1241
|
} catch {
|
|
61
1242
|
throw new TypeError("endpoint must be an unambiguous absolute HTTP(S) URL");
|
|
62
1243
|
}
|
|
63
1244
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.hostname === "" || parsed.username !== "" || parsed.password !== "") {
|
|
64
1245
|
throw new TypeError("endpoint must be an unambiguous absolute HTTP(S) URL");
|
|
65
1246
|
}
|
|
66
|
-
const inputWithoutTrailingSlashes =
|
|
1247
|
+
const inputWithoutTrailingSlashes = text2.replace(/\/+$/u, "");
|
|
67
1248
|
const parsedWithoutTrailingSlashes = parsed.href.replace(/\/+$/u, "");
|
|
68
1249
|
if (parsedWithoutTrailingSlashes !== inputWithoutTrailingSlashes) {
|
|
69
1250
|
throw new TypeError("endpoint must not require URL normalization");
|
|
@@ -134,6 +1315,10 @@ async function createXl1DataLakeSeed(options) {
|
|
|
134
1315
|
});
|
|
135
1316
|
}
|
|
136
1317
|
export {
|
|
137
|
-
|
|
1318
|
+
createFleetAuthority,
|
|
1319
|
+
createXl1DataLakeSeed,
|
|
1320
|
+
snapshotFleetQuerySelection,
|
|
1321
|
+
snapshotFleetSelectedPayloadSource,
|
|
1322
|
+
snapshotFleetVerifiedHistory
|
|
138
1323
|
};
|
|
139
1324
|
//# sourceMappingURL=index.mjs.map
|