@typeberry/lib 0.9.0-959889e → 0.9.0-a723180

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/package.json +1 -1
  2. package/packages/core/collections/sorted-array.d.ts +1 -1
  3. package/packages/core/collections/sorted-array.d.ts.map +1 -1
  4. package/packages/core/collections/sorted-array.js +4 -2
  5. package/packages/core/collections/sorted-array.test.js +10 -0
  6. package/packages/core/collections/sorted-set.d.ts +1 -1
  7. package/packages/core/collections/sorted-set.d.ts.map +1 -1
  8. package/packages/core/collections/sorted-set.js +6 -2
  9. package/packages/core/collections/sorted-set.test.js +24 -0
  10. package/packages/core/utils/shutdown.d.ts +3 -3
  11. package/packages/core/utils/shutdown.d.ts.map +1 -1
  12. package/packages/core/utils/shutdown.js +2 -79
  13. package/packages/core/utils/shutdown.node.d.ts +5 -0
  14. package/packages/core/utils/shutdown.node.d.ts.map +1 -0
  15. package/packages/core/utils/shutdown.node.js +76 -0
  16. package/packages/core/utils/shutdown.test.js +32 -23
  17. package/packages/jam/config-node/node-config.d.ts +20 -2
  18. package/packages/jam/config-node/node-config.d.ts.map +1 -1
  19. package/packages/jam/config-node/node-config.js +25 -3
  20. package/packages/jam/config-node/node-config.test.js +8 -1
  21. package/packages/jam/database/index.d.ts +1 -0
  22. package/packages/jam/database/index.d.ts.map +1 -1
  23. package/packages/jam/database/index.js +1 -0
  24. package/packages/jam/database/leaf-db-update.d.ts +1 -0
  25. package/packages/jam/database/leaf-db-update.d.ts.map +1 -1
  26. package/packages/jam/database/leaf-db-update.js +22 -5
  27. package/packages/jam/database/leaf-db-update.test.d.ts +2 -0
  28. package/packages/jam/database/leaf-db-update.test.d.ts.map +1 -0
  29. package/packages/jam/database/leaf-db-update.test.js +81 -0
  30. package/packages/jam/database/serialized-states-db.d.ts +4 -0
  31. package/packages/jam/database/serialized-states-db.d.ts.map +1 -1
  32. package/packages/jam/database/serialized-states-db.js +18 -2
  33. package/packages/jam/database/serialized-states-db.test.d.ts +2 -0
  34. package/packages/jam/database/serialized-states-db.test.d.ts.map +1 -0
  35. package/packages/jam/database/serialized-states-db.test.js +109 -0
  36. package/packages/jam/database/states.d.ts +11 -0
  37. package/packages/jam/database/states.d.ts.map +1 -1
  38. package/packages/jam/database/states.js +3 -0
  39. package/packages/jam/database/value-refs.d.ts +117 -0
  40. package/packages/jam/database/value-refs.d.ts.map +1 -0
  41. package/packages/jam/database/value-refs.js +206 -0
  42. package/packages/jam/database/value-refs.test.d.ts +2 -0
  43. package/packages/jam/database/value-refs.test.d.ts.map +1 -0
  44. package/packages/jam/database/value-refs.test.js +165 -0
  45. package/packages/jam/database-fjall/blocks.d.ts +25 -0
  46. package/packages/jam/database-fjall/blocks.d.ts.map +1 -0
  47. package/packages/jam/database-fjall/blocks.js +86 -0
  48. package/packages/jam/database-fjall/blocks.test.d.ts +2 -0
  49. package/packages/jam/database-fjall/blocks.test.d.ts.map +1 -0
  50. package/packages/jam/database-fjall/blocks.test.js +62 -0
  51. package/packages/jam/database-fjall/hybrid-states.d.ts +14 -0
  52. package/packages/jam/database-fjall/hybrid-states.d.ts.map +1 -1
  53. package/packages/jam/database-fjall/hybrid-states.js +55 -6
  54. package/packages/jam/database-fjall/hybrid-states.test.js +94 -2
  55. package/packages/jam/database-fjall/index.d.ts +2 -0
  56. package/packages/jam/database-fjall/index.d.ts.map +1 -1
  57. package/packages/jam/database-fjall/index.js +2 -0
  58. package/packages/jam/database-fjall/root.d.ts +14 -8
  59. package/packages/jam/database-fjall/root.d.ts.map +1 -1
  60. package/packages/jam/database-fjall/root.js +25 -9
  61. package/packages/jam/database-fjall/states.d.ts +31 -0
  62. package/packages/jam/database-fjall/states.d.ts.map +1 -0
  63. package/packages/jam/database-fjall/states.js +99 -0
  64. package/packages/jam/database-fjall/states.test.d.ts +2 -0
  65. package/packages/jam/database-fjall/states.test.d.ts.map +1 -0
  66. package/packages/jam/database-fjall/states.test.js +150 -0
  67. package/packages/jam/database-lmdb/hybrid-states.d.ts +12 -0
  68. package/packages/jam/database-lmdb/hybrid-states.d.ts.map +1 -1
  69. package/packages/jam/database-lmdb/hybrid-states.js +45 -4
  70. package/packages/jam/database-lmdb/hybrid-states.test.js +94 -2
  71. package/packages/jam/database-lmdb/states.d.ts +1 -0
  72. package/packages/jam/database-lmdb/states.d.ts.map +1 -1
  73. package/packages/jam/database-lmdb/states.js +5 -0
  74. package/packages/jam/node/export.d.ts.map +1 -1
  75. package/packages/jam/node/export.js +18 -9
  76. package/packages/jam/node/main-fuzz.d.ts.map +1 -1
  77. package/packages/jam/node/main-fuzz.js +85 -71
  78. package/packages/jam/node/main-importer.d.ts +4 -2
  79. package/packages/jam/node/main-importer.d.ts.map +1 -1
  80. package/packages/jam/node/main-importer.js +26 -12
  81. package/packages/jam/node/main.d.ts.map +1 -1
  82. package/packages/jam/node/main.js +42 -15
  83. package/packages/jam/node/workers.d.ts +4 -4
  84. package/packages/jam/node/workers.d.ts.map +1 -1
  85. package/packages/workers/api/config.d.ts +2 -2
  86. package/packages/workers/api/config.d.ts.map +1 -1
  87. package/packages/workers/api/config.js +1 -1
  88. package/packages/workers/api/port.d.ts +5 -1
  89. package/packages/workers/api/port.d.ts.map +1 -1
  90. package/packages/workers/api/port.js +56 -13
  91. package/packages/workers/api/port.test.js +35 -0
  92. package/packages/workers/api-node/config.d.ts +45 -4
  93. package/packages/workers/api-node/config.d.ts.map +1 -1
  94. package/packages/workers/api-node/config.js +127 -9
  95. package/packages/workers/api-node/config.test.js +52 -3
  96. package/packages/workers/api-node/port.d.ts +3 -0
  97. package/packages/workers/api-node/port.d.ts.map +1 -1
  98. package/packages/workers/api-node/port.js +31 -2
  99. package/packages/workers/api-node/port.test.js +17 -0
  100. package/packages/workers/api-node/protocol.d.ts +3 -3
  101. package/packages/workers/api-node/protocol.d.ts.map +1 -1
  102. package/packages/workers/api-node/protocol.js +18 -12
  103. package/packages/workers/block-authorship/main.js +1 -1
  104. package/packages/workers/importer/finality.d.ts +4 -0
  105. package/packages/workers/importer/finality.d.ts.map +1 -1
  106. package/packages/workers/importer/finality.js +10 -1
  107. package/packages/workers/importer/finality.test.js +6 -0
  108. package/packages/workers/importer/importer.d.ts.map +1 -1
  109. package/packages/workers/importer/importer.js +3 -0
  110. package/packages/workers/importer/main.d.ts +1 -1
  111. package/packages/workers/importer/main.d.ts.map +1 -1
  112. package/packages/workers/importer/main.js +1 -1
  113. package/packages/workers/jam-network/main.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeberry/lib",
