@polkadot-api/metadata-builders 0.2.0 → 0.3.1

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/dist/index.mjs CHANGED
@@ -6,8 +6,7 @@ var getLookupFn = (lookupData) => {
6
6
  const withCache2 = (fn) => {
7
7
  return (id) => {
8
8
  let entry = lookups.get(id);
9
- if (entry)
10
- return entry;
9
+ if (entry) return entry;
11
10
  if (from.has(id)) {
12
11
  const entry2 = {
13
12
  id
@@ -36,8 +35,7 @@ var getLookupFn = (lookupData) => {
36
35
  const getLookupEntryDef = withCache2((id) => {
37
36
  const { def, path, params } = lookupData[id];
38
37
  if (def.tag === "composite") {
39
- if (def.value.length === 0)
40
- return { type: "void" };
38
+ if (def.value.length === 0) return { type: "void" };
41
39
  if (def.value.length === 1) {
42
40
  const inner = getLookupEntryDef(def.value[0].type);
43
41
  if (isAccountId32SearchOn && path.at(-1) === "AccountId32" && isBytes(inner, 32)) {
@@ -90,8 +88,7 @@ var getLookupFn = (lookupData) => {
90
88
  }
91
89
  };
92
90
  }
93
- if (def.value.length === 0)
94
- return { type: "void" };
91
+ if (def.value.length === 0) return { type: "void" };
95
92
  const enumValue = {};
96
93
  const enumDocs = {};
97
94
  def.value.forEach((x) => {
@@ -118,17 +115,29 @@ var getLookupFn = (lookupData) => {
118
115
  values[key2] = getLookupEntryDef(x2.type);
119
116
  innerDocs[key2] = x2.docs;
120
117
  });
121
- enumValue[key] = allKey ? {
122
- type: "struct",
123
- value: values,
124
- innerDocs,
125
- idx: x.index
126
- } : {
127
- type: "tuple",
128
- value: Object.values(values),
129
- innerDocs: Object.values(innerDocs),
130
- idx: x.index
131
- };
118
+ if (allKey) {
119
+ enumValue[key] = {
120
+ type: "struct",
121
+ value: values,
122
+ innerDocs,
123
+ idx: x.index
124
+ };
125
+ } else {
126
+ const valuesArr = Object.values(values);
127
+ const innerDocsArr = Object.values(innerDocs);
128
+ const areAllSame = valuesArr.every((v) => v.id === valuesArr[0].id);
129
+ enumValue[key] = areAllSame && innerDocsArr.every((doc) => doc.length === 0) ? {
130
+ type: "array",
131
+ value: valuesArr[0],
132
+ len: valuesArr.length,
133
+ idx: x.index
134
+ } : {
135
+ type: "tuple",
136
+ value: valuesArr,
137
+ innerDocs: innerDocsArr,
138
+ idx: x.index
139
+ };
140
+ }
132
141
  });
133
142
  return {
134
143
  type: "enum",
@@ -146,10 +155,8 @@ var getLookupFn = (lookupData) => {
146
155
  if (def.tag === "array") {
147
156
  const { len } = def.value;
148
157
  const value = getLookupEntryDef(def.value.type);
149
- if (len === 0)
150
- return { type: "void" };
151
- if (len === 1)
152
- return value;
158
+ if (len === 0) return { type: "void" };
159
+ if (len === 1) return value;
153
160
  return {
154
161
  type: "array",
155
162
  value,
@@ -157,8 +164,7 @@ var getLookupFn = (lookupData) => {
157
164
  };
158
165
  }
159
166
  if (def.tag === "tuple") {
160
- if (def.value.length === 0)
161
- return { type: "void" };
167
+ if (def.value.length === 0) return { type: "void" };
162
168
  if (def.value.length === 1)
163
169
  return getLookupEntryDef(def.value[0]);
164
170
  const value = def.value.map((x) => getLookupEntryDef(x));
@@ -185,8 +191,7 @@ var getLookupFn = (lookupData) => {
185
191
  }
186
192
  if (def.tag === "compact") {
187
193
  const translated = getLookupEntryDef(def.value);
188
- if (translated.type === "void")
189
- return { type: "compact", isBig: null };
194
+ if (translated.type === "void") return { type: "compact", isBig: null };
190
195
  const isBig = Number(translated.value.slice(1)) > 32;
191
196
  return {
192
197
  type: "compact",
@@ -206,8 +211,7 @@ import * as scale from "@polkadot-api/substrate-bindings";
206
211
  // src/with-cache.ts
207
212
  var withCache = (fn, onEnterCircular, onExitCircular) => (input, cache, stack, ...rest) => {
208
213
  const { id } = input;
209
- if (cache.has(id))
210
- return cache.get(id);
214
+ if (cache.has(id)) return cache.get(id);
211
215
  if (stack.has(id)) {
212
216
  const res = onEnterCircular(() => cache.get(id), input, ...rest);
213
217
  cache.set(id, res);
@@ -226,18 +230,12 @@ var withCache = (fn, onEnterCircular, onExitCircular) => (input, cache, stack, .
226
230
  import { mapObject } from "@polkadot-api/utils";
227
231
  var _bytes = scale.Bin();
228
232
  var _buildCodec = (input, cache, stack, _accountId) => {
229
- if (input.type === "primitive")
230
- return scale[input.value];
231
- if (input.type === "void")
232
- return scale._void;
233
- if (input.type === "AccountId32")
234
- return _accountId;
235
- if (input.type === "AccountId20")
236
- return scale.ethAccount;
237
- if (input.type === "compact")
238
- return scale.compact;
239
- if (input.type === "bitSequence")
240
- return scale.bitSequence;
233
+ if (input.type === "primitive") return scale[input.value];
234
+ if (input.type === "void") return scale._void;
235
+ if (input.type === "AccountId32") return _accountId;
236
+ if (input.type === "AccountId20") return scale.ethAccount;
237
+ if (input.type === "compact") return scale.compact;
238
+ if (input.type === "bitSequence") return scale.bitSequence;
241
239
  const buildNextCodec = (nextInput) => buildCodec(nextInput, cache, stack, _accountId);
242
240
  const buildVector = (inner2, len) => {
243
241
  const innerCodec = buildNextCodec(inner2);
@@ -258,25 +256,28 @@ var _buildCodec = (input, cache, stack, _accountId) => {
258
256
  return scale.Bin(input.len);
259
257
  return buildVector(input.value, input.len);
260
258
  }
261
- if (input.type === "sequence")
262
- return buildVector(input.value);
263
- if (input.type === "tuple")
264
- return buildTuple(input.value);
265
- if (input.type === "struct")
266
- return buildStruct(input.value);
267
- if (input.type === "option")
268
- return scale.Option(buildNextCodec(input.value));
259
+ if (input.type === "sequence") return buildVector(input.value);
260
+ if (input.type === "tuple") return buildTuple(input.value);
261
+ if (input.type === "struct") return buildStruct(input.value);
262
+ if (input.type === "option") return scale.Option(buildNextCodec(input.value));
269
263
  if (input.type === "result")
270
264
  return scale.Result(
271
265
  buildNextCodec(input.value.ok),
272
266
  buildNextCodec(input.value.ko)
273
267
  );
274
268
  const dependencies = Object.values(input.value).map((v) => {
275
- if (v.type === "void")
276
- return scale._void;
277
- if (v.type === "lookupEntry")
278
- return buildNextCodec(v.value);
279
- return v.type === "tuple" ? buildTuple(v.value) : buildStruct(v.value);
269
+ switch (v.type) {
270
+ case "void":
271
+ return scale._void;
272
+ case "lookupEntry":
273
+ return buildNextCodec(v.value);
274
+ case "tuple":
275
+ return buildTuple(v.value);
276
+ case "struct":
277
+ return buildStruct(v.value);
278
+ case "array":
279
+ return buildVector(v.value, v.len);
280
+ }
280
281
  });
281
282
  const inner = Object.fromEntries(
282
283
  Object.keys(input.value).map((key, idx) => {
@@ -329,24 +330,42 @@ var getDynamicBuilder = (metadata) => {
329
330
  const { key, value, hashers } = storageEntry.type.value;
330
331
  const val = buildDefinition(value);
331
332
  const hashes = hashers.map((x) => scale[x.tag]);
332
- const hashArgs = hashes.length === 1 ? [[buildDefinition(key), hashes[0]]] : getLookupEntryDef(key).value.map(
333
- (x, idx) => [
334
- buildDefinition(x.id),
335
- hashes[idx]
336
- ]
337
- );
333
+ const hashArgs = (() => {
334
+ if (hashes.length === 1) {
335
+ return [[buildDefinition(key), hashes[0]]];
336
+ }
337
+ const keyDef = getLookupEntryDef(key);
338
+ switch (keyDef.type) {
339
+ case "array":
340
+ return hashes.map((hash) => [buildDefinition(keyDef.value.id), hash]);
341
+ case "tuple":
342
+ return keyDef.value.map((x, idx) => [
343
+ buildDefinition(x.id),
344
+ hashes[idx]
345
+ ]);
346
+ default:
347
+ throw new Error("Invalid key type");
348
+ }
349
+ })();
338
350
  return storageWithFallback(hashes.length, entry, val.dec, ...hashArgs);
339
351
  };
340
352
  const buildEnumEntry = (entry) => {
341
- if (entry.type === "void")
342
- return scale._void;
343
- if (entry.type === "lookupEntry")
344
- return buildDefinition(entry.value.id);
345
- return entry.type === "tuple" ? scale.Tuple(
346
- ...Object.values(entry.value).map((l) => buildDefinition(l.id))
347
- ) : scale.Struct(
348
- mapObject(entry.value, (x) => buildDefinition(x.id))
349
- );
353
+ switch (entry.type) {
354
+ case "void":
355
+ return scale._void;
356
+ case "lookupEntry":
357
+ return buildDefinition(entry.value.id);
358
+ case "tuple":
359
+ return scale.Tuple(
360
+ ...Object.values(entry.value).map((l) => buildDefinition(l.id))
361
+ );
362
+ case "struct":
363
+ return scale.Struct(
364
+ mapObject(entry.value, (x) => buildDefinition(x.id))
365
+ );
366
+ case "array":
367
+ return scale.Vector(buildDefinition(entry.value.id), entry.len);
368
+ }
350
369
  };
351
370
  const buildConstant = (pallet, constantName) => {
352
371
  const storageEntry = metadata.pallets.find((x) => x.name === pallet).constants.find((s) => s.name === constantName);
@@ -355,8 +374,7 @@ var getDynamicBuilder = (metadata) => {
355
374
  const buildVariant = (type) => (pallet, name) => {
356
375
  const palletEntry = metadata.pallets.find((x) => x.name === pallet);
357
376
  const lookup = getLookupEntryDef(palletEntry[type]);
358
- if (lookup.type !== "enum")
359
- throw null;
377
+ if (lookup.type !== "enum") throw null;
360
378
  const entry = lookup.value[name];
361
379
  return {
362
380
  location: [palletEntry.index, entry.idx],
@@ -365,8 +383,7 @@ var getDynamicBuilder = (metadata) => {
365
383
  };
366
384
  const buildRuntimeCall = (api, method) => {
367
385
  const entry = metadata.apis.find((x) => x.name === api)?.methods.find((x) => x.name === method);
368
- if (!entry)
369
- throw null;
386
+ if (!entry) throw null;
370
387
  return {
371
388
  args: scale.Tuple(...entry.inputs.map((x) => buildDefinition(x.type))),
372
389
  value: buildDefinition(entry.output)
@@ -386,13 +403,174 @@ var getDynamicBuilder = (metadata) => {
386
403
 
387
404
  // src/checksum-builder.ts
388
405
  import { h64 } from "@polkadot-api/substrate-bindings";
406
+
407
+ // src/lookup-graph.ts
408
+ function buildLookupGraph(lookupFn, lookupLength) {
409
+ const result = /* @__PURE__ */ new Map();
410
+ const visited = /* @__PURE__ */ new Set();
411
+ const addEdge = (from, to) => {
412
+ if (!result.has(from))
413
+ result.set(from, {
414
+ entry: lookupFn(from),
415
+ backRefs: /* @__PURE__ */ new Set(),
416
+ refs: /* @__PURE__ */ new Set()
417
+ });
418
+ if (!result.has(to))
419
+ result.set(to, {
420
+ entry: lookupFn(to),
421
+ backRefs: /* @__PURE__ */ new Set(),
422
+ refs: /* @__PURE__ */ new Set()
423
+ });
424
+ result.get(from).refs.add(to);
425
+ result.get(to).backRefs.add(from);
426
+ };
427
+ for (let i = 0; i < lookupLength; i++) {
428
+ const entry = lookupFn(i);
429
+ if (i !== entry.id) {
430
+ addEdge(i, entry.id);
431
+ }
432
+ if (visited.has(entry.id)) continue;
433
+ visited.add(entry.id);
434
+ switch (entry.type) {
435
+ case "array":
436
+ case "option":
437
+ case "sequence":
438
+ addEdge(entry.id, entry.value.id);
439
+ break;
440
+ case "enum":
441
+ Object.values(entry.value).forEach((enumEntry) => {
442
+ switch (enumEntry.type) {
443
+ case "array":
444
+ case "lookupEntry":
445
+ addEdge(entry.id, enumEntry.value.id);
446
+ break;
447
+ case "struct":
448
+ case "tuple":
449
+ Object.values(enumEntry.value).forEach(
450
+ (v) => addEdge(entry.id, v.id)
451
+ );
452
+ break;
453
+ }
454
+ });
455
+ break;
456
+ case "result":
457
+ addEdge(entry.id, entry.value.ok.id);
458
+ addEdge(entry.id, entry.value.ko.id);
459
+ break;
460
+ case "struct":
461
+ case "tuple":
462
+ Object.values(entry.value).forEach((v) => addEdge(entry.id, v.id));
463
+ break;
464
+ }
465
+ if (!result.has(entry.id)) {
466
+ result.set(entry.id, {
467
+ backRefs: /* @__PURE__ */ new Set(),
468
+ refs: /* @__PURE__ */ new Set(),
469
+ entry
470
+ });
471
+ }
472
+ }
473
+ return result;
474
+ }
475
+ var subgraphCache = /* @__PURE__ */ new WeakMap();
476
+ function _getSubgraph(id, graph, result, cache) {
477
+ if (result.has(id)) return;
478
+ const node = graph.get(id);
479
+ result.set(id, node);
480
+ cache.set(id, result);
481
+ node.refs.forEach((ref) => _getSubgraph(ref, graph, result, cache));
482
+ node.backRefs.forEach((ref) => _getSubgraph(ref, graph, result, cache));
483
+ }
484
+ function getSubgraph(id, graph) {
485
+ if (!subgraphCache.has(graph)) {
486
+ subgraphCache.set(graph, /* @__PURE__ */ new Map());
487
+ }
488
+ const cache = subgraphCache.get(graph);
489
+ if (cache.has(id)) return cache.get(id);
490
+ const result = /* @__PURE__ */ new Map();
491
+ _getSubgraph(id, graph, result, cache);
492
+ return result;
493
+ }
494
+ function getStronglyConnectedComponents(graph) {
495
+ const tarjanState = /* @__PURE__ */ new Map();
496
+ let index = 0;
497
+ const stack = [];
498
+ const result = [];
499
+ function strongConnect(v) {
500
+ const state = {
501
+ index,
502
+ lowLink: index,
503
+ onStack: true
504
+ };
505
+ tarjanState.set(v, state);
506
+ index++;
507
+ stack.push(v);
508
+ const edges = graph.get(v).refs;
509
+ for (let w of edges) {
510
+ const edgeState = tarjanState.get(w);
511
+ if (!edgeState) {
512
+ strongConnect(w);
513
+ state.lowLink = Math.min(state.lowLink, tarjanState.get(w).lowLink);
514
+ } else if (edgeState.onStack) {
515
+ state.lowLink = Math.min(state.lowLink, edgeState.index);
516
+ }
517
+ }
518
+ if (state.lowLink === state.index) {
519
+ const component = /* @__PURE__ */ new Set();
520
+ let poppedNode = -1;
521
+ do {
522
+ poppedNode = stack.pop();
523
+ tarjanState.get(poppedNode).onStack = false;
524
+ component.add(poppedNode);
525
+ } while (poppedNode !== v);
526
+ if (component.size > 1) result.push(component);
527
+ }
528
+ }
529
+ for (const node of graph.keys()) {
530
+ if (!tarjanState.has(node)) {
531
+ strongConnect(node);
532
+ }
533
+ }
534
+ return result;
535
+ }
536
+ function mergeSCCsWithCommonNodes(stronglyConnectedComponents) {
537
+ const scc = stronglyConnectedComponents;
538
+ const ungroupedCycles = new Set(scc.map((_, i) => i));
539
+ const edges = new Map(scc.map((_, i) => [i, /* @__PURE__ */ new Set()]));
540
+ scc.forEach((cycle, i) => {
541
+ scc.slice(i + 1).forEach((otherCycle, _j) => {
542
+ const j = _j + i + 1;
543
+ const combined = /* @__PURE__ */ new Set([...cycle, ...otherCycle]);
544
+ if (combined.size !== cycle.size + otherCycle.size) {
545
+ edges.get(i).add(j);
546
+ edges.get(j).add(i);
547
+ }
548
+ });
549
+ });
550
+ const groups = [];
551
+ while (ungroupedCycles.size) {
552
+ const group = /* @__PURE__ */ new Set();
553
+ const toVisit = [ungroupedCycles.values().next().value];
554
+ while (toVisit.length) {
555
+ const idx = toVisit.pop();
556
+ if (!ungroupedCycles.has(idx)) continue;
557
+ ungroupedCycles.delete(idx);
558
+ const cycle = scc[idx];
559
+ cycle.forEach((v) => group.add(Number(v)));
560
+ edges.get(idx).forEach((n) => toVisit.push(n));
561
+ }
562
+ groups.push(group);
563
+ }
564
+ return groups;
565
+ }
566
+
567
+ // src/checksum-builder.ts
389
568
  var textEncoder = new TextEncoder();
390
569
  var encodeText = textEncoder.encode.bind(textEncoder);
391
570
  var getChecksum = (values) => {
392
571
  const res = new Uint8Array(values.length * 8);
393
572
  const dv = new DataView(res.buffer);
394
- for (let i = 0; i < values.length; i++)
395
- dv.setBigUint64(i * 8, values[i]);
573
+ for (let i = 0; i < values.length; i++) dv.setBigUint64(i * 8, values[i]);
396
574
  return h64(res);
397
575
  };
398
576
  var getStringChecksum = (values) => getChecksum(values.map((v) => h64(encodeText(v))));
@@ -448,61 +626,10 @@ var structLikeBuilder = (shapeId, input, innerChecksum) => {
448
626
  );
449
627
  return getChecksum([shapeId, keysChecksum, valuesChecksum]);
450
628
  };
451
- var buildGraph = (entry, result = /* @__PURE__ */ new Map()) => {
452
- if (result.has(entry.id))
453
- return result;
454
- switch (entry.type) {
455
- case "array":
456
- case "option":
457
- case "sequence":
458
- result.set(entry.id, [entry, /* @__PURE__ */ new Set([entry.value.id])]);
459
- buildGraph(entry.value, result);
460
- break;
461
- case "enum": {
462
- const children = Object.values(entry.value).flatMap((value) => {
463
- if (value.type === "void")
464
- return [];
465
- if (value.type === "lookupEntry")
466
- return value.value;
467
- if (value.type === "struct")
468
- return Object.values(value.value);
469
- return value.value;
470
- });
471
- result.set(entry.id, [entry, new Set(children.map((child) => child.id))]);
472
- children.forEach((child) => buildGraph(child, result));
473
- break;
474
- }
475
- case "result":
476
- result.set(entry.id, [
477
- entry,
478
- /* @__PURE__ */ new Set([entry.value.ok.id, entry.value.ko.id])
479
- ]);
480
- buildGraph(entry.value.ok, result);
481
- buildGraph(entry.value.ko, result);
482
- break;
483
- case "struct": {
484
- const children = Object.values(entry.value);
485
- result.set(entry.id, [entry, new Set(children.map((child) => child.id))]);
486
- children.forEach((child) => buildGraph(child, result));
487
- break;
488
- }
489
- case "tuple":
490
- result.set(entry.id, [
491
- entry,
492
- new Set(entry.value.map((child) => child.id))
493
- ]);
494
- entry.value.forEach((child) => buildGraph(child, result));
495
- break;
496
- default:
497
- result.set(entry.id, [entry, /* @__PURE__ */ new Set()]);
498
- }
499
- return result;
500
- };
501
629
  var _buildChecksum = (input, buildNextChecksum) => {
502
630
  if (input.type === "primitive")
503
631
  return getChecksum([shapeIds.primitive, metadataPrimitiveIds[input.value]]);
504
- if (input.type === "void")
505
- return getChecksum([shapeIds.void]);
632
+ if (input.type === "void") return getChecksum([shapeIds.void]);
506
633
  if (input.type === "compact")
507
634
  return getChecksum([
508
635
  shapeIds.primitive,
@@ -516,6 +643,12 @@ var _buildChecksum = (input, buildNextChecksum) => {
516
643
  if (input.type === "AccountId20") {
517
644
  return getChecksum([shapeIds.primitive, runtimePrimitiveIds.accountId20]);
518
645
  }
646
+ const buildVector = (entry, length) => {
647
+ const innerChecksum = buildNextChecksum(entry);
648
+ return getChecksum(
649
+ length !== void 0 ? [shapeIds.vector, innerChecksum, BigInt(length)] : [shapeIds.vector, innerChecksum]
650
+ );
651
+ };
519
652
  if (input.type === "array") {
520
653
  const innerValue = input.value;
521
654
  if (innerValue.type === "primitive" && innerValue.value === "u8") {
@@ -525,23 +658,19 @@ var _buildChecksum = (input, buildNextChecksum) => {
525
658
  BigInt(input.len)
526
659
  ]);
527
660
  }
528
- const innerChecksum = buildNextChecksum(innerValue);
529
- return getChecksum([shapeIds.vector, innerChecksum, BigInt(input.len)]);
661
+ return buildVector(innerValue, input.len);
530
662
  }
531
663
  if (input.type === "sequence") {
532
664
  const innerValue = input.value;
533
665
  if (innerValue.type === "primitive" && innerValue.value === "u8") {
534
666
  return getChecksum([shapeIds.primitive, runtimePrimitiveIds.byteSequence]);
535
667
  }
536
- const innerChecksum = buildNextChecksum(innerValue);
537
- return getChecksum([shapeIds.vector, innerChecksum]);
668
+ return buildVector(innerValue);
538
669
  }
539
670
  const buildTuple = (entries) => getChecksum([shapeIds.tuple, ...entries.map(buildNextChecksum)]);
540
671
  const buildStruct = (entries) => structLikeBuilder(shapeIds.struct, entries, buildNextChecksum);
541
- if (input.type === "tuple")
542
- return buildTuple(input.value);
543
- if (input.type === "struct")
544
- return buildStruct(input.value);
672
+ if (input.type === "tuple") return buildTuple(input.value);
673
+ if (input.type === "struct") return buildStruct(input.value);
545
674
  if (input.type === "option")
546
675
  return getChecksum([shapeIds.option, buildNextChecksum(input.value)]);
547
676
  if (input.type === "result")
@@ -551,8 +680,7 @@ var _buildChecksum = (input, buildNextChecksum) => {
551
680
  buildNextChecksum(input.value.ko)
552
681
  ]);
553
682
  return structLikeBuilder(shapeIds.enum, input.value, (entry) => {
554
- if (entry.type === "lookupEntry")
555
- return buildNextChecksum(entry.value);
683
+ if (entry.type === "lookupEntry") return buildNextChecksum(entry.value);
556
684
  switch (entry.type) {
557
685
  case "void":
558
686
  return getChecksum([shapeIds.void]);
@@ -560,147 +688,129 @@ var _buildChecksum = (input, buildNextChecksum) => {
560
688
  return buildTuple(entry.value);
561
689
  case "struct":
562
690
  return buildStruct(entry.value);
691
+ case "array":
692
+ return buildVector(entry.value, entry.len);
563
693
  }
564
694
  });
565
695
  };
566
- var getCycles = (graph) => {
567
- const tarjanState = /* @__PURE__ */ new Map();
568
- let index = 0;
569
- const stack = [];
570
- const result = [];
571
- function strongConnect(v) {
572
- const state = {
573
- index,
574
- lowLink: index,
575
- onStack: true
576
- };
577
- tarjanState.set(v, state);
578
- index++;
579
- stack.push(v);
580
- const edges = graph.get(v)[1];
581
- for (let w of edges) {
582
- const edgeState = tarjanState.get(w);
583
- if (!edgeState) {
584
- strongConnect(w);
585
- state.lowLink = Math.min(state.lowLink, tarjanState.get(w).lowLink);
586
- } else if (edgeState.onStack) {
587
- state.lowLink = Math.min(state.lowLink, edgeState.index);
588
- }
589
- }
590
- if (state.lowLink === state.index) {
591
- const component = /* @__PURE__ */ new Set();
592
- let poppedNode = -1;
593
- do {
594
- poppedNode = stack.pop();
595
- tarjanState.get(poppedNode).onStack = false;
596
- component.add(poppedNode);
597
- } while (poppedNode !== v);
598
- if (component.size > 1)
599
- result.push(component);
600
- }
601
- }
602
- for (const node of graph.keys()) {
603
- if (!tarjanState.has(node)) {
604
- strongConnect(node);
605
- }
606
- }
607
- return result;
608
- };
609
- var getCyclicGroups = (cycles) => {
610
- const ungroupedCycles = new Set(cycles.map((_, i) => i));
611
- const edges = new Map(cycles.map((_, i) => [i, /* @__PURE__ */ new Set()]));
612
- cycles.forEach((cycle, i) => {
613
- cycles.slice(i + 1).forEach((otherCycle, _j) => {
614
- const j = _j + i + 1;
615
- const combined = /* @__PURE__ */ new Set([...cycle, ...otherCycle]);
616
- if (combined.size !== cycle.size + otherCycle.size) {
617
- edges.get(i).add(j);
618
- edges.get(j).add(i);
619
- }
620
- });
621
- });
622
- const groups = [];
623
- while (ungroupedCycles.size) {
624
- const group = /* @__PURE__ */ new Set();
625
- const toVisit = [ungroupedCycles.values().next().value];
626
- while (toVisit.length) {
627
- const idx = toVisit.pop();
628
- if (!ungroupedCycles.has(idx))
629
- continue;
630
- ungroupedCycles.delete(idx);
631
- const cycle = cycles[idx];
632
- cycle.forEach((v) => group.add(Number(v)));
633
- edges.get(idx).forEach((n) => toVisit.push(n));
634
- }
635
- groups.push(group);
636
- }
637
- return groups;
638
- };
639
696
  var sortCyclicGroups = (groups, graph) => {
640
697
  const getReachableNodes = (group) => {
641
- const first = group.values().next().value;
642
- const entry = graph.get(first)[0];
643
- return Array.from(buildGraph(entry).keys());
698
+ const result2 = /* @__PURE__ */ new Set();
699
+ const toVisit = Array.from(group);
700
+ while (toVisit.length) {
701
+ const id = toVisit.pop();
702
+ if (result2.has(id)) continue;
703
+ result2.add(id);
704
+ graph.get(id)?.refs.forEach((id2) => toVisit.push(id2));
705
+ }
706
+ return Array.from(result2);
644
707
  };
645
708
  const result = new Array();
646
709
  function dependentsFirst(group) {
647
- if (result.includes(group))
648
- return;
710
+ if (result.includes(group)) return;
649
711
  const dependents = groups.filter(
650
712
  (candidate) => candidate !== group && getReachableNodes(group).some((node) => candidate.has(node))
651
713
  );
652
714
  dependents.forEach((group2) => dependentsFirst(group2));
653
- if (result.includes(group))
654
- return;
715
+ if (result.includes(group)) return;
655
716
  result.push(group);
656
717
  }
657
718
  groups.forEach((group) => dependentsFirst(group));
658
719
  return result;
659
720
  };
660
- var buildChecksum = (entry, cache) => {
661
- if (cache.has(entry.id))
662
- return cache.get(entry.id);
663
- const graph = buildGraph(entry);
664
- const cycles = getCycles(graph);
665
- const cyclicGroups = getCyclicGroups(cycles);
666
- const sortedCyclicGroups = sortCyclicGroups(cyclicGroups, graph);
667
- const recursiveBuildChecksum = (entry2, writeCache, skipCache = false) => {
668
- if (!skipCache && cache.has(entry2.id)) {
669
- return cache.get(entry2.id);
721
+ function iterateChecksums(group, iterations, cache, graph) {
722
+ const groupReadCache = new Map([...group].map((id) => [id, 0n]));
723
+ const groupWriteCache = /* @__PURE__ */ new Map();
724
+ const recursiveBuildChecksum = (entry, skipCache = true) => {
725
+ if (!skipCache && (groupReadCache.has(entry.id) || cache.has(entry.id))) {
726
+ return groupReadCache.get(entry.id) ?? cache.get(entry.id);
670
727
  }
671
728
  const result = _buildChecksum(
672
- entry2,
673
- (nextEntry) => recursiveBuildChecksum(nextEntry, writeCache)
729
+ entry,
730
+ (nextEntry) => recursiveBuildChecksum(nextEntry, false)
674
731
  );
675
- writeCache(entry2.id, result);
732
+ if (group.has(entry.id)) {
733
+ groupWriteCache.set(entry.id, result);
734
+ } else {
735
+ cache.set(entry.id, result);
736
+ }
676
737
  return result;
677
738
  };
739
+ for (let i = 0; i < iterations; i++) {
740
+ group.forEach((id) => recursiveBuildChecksum(graph.get(id).entry));
741
+ group.forEach((id) => groupReadCache.set(id, groupWriteCache.get(id)));
742
+ }
743
+ return groupReadCache;
744
+ }
745
+ function getMirroredNodes(cyclicGroups, graph) {
746
+ const maxSize = cyclicGroups.reduce(
747
+ (acc, group) => Math.max(acc, group.size),
748
+ 0
749
+ );
750
+ const allEntries = new Set([...graph.values()].map((v) => v.entry.id));
751
+ const resultingChecksums = iterateChecksums(
752
+ allEntries,
753
+ maxSize,
754
+ // Cache won't be used, since it's using the internal one for every node.
755
+ /* @__PURE__ */ new Map(),
756
+ graph
757
+ );
758
+ const checksumToNodes = /* @__PURE__ */ new Map();
759
+ for (const id of allEntries) {
760
+ const checksum = resultingChecksums.get(id);
761
+ if (checksum == void 0) throw new Error("Unreachable");
762
+ if (!checksumToNodes.has(checksum)) {
763
+ checksumToNodes.set(checksum, []);
764
+ }
765
+ checksumToNodes.get(checksum).push(id);
766
+ }
767
+ const checksumsWithDuplicates = [...checksumToNodes.entries()].filter(
768
+ ([, nodes]) => nodes.length > 1
769
+ );
770
+ const duplicatesMap = {};
771
+ checksumsWithDuplicates.forEach(([, nodes]) => {
772
+ nodes.forEach((n) => duplicatesMap[n] = nodes);
773
+ });
774
+ return duplicatesMap;
775
+ }
776
+ var buildChecksum = (entry, cache, graph) => {
777
+ if (cache.has(entry.id)) return cache.get(entry.id);
778
+ const subGraph = getSubgraph(entry.id, graph);
779
+ const cycles = getStronglyConnectedComponents(subGraph);
780
+ const cyclicGroups = mergeSCCsWithCommonNodes(cycles).filter((group) => {
781
+ return !cache.has(group.values().next().value);
782
+ });
783
+ const mirrored = getMirroredNodes(cyclicGroups, subGraph);
784
+ const sortedCyclicGroups = sortCyclicGroups(
785
+ cyclicGroups.filter((group) => group.size > 1),
786
+ subGraph
787
+ );
678
788
  sortedCyclicGroups.forEach((group) => {
679
- group.forEach((id) => cache.set(id, 0n));
680
- for (let i = 0; i < group.size; i++) {
681
- const results = /* @__PURE__ */ new Map();
682
- group.forEach(
683
- (id) => recursiveBuildChecksum(
684
- graph.get(id)[0],
685
- (id2, value) => {
686
- const writeCache = group.has(id2) ? results : cache;
687
- writeCache.set(id2, value);
688
- },
689
- true
690
- )
691
- );
692
- Array.from(results.entries()).forEach(
693
- ([id, checksum]) => cache.set(id, checksum)
694
- );
789
+ if (cache.has(group.values().next().value)) {
790
+ return;
695
791
  }
792
+ const result = iterateChecksums(group, group.size, cache, graph);
793
+ group.forEach((id) => {
794
+ const checksum = result.get(id);
795
+ if (id in mirrored) {
796
+ mirrored[id].forEach((id2) => cache.set(id2, checksum));
797
+ } else {
798
+ cache.set(id, checksum);
799
+ }
800
+ });
696
801
  });
697
- return recursiveBuildChecksum(entry, (id, value) => cache.set(id, value));
802
+ const getChecksum2 = (entry2) => {
803
+ if (cache.has(entry2.id)) return cache.get(entry2.id);
804
+ return _buildChecksum(entry2, getChecksum2);
805
+ };
806
+ return getChecksum2(entry);
698
807
  };
699
808
  var getChecksumBuilder = (metadata) => {
700
809
  const lookupData = metadata.lookup;
701
810
  const getLookupEntryDef = getLookupFn(lookupData);
811
+ const graph = buildLookupGraph(getLookupEntryDef, lookupData.length);
702
812
  const cache = /* @__PURE__ */ new Map();
703
- const buildDefinition = (id) => buildChecksum(getLookupEntryDef(id), cache);
813
+ const buildDefinition = (id) => buildChecksum(getLookupEntryDef(id), cache, graph);
704
814
  const buildStorage = (pallet, entry) => {
705
815
  try {
706
816
  const storageEntry = metadata.pallets.find((x) => x.name === pallet).storage.items.find((s) => s.name === entry);
@@ -717,8 +827,7 @@ var getChecksumBuilder = (metadata) => {
717
827
  const buildRuntimeCall = (api, method) => {
718
828
  try {
719
829
  const entry = metadata.apis.find((x) => x.name === api)?.methods.find((x) => x.name === method);
720
- if (!entry)
721
- throw null;
830
+ if (!entry) throw null;
722
831
  const argNamesChecksum = getStringChecksum(
723
832
  entry.inputs.map((x) => x.name)
724
833
  );
@@ -732,14 +841,20 @@ var getChecksumBuilder = (metadata) => {
732
841
  }
733
842
  };
734
843
  const buildComposite = (input) => {
735
- if (input.type === "void")
736
- return getChecksum([0n]);
844
+ if (input.type === "void") return getChecksum([0n]);
737
845
  if (input.type === "tuple") {
738
846
  const values = Object.values(input.value).map(
739
847
  (entry) => buildDefinition(entry.id)
740
848
  );
741
849
  return getChecksum([shapeIds.tuple, ...values]);
742
850
  }
851
+ if (input.type === "array") {
852
+ return getChecksum([
853
+ shapeIds.vector,
854
+ buildDefinition(input.value.id),
855
+ BigInt(input.len)
856
+ ]);
857
+ }
743
858
  return structLikeBuilder(
744
859
  shapeIds.struct,
745
860
  input.value,
@@ -760,8 +875,7 @@ var getChecksumBuilder = (metadata) => {
760
875
  palletEntry[variantType]
761
876
  );
762
877
  buildDefinition(enumLookup.id);
763
- if (enumLookup.type !== "enum")
764
- throw null;
878
+ if (enumLookup.type !== "enum") throw null;
765
879
  const entry = enumLookup.value[name];
766
880
  return entry.type === "lookupEntry" ? buildDefinition(entry.value.id) : buildComposite(entry);
767
881
  } catch (_) {