3
- "version": "0.9.0-959889e",
3
+ "version": "0.9.0-a723180",
4
4
  "description": "Typeberry Library",
5
5
  "main": "./bin/lib/index.js",
6
6
  "types": "./bin/lib/index.d.ts",
@@ -56,7 +56,7 @@ export declare class SortedArray<V> implements ImmutableSortedArray<V> {
56
56
  findIndex(v: V): number;
57
57
  findExact(v: V): V | undefined;
58
58
  /** Remove one matching element from the collection. */
59
- removeOne(v: V): void;
59
+ removeOne(v: V): V | undefined;
60
60
  has(v: V): boolean;
61
61
  get length(): number;
62
62
  /** Return a regular array that's a copy of this one. */
@@ -1 +1 @@
1
- {"version":3,"file":"sorted-array.d.ts","sourceRoot":"","sources":["../../../../../packages/core/collections/sorted-array.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD,MAAM,WAAW,oBAAoB,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IAC1D,wBAAwB;IACxB,IAAI,KAAK,IAAI,SAAS,CAAC,EAAE,CAAC;IAC1B,6BAA6B;IAC7B,IAAI,UAAU,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAEhC;;;OAGG;IACH,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC;IAExB;;;;;;;OAOG;IACH,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAE/B,qDAAqD;IACrD,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;IAEnB,+CAA+C;IAC/C,IAAI,MAAM,IAAI,MAAM,CAAC;IAErB,wDAAwD;IACxD,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;CAC1C;AAED;;;;;;;GAOG;AACH,qBAAa,WAAW,CAAC,CAAC,CAAE,YAAW,oBAAoB,CAAC,CAAC,CAAC;aAgC1C,KAAK,EAAE,CAAC,EAAE;aACV,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;IAhC3C;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,SAAS,CAAC,EAAO;IAMvE;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,SAAS,CAAC,EAAO;IAkB7E,SAAS,aACS,KAAK,EAAE,CAAC,EAAE,EACV,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;IAG3C,4CAA4C;IACrC,MAAM,CAAC,CAAC,EAAE,CAAC;IAKlB;;;;OAIG;IACI,GAAG,IAAI,CAAC,GAAG,SAAS;IAIpB,SAAS,CAAC,CAAC,EAAE,CAAC;IASd,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IASrC,uDAAuD;IAChD,SAAS,CAAC,CAAC,EAAE,CAAC;IAQd,GAAG,CAAC,CAAC,EAAE,CAAC;IAIf,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED,wDAAwD;IACjD,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE;IAI/C,SAAS,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;;;;IA8B3B,4DAA4D;IAC5D,MAAM,CAAC,wBAAwB,CAAC,CAAC,EAAE,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAqClG,kDAAkD;IACjD,CAAC,MAAM,CAAC,QAAQ,CAAC;CAKnB"}
1
+ {"version":3,"file":"sorted-array.d.ts","sourceRoot":"","sources":["../../../../../packages/core/collections/sorted-array.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD,MAAM,WAAW,oBAAoB,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IAC1D,wBAAwB;IACxB,IAAI,KAAK,IAAI,SAAS,CAAC,EAAE,CAAC;IAC1B,6BAA6B;IAC7B,IAAI,UAAU,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAEhC;;;OAGG;IACH,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC;IAExB;;;;;;;OAOG;IACH,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAE/B,qDAAqD;IACrD,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;IAEnB,+CAA+C;IAC/C,IAAI,MAAM,IAAI,MAAM,CAAC;IAErB,wDAAwD;IACxD,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;CAC1C;AAED;;;;;;;GAOG;AACH,qBAAa,WAAW,CAAC,CAAC,CAAE,YAAW,oBAAoB,CAAC,CAAC,CAAC;aAgC1C,KAAK,EAAE,CAAC,EAAE;aACV,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;IAhC3C;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,SAAS,CAAC,EAAO;IAMvE;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,SAAS,CAAC,EAAO;IAkB7E,SAAS,aACS,KAAK,EAAE,CAAC,EAAE,EACV,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;IAG3C,4CAA4C;IACrC,MAAM,CAAC,CAAC,EAAE,CAAC;IAKlB;;;;OAIG;IACI,GAAG,IAAI,CAAC,GAAG,SAAS;IAIpB,SAAS,CAAC,CAAC,EAAE,CAAC;IASd,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IASrC,uDAAuD;IAChD,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAU9B,GAAG,CAAC,CAAC,EAAE,CAAC;IAIf,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED,wDAAwD;IACjD,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE;IAI/C,SAAS,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;;;;IA8B3B,4DAA4D;IAC5D,MAAM,CAAC,wBAAwB,CAAC,CAAC,EAAE,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAqClG,kDAAkD;IACjD,CAAC,MAAM,CAAC,QAAQ,CAAC;CAKnB"}
@@ -69,9 +69,11 @@ export class SortedArray {
69
69
  removeOne(v) {
70
70
  const findIdx = this.binarySearch(v);
71
71
  if (findIdx.isEqual) {
72
- // remove the element
73
- this.array.splice(findIdx.idx, 1);
72
+ // remove the element and return the stored one
73
+ const [removed] = this.array.splice(findIdx.idx, 1);
74
+ return removed;
74
75
  }
76
+ return undefined;
75
77
  }
76
78
  has(v) {
77
79
  return this.binarySearch(v).isEqual;
@@ -59,6 +59,16 @@ describe("SortedArray", { timeout: 10 }, () => {
59
59
  data.removeOne(2);
60
60
  assert.deepStrictEqual(data.slice(), [3]);
61
61
  });
62
+ it("should return the stored element that was removed", () => {
63
+ const byKey = (self, other) => cmp(self[0], other[0]);
64
+ const data = SortedArray.fromArray(byKey, [
65
+ [1, "a"],
66
+ [2, "b"],
67
+ ]);
68
+ const removed = data.removeOne([1, "x"]);
69
+ assert.deepStrictEqual(removed, [1, "a"]);
70
+ assert.strictEqual(data.removeOne([5, "z"]), undefined);
71
+ });
62
72
  it("should throw when using fromSortedArray and array is not sorted", () => {
63
73
  const data = [1, 3, 2];
64
74
  const tryToCreate = () => SortedArray.fromSortedArray(cmp, data);
@@ -34,7 +34,7 @@ export declare class SortedSet<V> extends SortedArray<V> implements ImmutableSor
34
34
  *
35
35
  * Putting another value that's equal via comparator will replace the current one.
36
36
  */
37
- replace(v: V): void;
37
+ replace(v: V): V | undefined;
38
38
  /** Create a new SortedSet from two sorted collections. */
39
39
  static fromTwoSortedCollections<V>(first: ImmutableSortedArray<V>, second: ImmutableSortedArray<V>): SortedSet<V>;
40
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sorted-set.d.ts","sourceRoot":"","sources":["../../../../../packages/core/collections/sorted-set.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,KAAK,oBAAoB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE3E,MAAM,WAAW,kBAAkB,CAAC,CAAC,CAAE,SAAQ,oBAAoB,CAAC,CAAC,CAAC;CAAG;AAEzE;;;;;;;GAOG;AACH,qBAAa,SAAS,CAAC,CAAC,CAAE,SAAQ,WAAW,CAAC,CAAC,CAAE,YAAW,kBAAkB,CAAC,CAAC,CAAC;IAC/E;;;OAGG;IACH,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,SAAS,CAAC,EAAO;IAkBvE;;;OAGG;IACH,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE;IAaxE;;;;OAIG;IACH,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,SAAS,CAAC,EAAO;IAiB7E,wEAAwE;IACjE,MAAM,CAAC,CAAC,EAAE,CAAC;IAOlB;;;;OAIG;IACI,OAAO,CAAC,CAAC,EAAE,CAAC;IAMnB,0DAA0D;IAC1D,MAAM,CAAC,wBAAwB,CAAC,CAAC,EAAE,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;CA0BnG"}
1
+ {"version":3,"file":"sorted-set.d.ts","sourceRoot":"","sources":["../../../../../packages/core/collections/sorted-set.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,KAAK,oBAAoB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE3E,MAAM,WAAW,kBAAkB,CAAC,CAAC,CAAE,SAAQ,oBAAoB,CAAC,CAAC,CAAC;CAAG;AAEzE;;;;;;;GAOG;AACH,qBAAa,SAAS,CAAC,CAAC,CAAE,SAAQ,WAAW,CAAC,CAAC,CAAE,YAAW,kBAAkB,CAAC,CAAC,CAAC;IAC/E;;;OAGG;IACH,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,SAAS,CAAC,EAAO;IAkBvE;;;OAGG;IACH,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE;IAaxE;;;;OAIG;IACH,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,SAAS,CAAC,EAAO;IAiB7E,wEAAwE;IACjE,MAAM,CAAC,CAAC,EAAE,CAAC;IAOlB;;;;OAIG;IACI,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAUnC,0DAA0D;IAC1D,MAAM,CAAC,wBAAwB,CAAC,CAAC,EAAE,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;CA0BnG"}
@@ -73,8 +73,12 @@ export class SortedSet extends SortedArray {
73
73
  */
74
74
  replace(v) {
75
75
  const findIdx = this.binarySearch(v);
76
- const toRemove = findIdx.isEqual ? 1 : 0;
77
- this.array.splice(findIdx.idx, toRemove, v);
76
+ if (findIdx.isEqual) {
77
+ const [displaced] = this.array.splice(findIdx.idx, 1, v);
78
+ return displaced;
79
+ }
80
+ this.array.splice(findIdx.idx, 0, v);
81
+ return undefined;
78
82
  }
79
83
  /** Create a new SortedSet from two sorted collections. */
80
84
  static fromTwoSortedCollections(first, second) {
@@ -65,6 +65,30 @@ describe("SortedSet", () => {
65
65
  assert.deepStrictEqual(data.length, 3);
66
66
  });
67
67
  });
68
+ describe("replace", () => {
69
+ const byKey = (self, other) => cmp(self[0], other[0]);
70
+ it("should return the displaced element when replacing an equal one", () => {
71
+ const data = SortedSet.fromArrayUnique(byKey, [
72
+ [1, "a"],
73
+ [2, "b"],
74
+ ]);
75
+ const displaced = data.replace([1, "c"]);
76
+ assert.deepStrictEqual(displaced, [1, "a"]);
77
+ assert.deepStrictEqual(data.slice(), [
78
+ [1, "c"],
79
+ [2, "b"],
80
+ ]);
81
+ });
82
+ it("should return undefined when inserting a fresh element", () => {
83
+ const data = SortedSet.fromArrayUnique(byKey, [[1, "a"]]);
84
+ const displaced = data.replace([2, "b"]);
85
+ assert.strictEqual(displaced, undefined);
86
+ assert.deepStrictEqual(data.slice(), [
87
+ [1, "a"],
88
+ [2, "b"],
89
+ ]);
90
+ });
91
+ });
68
92
  describe("fromTwoSortedCollections", () => {
69
93
  it("should merge two sorted sets without duplicates", () => {
70
94
  const arr1 = [1, 2, 3];
@@ -1,4 +1,5 @@
1
1
  export type Closer = () => Promise<void>;
2
+ export type ShutdownSignal = string;
2
3
  export interface ShutdownLogger {
3
4
  info: (msg: string) => void;
4
5
  error: (msg: string) => void;
@@ -7,12 +8,11 @@ export interface ShutdownOptions {
7
8
  /** Max ms allowed for `close` before forced exit(1). Default 10_000. */
8
9
  timeoutMs?: number;
9
10
  /** Signals to listen for. Default ["SIGTERM", "SIGINT"]. */
10
- signals?: readonly NodeJS.Signals[];
11
+ signals?: readonly ShutdownSignal[];
11
12
  /** Logger; defaults to a no-op logger. */
12
13
  log?: ShutdownLogger;
13
14
  /** Test hook used instead of process.exit. */
14
15
  exit?: (code: number) => never;
15
16
  }
16
- /** Returns an uninstall function (used by tests). */
17
- export declare function installShutdownHandlers(close: Closer, options?: ShutdownOptions): () => void;
17
+ export declare function installShutdownHandlers(_close: Closer, _options?: ShutdownOptions): () => void;
18
18
  //# sourceMappingURL=shutdown.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../../../../packages/core/utils/shutdown.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,SAAS,MAAM,CAAC,OAAO,EAAE,CAAC;IACpC,0CAA0C;IAC1C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;CAChC;AASD,qDAAqD;AACrD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,MAAM,IAAI,CAiFhG"}
1
+ {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../../../../packages/core/utils/shutdown.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzC,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IACpC,0CAA0C;IAC1C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;CAChC;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,eAAoB,GAAG,MAAM,IAAI,CAElG"}
@@ -1,80 +1,3 @@
1
- const DEFAULT_SIGNALS = ["SIGTERM", "SIGINT"];
2
- const DEFAULT_TIMEOUT_MS = 10_000;
3
- function isNodeRuntime() {
4
- return typeof process !== "undefined" && typeof process.on === "function" && typeof process.exit === "function";
5
- }
6
- /** Returns an uninstall function (used by tests). */
7
- export function installShutdownHandlers(close, options = {}) {
8
- if (!isNodeRuntime()) {
9
- return () => { };
10
- }
11
- const signals = options.signals ?? DEFAULT_SIGNALS;
12
- const exit = (options.exit ?? process.exit);
13
- const log = options.log;
14
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
15
- let state = "idle";
16
- const forceExit = (signal) => {
17
- log?.error(`Received ${signal} during shutdown, forcing exit.`);
18
- try {
19
- exit(1);
20
- }
21
- catch {
22
- // test-time exit throws; swallow.
23
- }
24
- };
25
- const handler = (signal) => {
26
- if (state === "closing" || state === "done") {
27
- forceExit(signal);
28
- return;
29
- }
30
- state = "closing";
31
- log?.info(`Received ${signal}, draining...`);
32
- void (async () => {
33
- const TIMED_OUT = Symbol("timed-out");
34
- let timeoutHandle;
35
- const timeoutPromise = new Promise((resolve) => {
36
- timeoutHandle = setTimeout(() => resolve(TIMED_OUT), timeoutMs);
37
- });
38
- timeoutHandle?.unref?.();
39
- let code = 0;
40
- try {
41
- const outcome = await Promise.race([
42
- close().then(() => "ok", (e) => ({ err: e })),
43
- timeoutPromise,
44
- ]);
45
- if (outcome === TIMED_OUT) {
46
- code = 1;
47
- log?.error(`Shutdown cleanup exceeded ${timeoutMs}ms timeout, forcing exit.`);
48
- }
49
- else if (typeof outcome === "object" && "err" in outcome) {
50
- code = 1;
51
- const e = outcome.err;
52
- log?.error(`Shutdown close threw: ${e instanceof Error ? (e.stack ?? e.message) : String(e)}`);
53
- }
54
- else {
55
- log?.info("Shutdown complete.");
56
- }
57
- }
58
- finally {
59
- clearTimeout(timeoutHandle);
60
- state = "done";
61
- }
62
- try {
63
- exit(code);
64
- }
65
- catch {
66
- // test-time exit throws; swallow.
67
- }
68
- })();
69
- };
70
- // Node passes the signal name to the listener, so a single handler works
71
- // for every signal.
72
- for (const sig of signals) {
73
- process.on(sig, handler);
74
- }
75
- return () => {
76
- for (const sig of signals) {
77
- process.off(sig, handler);
78
- }
79
- };
1
+ export function installShutdownHandlers(_close, _options = {}) {
2
+ return () => { };
80
3
  }
@@ -0,0 +1,5 @@
1
+ import type { Closer, ShutdownOptions } from "./shutdown.js";
2
+ export type { Closer, ShutdownLogger, ShutdownOptions, ShutdownSignal } from "./shutdown.js";
3
+ /** Returns an uninstall function (used by tests). */
4
+ export declare function installShutdownHandlers(close: Closer, options?: ShutdownOptions): () => void;
5
+ //# sourceMappingURL=shutdown.node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.node.d.ts","sourceRoot":"","sources":["../../../../../packages/core/utils/shutdown.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE7D,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAK7F,qDAAqD;AACrD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,MAAM,IAAI,CA+EhG"}
@@ -0,0 +1,76 @@
1
+ const DEFAULT_SIGNALS = ["SIGTERM", "SIGINT"];
2
+ const DEFAULT_TIMEOUT_MS = 10_000;
3
+ /** Returns an uninstall function (used by tests). */
4
+ export function installShutdownHandlers(close, options = {}) {
5
+ const signals = (options.signals ?? DEFAULT_SIGNALS);
6
+ const exit = (options.exit ?? process.exit);
7
+ const log = options.log;
8
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
9
+ let state = "idle";
10
+ const forceExit = (signal) => {
11
+ log?.error(`Received ${signal} during shutdown, forcing exit.`);
12
+ try {
13
+ exit(1);
14
+ }
15
+ catch {
16
+ // test-time exit throws; swallow.
17
+ }
18
+ };
19
+ const handler = (signal) => {
20
+ if (state === "closing" || state === "done") {
21
+ forceExit(signal);
22
+ return;
23
+ }
24
+ state = "closing";
25
+ log?.info(`Received ${signal}, draining...`);
26
+ void (async () => {
27
+ const TIMED_OUT = Symbol("timed-out");
28
+ let timeoutHandle;
29
+ const timeoutPromise = new Promise((resolve) => {
30
+ timeoutHandle = setTimeout(() => resolve(TIMED_OUT), timeoutMs);
31
+ });
32
+ timeoutHandle?.unref?.();
33
+ let code = 0;
34
+ try {
35
+ const outcome = await Promise.race([
36
+ Promise.resolve()
37
+ .then(close)
38
+ .then(() => "ok", (e) => ({ err: e })),
39
+ timeoutPromise,
40
+ ]);
41
+ if (outcome === TIMED_OUT) {
42
+ code = 1;
43
+ log?.error(`Shutdown cleanup exceeded ${timeoutMs}ms timeout, forcing exit.`);
44
+ }
45
+ else if (typeof outcome === "object" && "err" in outcome) {
46
+ code = 1;
47
+ const e = outcome.err;
48
+ log?.error(`Shutdown close threw: ${e instanceof Error ? (e.stack ?? e.message) : String(e)}`);
49
+ }
50
+ else {
51
+ log?.info("Shutdown complete.");
52
+ }
53
+ }
54
+ finally {
55
+ clearTimeout(timeoutHandle);
56
+ state = "done";
57
+ }
58
+ try {
59
+ exit(code);
60
+ }
61
+ catch {
62
+ // test-time exit throws; swallow.
63
+ }
64
+ })();
65
+ };
66
+ // Node passes the signal name to the listener, so a single handler works
67
+ // for every signal.
68
+ for (const sig of signals) {
69
+ process.on(sig, handler);
70
+ }
71
+ return () => {
72
+ for (const sig of signals) {
73
+ process.off(sig, handler);
74
+ }
75
+ };
76
+ }
@@ -1,6 +1,7 @@
1
1
  import assert from "node:assert";
2
2
  import { afterEach, describe, it } from "node:test";
3
- import { installShutdownHandlers } from "./shutdown.js";
3
+ import { installShutdownHandlers as installGenericShutdownHandlers } from "./shutdown.js";
4
+ import { installShutdownHandlers } from "./shutdown.node.js";
4
5
  function makeExitRecorder() {
5
6
  let resolveExited;
6
7
  const exited = new Promise((resolve) => {
@@ -109,28 +110,16 @@ describe("utils::installShutdownHandlers", () => {
109
110
  assert.strictEqual(closeCalled, false);
110
111
  assert.strictEqual(exitRec.exitCode, null);
111
112
  });
112
- it("is a no-op in non-Node runtimes", async () => {
113
- const originalOn = process.on;
114
- const originalExit = process.exit;
115
- // Hide the Node-specific surface so installShutdownHandlers takes the no-op branch.
116
- process.on = undefined;
117
- process.exit = undefined;
118
- try {
119
- const exitRec = makeExitRecorder();
120
- let closeCalled = false;
121
- const uninstall = installShutdownHandlers(async () => {
122
- closeCalled = true;
123
- }, { exit: exitRec.exit, log: silentLog });
124
- // The uninstall must be callable without throwing even in the no-op path.
125
- uninstall();
126
- assert.strictEqual(typeof uninstall, "function");
127
- assert.strictEqual(closeCalled, false);
128
- assert.strictEqual(exitRec.exitCode, null);
129
- }
130
- finally {
131
- process.on = originalOn;
132
- process.exit = originalExit;
133
- }
113
+ it("is a no-op from the generic shutdown module", async () => {
114
+ const exitRec = makeExitRecorder();
115
+ let closeCalled = false;
116
+ const uninstall = installGenericShutdownHandlers(async () => {
117
+ closeCalled = true;
118
+ }, { exit: exitRec.exit, log: silentLog });
119
+ uninstall();
120
+ assert.strictEqual(typeof uninstall, "function");
121
+ assert.strictEqual(closeCalled, false);
122
+ assert.strictEqual(exitRec.exitCode, null);
134
123
  });
135
124
  it("exits with code 1 when close rejects", async () => {
136
125
  const exitRec = makeExitRecorder();
@@ -152,4 +141,24 @@ describe("utils::installShutdownHandlers", () => {
152
141
  assert.ok(errorLogged !== null, "expected error to be logged");
153
142
  assert.match(errorLogged, /boom/);
154
143
  });
144
+ it("exits with code 1 when close throws synchronously", async () => {
145
+ const exitRec = makeExitRecorder();
146
+ let errorLogged = null;
147
+ uninstallers.push(installShutdownHandlers(() => {
148
+ throw new Error("sync boom");
149
+ }, {
150
+ exit: exitRec.exit,
151
+ log: {
152
+ info: () => { },
153
+ error: (msg) => {
154
+ errorLogged = msg;
155
+ },
156
+ },
157
+ }));
158
+ process.emit("SIGTERM", "SIGTERM");
159
+ await exitRec.exited;
160
+ assert.strictEqual(exitRec.exitCode, 1);
161
+ assert.ok(errorLogged !== null, "expected error to be logged");
162
+ assert.match(errorLogged, /sync boom/);
163
+ });
155
164
  });
@@ -1,4 +1,3 @@
1
- import type { JsonObject } from "#@typeberry/block-json";
2
1
  import { PvmBackend } from "#@typeberry/config";
3
2
  import { type FromJson } from "#@typeberry/json-parser";
4
3
  import { AuthorshipOptions } from "./authorship.js";
@@ -20,7 +19,23 @@ export declare enum KnownChainSpec {
20
19
  /** Full chain spec. */
21
20
  Full = "full"
22
21
  }
22
+ /** Persistent regular-node database backend. */
23
+ export declare enum RegularStateBackend {
24
+ /** @deprecated lmdb remains available as an explicit fallback, but fjall is the default backend. */
25
+ Lmdb = "lmdb",
26
+ Fjall = "fjall"
27
+ }
23
28
  export declare const knownChainSpecFromJson: FromJson<KnownChainSpec>;
29
+ export declare const regularStateBackendFromJson: FromJson<RegularStateBackend>;
30
+ type NodeConfigurationJson = {
31
+ $schema: string;
32
+ version: number;
33
+ flavor: KnownChainSpec;
34
+ chain_spec: JipChainSpec;
35
+ database_base_path?: string;
36
+ state_backend?: RegularStateBackend;
37
+ authorship: AuthorshipOptions;
38
+ };
24
39
  export declare class NodeConfiguration {
25
40
  readonly $schema: string;
26
41
  readonly version: number;
@@ -28,10 +43,13 @@ export declare class NodeConfiguration {
28
43
  readonly chainSpec: JipChainSpec;
29
44
  /** If database path is not provided, we load an in-memory db. */
30
45
  readonly databaseBasePath: string | undefined;
46
+ /** Persistent database backend used when `databaseBasePath` is set. */
47
+ readonly stateBackend: RegularStateBackend;
31
48
  readonly authorship: AuthorshipOptions;
32
49
  static fromJson: import("@typeberry/json-parser").FromJsonWithParser<unknown, NodeConfiguration>;
33
- static new({ $schema, version, flavor, chain_spec, database_base_path, authorship }: JsonObject<NodeConfiguration>): NodeConfiguration;
50
+ static new({ $schema, version, flavor, chain_spec, database_base_path, state_backend, authorship, }: NodeConfigurationJson): NodeConfiguration;
34
51
  private constructor();
35
52
  }
36
53
  export declare function loadConfig(config: string[], withRelPath: (p: string) => string): NodeConfiguration;
54
+ export {};
37
55
  //# sourceMappingURL=node-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node-config.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/config-node/node-config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,EAAE,KAAK,QAAQ,EAAuB,MAAM,wBAAwB,CAAC;AAG5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAInD,+DAA+D;AAC/D,eAAO,MAAM,eAAe,QAAQ,CAAC;AACrC,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C,2BAA2B;AAC3B,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC,eAAO,MAAM,aAAa;;;;CAIzB,CAAC;AAEF,0BAA0B;AAC1B,oBAAY,cAAc;IACxB,uBAAuB;IACvB,IAAI,SAAS;IACb,uBAAuB;IACvB,IAAI,SAAS;CACd;AAED,eAAO,MAAM,sBAAsB,EAS7B,QAAQ,CAAC,cAAc,CAAC,CAAC;AAE/B,qBAAa,iBAAiB;aAqBV,OAAO,EAAE,MAAM;aACf,OAAO,EAAE,MAAM;aACf,MAAM,EAAE,cAAc;aACtB,SAAS,EAAE,YAAY;IACvC,iEAAiE;aACjD,gBAAgB,EAAE,MAAM,GAAG,SAAS;aACpC,UAAU,EAAE,iBAAiB;IA1B/C,MAAM,CAAC,QAAQ,kFAUb;IAEF,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,UAAU,EAAE,EAAE,UAAU,CAAC,iBAAiB,CAAC;IAOlH,OAAO;CASR;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,iBAAiB,CAuDlG"}
1
+ {"version":3,"file":"node-config.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/config-node/node-config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,EAAE,KAAK,QAAQ,EAAuB,MAAM,wBAAwB,CAAC;AAG5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAInD,+DAA+D;AAC/D,eAAO,MAAM,eAAe,QAAQ,CAAC;AACrC,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C,2BAA2B;AAC3B,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC,eAAO,MAAM,aAAa;;;;CAIzB,CAAC;AAEF,0BAA0B;AAC1B,oBAAY,cAAc;IACxB,uBAAuB;IACvB,IAAI,SAAS;IACb,uBAAuB;IACvB,IAAI,SAAS;CACd;AAED,gDAAgD;AAChD,oBAAY,mBAAmB;IAC7B,oGAAoG;IACpG,IAAI,SAAS;IACb,KAAK,UAAU;CAChB;AAED,eAAO,MAAM,sBAAsB,EAS7B,QAAQ,CAAC,cAAc,CAAC,CAAC;AAE/B,eAAO,MAAM,2BAA2B,EASlC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;AAEpC,KAAK,qBAAqB,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,cAAc,CAAC;IACvB,UAAU,EAAE,YAAY,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,UAAU,EAAE,iBAAiB,CAAC;CAC/B,CAAC;AAEF,qBAAa,iBAAiB;aAsCV,OAAO,EAAE,MAAM;aACf,OAAO,EAAE,MAAM;aACf,MAAM,EAAE,cAAc;aACtB,SAAS,EAAE,YAAY;IACvC,iEAAiE;aACjD,gBAAgB,EAAE,MAAM,GAAG,SAAS;IACpD,uEAAuE;aACvD,YAAY,EAAE,mBAAmB;aACjC,UAAU,EAAE,iBAAiB;IA7C/C,MAAM,CAAC,QAAQ,kFAWb;IAEF,MAAM,CAAC,GAAG,CAAC,EACT,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,UAAU,GACX,EAAE,qBAAqB;IAexB,OAAO;CAWR;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,iBAAiB,CAuDlG"}
@@ -26,6 +26,13 @@ export var KnownChainSpec;
26
26
  /** Full chain spec. */
27
27
  KnownChainSpec["Full"] = "full";
28
28
  })(KnownChainSpec || (KnownChainSpec = {}));
29
+ /** Persistent regular-node database backend. */
30
+ export var RegularStateBackend;
31
+ (function (RegularStateBackend) {
32
+ /** @deprecated lmdb remains available as an explicit fallback, but fjall is the default backend. */
33
+ RegularStateBackend["Lmdb"] = "lmdb";
34
+ RegularStateBackend["Fjall"] = "fjall";
35
+ })(RegularStateBackend || (RegularStateBackend = {}));
29
36
  export const knownChainSpecFromJson = json.fromString((input, ctx) => {
30
37
  switch (input) {
31
38
  case KnownChainSpec.Tiny:
@@ -36,12 +43,23 @@ export const knownChainSpecFromJson = json.fromString((input, ctx) => {
36
43
  throw Error(`unknown network flavor: ${input} at ${ctx}`);
37
44
  }
38
45
  });
46
+ export const regularStateBackendFromJson = json.fromString((input, ctx) => {
47
+ switch (input) {
48
+ case RegularStateBackend.Lmdb:
49
+ return RegularStateBackend.Lmdb;
50
+ case RegularStateBackend.Fjall:
51
+ return RegularStateBackend.Fjall;
52
+ default:
53
+ throw Error(`unknown state backend: ${input} at ${ctx}`);
54
+ }
55
+ });
39
56
  export class NodeConfiguration {
40
57
  $schema;
41
58
  version;
42
59
  flavor;
43
60
  chainSpec;
44
61
  databaseBasePath;
62
+ stateBackend;
45
63
  authorship;
46
64
  static fromJson = json.object({
47
65
  $schema: "string",
@@ -49,22 +67,26 @@ export class NodeConfiguration {
49
67
  flavor: knownChainSpecFromJson,
50
68
  chain_spec: JipChainSpec.fromJson,
51
69
  database_base_path: json.optional("string"),
70
+ state_backend: json.optional(regularStateBackendFromJson),
52
71
  authorship: AuthorshipOptions.fromJson,
53
72
  }, NodeConfiguration.new);
54
- static new({ $schema, version, flavor, chain_spec, database_base_path, authorship }) {
73
+ static new({ $schema, version, flavor, chain_spec, database_base_path, state_backend, authorship, }) {
55
74
  if (version !== 1) {
56
75
  throw new Error("Only version=1 config is supported.");
57
76
  }
58
- return new NodeConfiguration($schema, version, flavor, chain_spec, database_base_path ?? undefined, authorship);
77
+ return new NodeConfiguration($schema, version, flavor, chain_spec, database_base_path ?? undefined, state_backend ?? RegularStateBackend.Fjall, authorship);
59
78
  }
60
79
  constructor($schema, version, flavor, chainSpec,
61
80
  /** If database path is not provided, we load an in-memory db. */
62
- databaseBasePath, authorship) {
81
+ databaseBasePath,
82
+ /** Persistent database backend used when `databaseBasePath` is set. */
83
+ stateBackend, authorship) {
63
84
  this.$schema = $schema;
64
85
  this.version = version;
65
86
  this.flavor = flavor;
66
87
  this.chainSpec = chainSpec;
67
88
  this.databaseBasePath = databaseBasePath;
89
+ this.stateBackend = stateBackend;
68
90
  this.authorship = authorship;
69
91
  }
70
92
  }
@@ -5,7 +5,7 @@ import { configs } from "#@typeberry/configs";
5
5
  import polkajamConfig from "#@typeberry/configs/typeberry-polkajam-dev.json" with { type: "json" };
6
6
  import { parseFromJson } from "#@typeberry/json-parser";
7
7
  import { workspacePathFix } from "#@typeberry/utils";
8
- import { KnownChainSpec, loadConfig, NodeConfiguration } from "./node-config.js";
8
+ import { KnownChainSpec, loadConfig, NodeConfiguration, RegularStateBackend } from "./node-config.js";
9
9
  const withRelPath = workspacePathFix(`${import.meta.dirname}/../..`);
10
10
  const NODE_CONFIG_TEST = {
11
11
  $schema: "https://typeberry.dev/schemas/config-v1.schema.json",
@@ -40,6 +40,13 @@ describe("Importing Node Configuration", () => {
40
40
  it("should read the database base path", () => {
41
41
  assert.deepStrictEqual(config.databaseBasePath, "/tmp/jam-node-db");
42
42
  });
43
+ it("defaults to the fjall state backend", () => {
44
+ assert.deepStrictEqual(config.stateBackend, RegularStateBackend.Fjall);
45
+ });
46
+ it("should read the state backend", () => {
47
+ const lmdbConfig = parseFromJson({ ...NODE_CONFIG_TEST, state_backend: "lmdb" }, NodeConfiguration.fromJson);
48
+ assert.deepStrictEqual(lmdbConfig.stateBackend, RegularStateBackend.Lmdb);
49
+ });
43
50
  it("should read the chain spec", () => {
44
51
  assert.deepStrictEqual(config.chainSpec.id, "testnet");
45
52
  assert(config.chainSpec.bootnodes !== undefined);
@@ -4,4 +4,5 @@ export * from "./leaf-db-update.js";
4
4
  export * from "./root.js";
5
5
  export * from "./serialized-states-db.js";
6
6
  export * from "./states.js";
7
+ export * from "./value-refs.js";
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/database/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,WAAW,CAAC;AAC1B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/database/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,WAAW,CAAC;AAC1B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC"}
@@ -4,3 +4,4 @@ export * from "./leaf-db-update.js";
4
4
  export * from "./root.js";
5
5
  export * from "./serialized-states-db.js";
6
6
  export * from "./states.js";
7
+ export * from "./value-refs.js";
@@ -5,6 +5,7 @@ import { StateEntryUpdateAction, type StateKey } from "#@typeberry/state-merklei
5
5
  import { type LeafNode, type ValueHash } from "#@typeberry/trie";
6
6
  export declare function updateLeafs(leafs: SortedSet<LeafNode>, blake2b: Blake2b, data: Iterable<[StateEntryUpdateAction, StateKey | TruncatedHash, BytesBlob]>): {
7
7
  values: [ValueHash, BytesBlob][];
8
+ removed: ValueHash[];
8
9
  leafs: SortedSet<LeafNode>;
9
10
  };
10
11
  //# sourceMappingURL=leaf-db-update.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"leaf-db-update.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/database/leaf-db-update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,KAAK,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AACvF,OAAO,EAAgB,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI9E,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,EAC1B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,QAAQ,CAAC,CAAC,sBAAsB,EAAE,QAAQ,GAAG,aAAa,EAAE,SAAS,CAAC,CAAC,GAC5E;IACD,MAAM,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC;IACjC,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;CAC5B,CAwBA"}
1
+ {"version":3,"file":"leaf-db-update.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/database/leaf-db-update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,KAAK,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AACvF,OAAO,EAAgB,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI9E,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,EAC1B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,QAAQ,CAAC,CAAC,sBAAsB,EAAE,QAAQ,GAAG,aAAa,EAAE,SAAS,CAAC,CAAC,GAC5E;IACD,MAAM,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC;IACjC,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;CAC5B,CAyCA"}
@@ -7,18 +7,34 @@ export function updateLeafs(leafs, blake2b, data) {
7
7
  const blake2bTrieHasher = getBlake2bTrieHasher(blake2b);
8
8
  // We will collect all values that don't fit directly into leaf nodes.
9
9
  const values = [];
10
+ // Value hashes that are no longer referenced by the leaf they were stored under.
11
+ // NOTE this does not yet mean they can be removed from the DB - the same value
12
+ // may still be referenced by another leaf or another state. It's up to value
13
+ // ref-counting to decide that.
14
+ const removed = [];
10
15
  for (const [action, key, value] of data) {
11
16
  if (action === StateEntryUpdateAction.Insert) {
12
17
  const leafNode = InMemoryTrie.constructLeaf(blake2bTrieHasher, key.asOpaque(), value);
13
- leafs.replace(leafNode);
14
- if (!leafNode.hasEmbeddedValue()) {
15
- values.push([leafNode.getValueHash(), value]);
18
+ const displaced = leafs.replace(leafNode);
19
+ const newHash = leafNode.hasEmbeddedValue() ? null : leafNode.getValueHash();
20
+ const oldHash = displaced !== undefined && !displaced.hasEmbeddedValue() ? displaced.getValueHash() : null;
21
+ // Re-inserting the exact same value under the same key is a no-op for the DB.
22
+ if (newHash !== null && oldHash !== null && newHash.isEqualTo(oldHash)) {
23
+ continue;
24
+ }
25
+ if (newHash !== null) {
26
+ values.push([newHash, value]);
27
+ }
28
+ if (oldHash !== null) {
29
+ removed.push(oldHash);
16
30
  }
17
31
  }
18
32
  else if (action === StateEntryUpdateAction.Remove) {
19
33
  const leafNode = InMemoryTrie.constructLeaf(blake2bTrieHasher, key.asOpaque(), BytesBlob.empty());
20
- leafs.removeOne(leafNode);
21
- // TODO [ToDr] Handle ref-counting values or updating some header-hash-based references.
34
+ const removedLeaf = leafs.removeOne(leafNode);
35
+ if (removedLeaf !== undefined && !removedLeaf.hasEmbeddedValue()) {
36
+ removed.push(removedLeaf.getValueHash());
37
+ }
22
38
  }
23
39
  else {
24
40
  assertNever(action);
@@ -26,6 +42,7 @@ export function updateLeafs(leafs, blake2b, data) {
26
42
  }
27
43
  return {
28
44
  values,
45
+ removed,
29
46
  leafs,
30
47
  };
31
48
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=leaf-db-update.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leaf-db-update.test.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/database/leaf-db-update.test.ts"],"names":[],"mappings":""}