@typeberry/lib 0.8.4-faebc7a → 0.9.0-1c3f157

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 (197) hide show
  1. package/package.json +1 -1
  2. package/packages/configs/index.d.ts +30 -1
  3. package/packages/configs/index.d.ts.map +1 -1
  4. package/packages/configs/index.js +4 -2
  5. package/packages/configs/typeberry-dev-full.json +29 -0
  6. package/packages/core/bytes/bytes.d.ts +1 -0
  7. package/packages/core/bytes/bytes.d.ts.map +1 -1
  8. package/packages/core/bytes/bytes.js +8 -0
  9. package/packages/core/collections/sorted-array.d.ts +1 -1
  10. package/packages/core/collections/sorted-array.d.ts.map +1 -1
  11. package/packages/core/collections/sorted-array.js +4 -2
  12. package/packages/core/collections/sorted-array.test.js +10 -0
  13. package/packages/core/collections/sorted-set.d.ts +1 -1
  14. package/packages/core/collections/sorted-set.d.ts.map +1 -1
  15. package/packages/core/collections/sorted-set.js +6 -2
  16. package/packages/core/collections/sorted-set.test.js +24 -0
  17. package/packages/core/utils/debug.d.ts +4 -2
  18. package/packages/core/utils/debug.d.ts.map +1 -1
  19. package/packages/core/utils/debug.js +18 -13
  20. package/packages/core/utils/debug.test.js +12 -6
  21. package/packages/core/utils/index.d.ts +1 -0
  22. package/packages/core/utils/index.d.ts.map +1 -1
  23. package/packages/core/utils/index.js +1 -0
  24. package/packages/core/utils/shutdown.d.ts +18 -0
  25. package/packages/core/utils/shutdown.d.ts.map +1 -0
  26. package/packages/core/utils/shutdown.js +3 -0
  27. package/packages/core/utils/shutdown.node.d.ts +5 -0
  28. package/packages/core/utils/shutdown.node.d.ts.map +1 -0
  29. package/packages/core/utils/shutdown.node.js +76 -0
  30. package/packages/core/utils/shutdown.test.d.ts +2 -0
  31. package/packages/core/utils/shutdown.test.d.ts.map +1 -0
  32. package/packages/core/utils/shutdown.test.js +164 -0
  33. package/packages/extensions/ipc/server.d.ts.map +1 -1
  34. package/packages/extensions/ipc/server.js +7 -0
  35. package/packages/jam/config-node/node-config.d.ts +22 -3
  36. package/packages/jam/config-node/node-config.d.ts.map +1 -1
  37. package/packages/jam/config-node/node-config.js +33 -6
  38. package/packages/jam/config-node/node-config.test.js +11 -4
  39. package/packages/jam/database/index.d.ts +1 -0
  40. package/packages/jam/database/index.d.ts.map +1 -1
  41. package/packages/jam/database/index.js +1 -0
  42. package/packages/jam/database/leaf-db-update.d.ts +1 -0
  43. package/packages/jam/database/leaf-db-update.d.ts.map +1 -1
  44. package/packages/jam/database/leaf-db-update.js +22 -5
  45. package/packages/jam/database/leaf-db-update.test.d.ts +2 -0
  46. package/packages/jam/database/leaf-db-update.test.d.ts.map +1 -0
  47. package/packages/jam/database/leaf-db-update.test.js +81 -0
  48. package/packages/jam/database/serialized-states-db.d.ts +1 -0
  49. package/packages/jam/database/serialized-states-db.d.ts.map +1 -1
  50. package/packages/jam/database/serialized-states-db.js +4 -0
  51. package/packages/jam/database/states.d.ts +11 -0
  52. package/packages/jam/database/states.d.ts.map +1 -1
  53. package/packages/jam/database/states.js +3 -0
  54. package/packages/jam/database/value-refs.d.ts +117 -0
  55. package/packages/jam/database/value-refs.d.ts.map +1 -0
  56. package/packages/jam/database/value-refs.js +206 -0
  57. package/packages/jam/database/value-refs.test.d.ts +2 -0
  58. package/packages/jam/database/value-refs.test.d.ts.map +1 -0
  59. package/packages/jam/database/value-refs.test.js +165 -0
  60. package/packages/jam/database-fjall/blocks.d.ts +25 -0
  61. package/packages/jam/database-fjall/blocks.d.ts.map +1 -0
  62. package/packages/jam/database-fjall/blocks.js +86 -0
  63. package/packages/jam/database-fjall/blocks.test.d.ts +2 -0
  64. package/packages/jam/database-fjall/blocks.test.d.ts.map +1 -0
  65. package/packages/jam/database-fjall/blocks.test.js +62 -0
  66. package/packages/jam/database-fjall/hybrid-states.d.ts +61 -10
  67. package/packages/jam/database-fjall/hybrid-states.d.ts.map +1 -1
  68. package/packages/jam/database-fjall/hybrid-states.js +131 -26
  69. package/packages/jam/database-fjall/hybrid-states.test.js +31 -1
  70. package/packages/jam/database-fjall/index.d.ts +2 -0
  71. package/packages/jam/database-fjall/index.d.ts.map +1 -1
  72. package/packages/jam/database-fjall/index.js +2 -0
  73. package/packages/jam/database-fjall/root.d.ts +29 -17
  74. package/packages/jam/database-fjall/root.d.ts.map +1 -1
  75. package/packages/jam/database-fjall/root.js +33 -13
  76. package/packages/jam/database-fjall/states.d.ts +31 -0
  77. package/packages/jam/database-fjall/states.d.ts.map +1 -0
  78. package/packages/jam/database-fjall/states.js +99 -0
  79. package/packages/jam/database-fjall/states.test.d.ts +2 -0
  80. package/packages/jam/database-fjall/states.test.d.ts.map +1 -0
  81. package/packages/jam/database-fjall/states.test.js +150 -0
  82. package/packages/jam/database-lmdb/hybrid-states.d.ts +12 -0
  83. package/packages/jam/database-lmdb/hybrid-states.d.ts.map +1 -1
  84. package/packages/jam/database-lmdb/hybrid-states.js +45 -4
  85. package/packages/jam/database-lmdb/states.d.ts +1 -0
  86. package/packages/jam/database-lmdb/states.d.ts.map +1 -1
  87. package/packages/jam/database-lmdb/states.js +5 -0
  88. package/packages/jam/jamnp-s/tasks/ticket-distribution.js +1 -1
  89. package/packages/jam/node/export.d.ts.map +1 -1
  90. package/packages/jam/node/export.js +18 -9
  91. package/packages/jam/node/main-fuzz.d.ts +4 -1
  92. package/packages/jam/node/main-fuzz.d.ts.map +1 -1
  93. package/packages/jam/node/main-fuzz.js +127 -55
  94. package/packages/jam/node/main-importer.d.ts +11 -2
  95. package/packages/jam/node/main-importer.d.ts.map +1 -1
  96. package/packages/jam/node/main-importer.js +27 -12
  97. package/packages/jam/node/main.d.ts.map +1 -1
  98. package/packages/jam/node/main.js +42 -15
  99. package/packages/jam/node/workers.d.ts +4 -4
  100. package/packages/jam/node/workers.d.ts.map +1 -1
  101. package/packages/jam/safrole/bandersnatch-vrf.d.ts +22 -2
  102. package/packages/jam/safrole/bandersnatch-vrf.d.ts.map +1 -1
  103. package/packages/jam/safrole/bandersnatch-vrf.js +54 -20
  104. package/packages/jam/safrole/bandersnatch-vrf.test.js +3 -2
  105. package/packages/jam/safrole/bandersnatch-wasm.d.ts +10 -0
  106. package/packages/jam/safrole/bandersnatch-wasm.d.ts.map +1 -1
  107. package/packages/jam/safrole/bandersnatch-wasm.js +12 -0
  108. package/packages/jam/ticket-pool/ticket-validator.d.ts +5 -4
  109. package/packages/jam/ticket-pool/ticket-validator.d.ts.map +1 -1
  110. package/packages/jam/ticket-pool/ticket-validator.js +8 -3
  111. package/packages/jam/ticket-pool/ticket-validator.test.js +5 -4
  112. package/packages/jam/ticket-pool/verified-ticket-pool.d.ts +2 -0
  113. package/packages/jam/ticket-pool/verified-ticket-pool.d.ts.map +1 -1
  114. package/packages/jam/ticket-pool/verified-ticket-pool.js +4 -0
  115. package/packages/jam/ticket-pool/verified-ticket-pool.test.js +5 -5
  116. package/packages/workers/api/config.d.ts +2 -2
  117. package/packages/workers/api/config.d.ts.map +1 -1
  118. package/packages/workers/api/config.js +1 -1
  119. package/packages/workers/api/port.d.ts +5 -1
  120. package/packages/workers/api/port.d.ts.map +1 -1
  121. package/packages/workers/api/port.js +56 -13
  122. package/packages/workers/api/port.test.js +35 -0
  123. package/packages/workers/api-node/config.d.ts +58 -9
  124. package/packages/workers/api-node/config.d.ts.map +1 -1
  125. package/packages/workers/api-node/config.js +140 -18
  126. package/packages/workers/api-node/config.test.js +52 -3
  127. package/packages/workers/api-node/port.d.ts +3 -0
  128. package/packages/workers/api-node/port.d.ts.map +1 -1
  129. package/packages/workers/api-node/port.js +31 -2
  130. package/packages/workers/api-node/port.test.js +17 -0
  131. package/packages/workers/api-node/protocol.d.ts +3 -3
  132. package/packages/workers/api-node/protocol.d.ts.map +1 -1
  133. package/packages/workers/api-node/protocol.js +18 -12
  134. package/packages/workers/block-authorship/{generator.d.ts → block-generator.d.ts} +5 -5
  135. package/packages/workers/block-authorship/block-generator.d.ts.map +1 -0
  136. package/packages/workers/block-authorship/{generator.js → block-generator.js} +3 -3
  137. package/packages/workers/block-authorship/block-generator.test.d.ts +2 -0
  138. package/packages/workers/block-authorship/block-generator.test.d.ts.map +1 -0
  139. package/packages/workers/block-authorship/{generator.test.js → block-generator.test.js} +8 -8
  140. package/packages/workers/block-authorship/epoch-authoring-slots.d.ts +35 -0
  141. package/packages/workers/block-authorship/epoch-authoring-slots.d.ts.map +1 -0
  142. package/packages/workers/block-authorship/epoch-authoring-slots.js +86 -0
  143. package/packages/workers/block-authorship/epoch-tracker.d.ts +29 -0
  144. package/packages/workers/block-authorship/epoch-tracker.d.ts.map +1 -0
  145. package/packages/workers/block-authorship/epoch-tracker.js +80 -0
  146. package/packages/workers/block-authorship/index.d.ts.map +1 -1
  147. package/packages/workers/block-authorship/index.js +1 -1
  148. package/packages/workers/block-authorship/main.d.ts +3 -0
  149. package/packages/workers/block-authorship/main.d.ts.map +1 -1
  150. package/packages/workers/block-authorship/main.js +194 -262
  151. package/packages/workers/block-authorship/ticket-generator/bootstrap-main.d.ts +2 -0
  152. package/packages/workers/block-authorship/ticket-generator/bootstrap-main.d.ts.map +1 -0
  153. package/packages/workers/block-authorship/ticket-generator/bootstrap-main.js +23 -0
  154. package/packages/workers/block-authorship/ticket-generator/index.d.ts +16 -0
  155. package/packages/workers/block-authorship/ticket-generator/index.d.ts.map +1 -0
  156. package/packages/workers/block-authorship/ticket-generator/index.js +62 -0
  157. package/packages/workers/block-authorship/ticket-generator/protocol.d.ts +50 -0
  158. package/packages/workers/block-authorship/ticket-generator/protocol.d.ts.map +1 -0
  159. package/packages/workers/block-authorship/ticket-generator/protocol.js +54 -0
  160. package/packages/workers/block-authorship/{ticket-generator.d.ts → ticket-generator/ticket-generator.d.ts} +4 -0
  161. package/packages/workers/block-authorship/ticket-generator/ticket-generator.d.ts.map +1 -0
  162. package/packages/workers/block-authorship/{ticket-generator.js → ticket-generator/ticket-generator.js} +19 -9
  163. package/packages/workers/block-authorship/ticket-generator/ticket-generator.test.d.ts.map +1 -0
  164. package/packages/workers/block-authorship/{ticket-generator.test.js → ticket-generator/ticket-generator.test.js} +13 -9
  165. package/packages/workers/block-authorship/ticket-generator/worker-pool.d.ts +36 -0
  166. package/packages/workers/block-authorship/ticket-generator/worker-pool.d.ts.map +1 -0
  167. package/packages/workers/block-authorship/ticket-generator/worker-pool.js +111 -0
  168. package/packages/workers/block-authorship/ticket-validator.d.ts +7 -8
  169. package/packages/workers/block-authorship/ticket-validator.d.ts.map +1 -1
  170. package/packages/workers/block-authorship/ticket-validator.js +26 -23
  171. package/packages/workers/comms-authorship-network/protocol.d.ts +4 -4
  172. package/packages/workers/comms-authorship-network/protocol.d.ts.map +1 -1
  173. package/packages/workers/comms-authorship-network/protocol.js +4 -5
  174. package/packages/workers/comms-authorship-network/tickets-message.d.ts +0 -14
  175. package/packages/workers/comms-authorship-network/tickets-message.d.ts.map +1 -1
  176. package/packages/workers/comms-authorship-network/tickets-message.js +0 -17
  177. package/packages/workers/importer/finality.d.ts +2 -0
  178. package/packages/workers/importer/finality.d.ts.map +1 -1
  179. package/packages/workers/importer/finality.js +8 -1
  180. package/packages/workers/importer/importer.d.ts +2 -2
  181. package/packages/workers/importer/importer.d.ts.map +1 -1
  182. package/packages/workers/importer/importer.js +6 -5
  183. package/packages/workers/importer/main.d.ts +1 -1
  184. package/packages/workers/importer/main.d.ts.map +1 -1
  185. package/packages/workers/importer/main.js +1 -1
  186. package/packages/workers/importer/stats.d.ts +1 -3
  187. package/packages/workers/importer/stats.d.ts.map +1 -1
  188. package/packages/workers/importer/stats.js +12 -12
  189. package/packages/workers/jam-network/main.d.ts.map +1 -1
  190. package/packages/workers/jam-network/main.js +9 -4
  191. package/packages/workers/block-authorship/generator.d.ts.map +0 -1
  192. package/packages/workers/block-authorship/generator.test.d.ts +0 -2
  193. package/packages/workers/block-authorship/generator.test.d.ts.map +0 -1
  194. package/packages/workers/block-authorship/ticket-generator.d.ts.map +0 -1
  195. package/packages/workers/block-authorship/ticket-generator.test.d.ts.map +0 -1
  196. /package/packages/configs/{typeberry-dev.json → typeberry-dev-tiny.json} +0 -0
  197. /package/packages/workers/block-authorship/{ticket-generator.test.d.ts → ticket-generator/ticket-generator.test.d.ts} +0 -0
@@ -1,6 +1,7 @@
1
+ import { type FjallValuesSession } from "#@typeberry/workers-api-node";
1
2
  import type { JamConfig } from "./jam-config.js";
2
3
  import type { NodeApi } from "./main.js";
3
- export type StateBackend = "lmdb" | "lmdb-hybrid" | "fjall-hybrid";
4
+ export type StateBackend = "lmdb" | "fjall" | "lmdb-hybrid" | "fjall-hybrid";
4
5
  export type ImporterOptions = {
5
6
  initGenesisFromAncestry?: boolean;
6
7
  dummyFinalityDepth?: number;
@@ -8,9 +9,17 @@ export type ImporterOptions = {
8
9
  /** Open the database without fsync/compression. Only safe for throwaway dbs (e.g. fuzzing). */
9
10
  ephemeral?: boolean;
10
11
  /**
11
- * Persistent backend to use when `databaseBasePath` is set. Defaults to full LMDB.
12
+ * Persistent backend used when `databaseBasePath` is set. Defaults to config's backend (fjall unless overridden).
13
+ *
14
+ * lmdb and lmdb-hybrid are deprecated and retained as explicit fallbacks.
12
15
  */
13
16
  stateBackend?: StateBackend;
17
+ /**
18
+ * Reuse an already-open fjall values session instead of opening a fresh
19
+ * keyspace. Only used when `stateBackend === "fjall-hybrid"`. The fuzz target
20
+ * opens one per run and reuses it across resets.
21
+ */
22
+ sharedFjallSession?: FjallValuesSession;
14
23
  };
15
24
  export declare function mainImporter(config: JamConfig, withRelPath: (v: string) => string, options?: ImporterOptions): Promise<NodeApi>;
16
25
  //# sourceMappingURL=main-importer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"main-importer.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main-importer.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,aAAa,GAAG,cAAc,CAAC;AAEnE,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC;AAEF,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAClC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,OAAO,CAAC,CAqGlB"}
1
+ {"version":3,"file":"main-importer.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main-importer.ts"],"names":[],"mappings":"AASA,OAAO,EACL,KAAK,kBAAkB,EAKxB,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,aAAa,GAAG,cAAc,CAAC;AAE7E,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC,CAAC;AAEF,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAClC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,OAAO,CAAC,CAqHlB"}
@@ -1,12 +1,12 @@
1
1
  import { Bytes } from "#@typeberry/bytes";
2
2
  import { PvmBackend } from "#@typeberry/config";
3
- import { KnownChainSpec } from "#@typeberry/config-node";
3
+ import { KnownChainSpec, RegularStateBackend } from "#@typeberry/config-node";
4
4
  import { bandersnatch, initWasm } from "#@typeberry/crypto";
5
5
  import { Blake2b, HASH_SIZE } from "#@typeberry/hash";
6
6
  import { createImporter, ImporterConfig } from "#@typeberry/importer";
7
7
  import { tryAsU16 } from "#@typeberry/numbers";
8
8
  import { CURRENT_SUITE, CURRENT_VERSION, Result, resultToString, version } from "#@typeberry/utils";
9
- import { HybridWorkerConfig, InMemWorkerConfig, LmdbWorkerConfig } from "#@typeberry/workers-api-node";
9
+ import { FjallWorkerConfig, HybridWorkerConfig, InMemWorkerConfig, LmdbWorkerConfig, } from "#@typeberry/workers-api-node";
10
10
  import { getChainSpec, getDatabasePath, initializeDatabase, logger } from "./common.js";
11
11
  const zeroHash = Bytes.zero(HASH_SIZE).asOpaque();
12
12
  export async function mainImporter(config, withRelPath, options = {}) {
@@ -18,8 +18,13 @@ export async function mainImporter(config, withRelPath, options = {}) {
18
18
  logger.info `🐇 Bandersnatch ${bandesnatchNative.isOk ? "native 🚀" : `using wasm: ${bandesnatchNative.error}`}`;
19
19
  // Single source of truth for the states db backend: drives both the log line
20
20
  // below and the worker config picked further down.
21
- const dbBackend = config.node.databaseBasePath === undefined ? "in-memory" : (options.stateBackend ?? "lmdb");
21
+ const dbBackend = config.node.databaseBasePath === undefined
22
+ ? "in-memory"
23
+ : (options.stateBackend ?? config.node.stateBackend ?? RegularStateBackend.Fjall);
22
24
  logger.info `🗄️ States DB: ${dbBackend}.`;
25
+ if (dbBackend === "lmdb" || dbBackend === "lmdb-hybrid") {
26
+ logger.warn `🗄️ The ${dbBackend} state backend is deprecated. Use fjall unless you need a temporary fallback.`;
27
+ }
23
28
  const chainSpec = getChainSpec(config.node.flavor);
24
29
  const blake2b = await Blake2b.createHasher();
25
30
  const nodeName = config.nodeName;
@@ -49,18 +54,28 @@ export async function mainImporter(config, withRelPath, options = {}) {
49
54
  ephemeral,
50
55
  compression,
51
56
  backend: dbBackend === "lmdb-hybrid" ? "lmdb" : "fjall",
57
+ sharedFjallSession: options.sharedFjallSession,
52
58
  })
53
- : LmdbWorkerConfig.new({
54
- nodeName,
55
- chainSpec,
56
- blake2b,
57
- dbPath,
58
- workerParams,
59
- ephemeral,
60
- });
59
+ : dbBackend === "fjall"
60
+ ? FjallWorkerConfig.new({
61
+ nodeName,
62
+ chainSpec,
63
+ blake2b,
64
+ dbPath,
65
+ workerParams,
66
+ ephemeral,
67
+ })
68
+ : LmdbWorkerConfig.new({
69
+ nodeName,
70
+ chainSpec,
71
+ blake2b,
72
+ dbPath,
73
+ workerParams,
74
+ ephemeral,
75
+ });
61
76
  // Initialize the database with genesis state and block if there isn't one.
62
77
  logger.info `🛢️ Opening database at ${dbPath}`;
63
- const rootDb = workerConfig.openDatabase({ readonly: false });
78
+ const rootDb = await workerConfig.openDatabase({ readonly: false });
64
79
  await initializeDatabase(chainSpec, blake2b, genesisHeaderHash, rootDb, config.node.chainSpec, config.ancestry, {
65
80
  initGenesisFromAncestry: options.initGenesisFromAncestry,
66
81
  });
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAc,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEzF,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,mBAAmB,CAAC;AAe/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAkC,MAAM,EAAW,MAAM,kBAAkB,CAAC;AAKnF,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,iBAAiB,CAAC;AAWhE,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAChE,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;IACtE,oBAAoB,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,wBAAsB,IAAI,CACxB,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAClC,SAAS,EAAE,SAAS,GAAG,IAAI,GAC1B,OAAO,CAAC,OAAO,CAAC,CA2KlB"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAc,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEzF,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,mBAAmB,CAAC;AAgB/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAkC,MAAM,EAAW,MAAM,kBAAkB,CAAC;AAYnF,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,iBAAiB,CAAC;AAWhE,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAChE,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;IACtE,oBAAoB,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,wBAAsB,IAAI,CACxB,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAClC,SAAS,EAAE,SAAS,GAAG,IAAI,GAC1B,OAAO,CAAC,OAAO,CAAC,CA2LlB"}
@@ -1,6 +1,7 @@
1
1
  import { isMainThread } from "node:worker_threads";
2
2
  import { AUTHORSHIP_NETWORK_PORT } from "#@typeberry/comms-authorship-network";
3
3
  import { PvmBackend } from "#@typeberry/config";
4
+ import { RegularStateBackend } from "#@typeberry/config-node";
4
5
  import { initWasm } from "#@typeberry/crypto";
5
6
  import { deriveBandersnatchSecretKey, deriveEd25519SecretKey, trivialSeed, } from "#@typeberry/crypto/key-derivation.js";
6
7
  import { Blake2b } from "#@typeberry/hash";
@@ -10,7 +11,7 @@ import { Listener } from "#@typeberry/listener";
10
11
  import { tryAsU16, tryAsU32 } from "#@typeberry/numbers";
11
12
  import { CURRENT_SUITE, CURRENT_VERSION, Result, version } from "#@typeberry/utils";
12
13
  import { DirectPort, DirectWorkerConfig } from "#@typeberry/workers-api";
13
- import { InMemWorkerConfig, LmdbWorkerConfig, logHostEnvironment, ThreadPort } from "#@typeberry/workers-api-node";
14
+ import { FjallWorkerConfig, InMemWorkerConfig, LmdbWorkerConfig, logHostEnvironment, ThreadPort, } from "#@typeberry/workers-api-node";
14
15
  import { getChainSpec, getDatabasePath, initializeDatabase, logger } from "./common.js";
15
16
  import { initializeExtensions } from "./extensions.js";
16
17
  import * as metrics from "./metrics.js";
@@ -29,9 +30,12 @@ export async function main(config, withRelPath, telemetry) {
29
30
  const blake2b = await Blake2b.createHasher();
30
31
  const nodeName = config.nodeName;
31
32
  const isInMemory = config.node.databaseBasePath === undefined;
32
- logger.info `🗄️ States DB: ${isInMemory ? "in-memory" : "lmdb"}.`;
33
+ logger.info `🗄️ States DB: ${isInMemory ? "in-memory" : config.node.stateBackend}.`;
34
+ if (!isInMemory && config.node.stateBackend === RegularStateBackend.Lmdb) {
35
+ logger.warn `🗄️ The lmdb state backend is deprecated. Use state_backend="fjall" unless you need a temporary fallback.`;
36
+ }
33
37
  const { dbPath, genesisHeaderHash } = getDatabasePath(blake2b, nodeName, config.node.chainSpec.genesisHeader, withRelPath(config.node.databaseBasePath ?? "<in-memory>"));
34
- const baseConfig = { nodeName, chainSpec, blake2b, dbPath };
38
+ const baseConfig = { nodeName, chainSpec, blake2b, dbPath, stateBackend: config.node.stateBackend };
35
39
  const importerParams = {
36
40
  ...baseConfig,
37
41
  workerParams: ImporterConfig.create({
@@ -42,16 +46,29 @@ export async function main(config, withRelPath, telemetry) {
42
46
  };
43
47
  const importerConfig = isInMemory
44
48
  ? { isInMemory, config: InMemWorkerConfig.new(importerParams) }
45
- : { isInMemory, config: LmdbWorkerConfig.new(importerParams) };
49
+ : { isInMemory, config: createPersistentWorkerConfig(importerParams) };
46
50
  // Initialize the database with genesis state and block if there isn't one.
47
51
  logger.info `🛢️ Opening database at ${dbPath}`;
48
- const rootDb = importerConfig.config.openDatabase({ readonly: false });
49
- await initializeDatabase(chainSpec, blake2b, genesisHeaderHash, rootDb, config.node.chainSpec, config.ancestry);
50
- // NOTE [ToDr] even though, we should be closing the database here,
51
- // it seems that opening it in the main thread for writing, and later
52
- // in the importer thread, causes issues. Everything works fine though,
53
- // if we DO NOT close the database (I guess it's process-shared?)
54
- // await rootDb.close();
52
+ const rootDb = await importerConfig.config.openDatabase({ readonly: false });
53
+ try {
54
+ await initializeDatabase(chainSpec, blake2b, genesisHeaderHash, rootDb, config.node.chainSpec, config.ancestry);
55
+ }
56
+ catch (e) {
57
+ try {
58
+ await rootDb.close();
59
+ }
60
+ catch (closeError) {
61
+ logger.warn `Failed to close database after initialization error: ${closeError}`;
62
+ }
63
+ throw e;
64
+ }
65
+ // fjall-js shares the engine explicitly and requires every handle to close.
66
+ // Keep lmdb's historical main-thread handle open until shutdown.
67
+ let mainRootDb = rootDb;
68
+ if (!importerConfig.isInMemory && config.node.stateBackend === RegularStateBackend.Fjall) {
69
+ await rootDb.close();
70
+ mainRootDb = null;
71
+ }
55
72
  // Start block importer
56
73
  let importer;
57
74
  let closeImporter;
@@ -138,8 +155,10 @@ export async function main(config, withRelPath, telemetry) {
138
155
  await closeImporter();
139
156
  logger.log `[main] ☠️ Closing the extensions`;
140
157
  closeExtensions();
141
- logger.log `[main] 🛢️ Closing the database`;
142
- await rootDb.close();
158
+ if (mainRootDb !== null) {
159
+ logger.log `[main] 🛢️ Closing the database`;
160
+ await mainRootDb.close();
161
+ }
143
162
  logger.log `[main] 📳 Closing telemetry`;
144
163
  await telemetry?.close();
145
164
  logger.info `[main] ✅ Done.`;
@@ -167,7 +186,7 @@ const initAuthorship = async (importer, isAuthoring, isFastForward, params, base
167
186
  statesDb: params.rootDb.getStatesDb(),
168
187
  workerParams,
169
188
  }), params.networkingPort)
170
- : await spawnBlockGeneratorWorker(LmdbWorkerConfig.new({
189
+ : await spawnBlockGeneratorWorker(createPersistentWorkerConfig({
171
190
  ...baseConfig,
172
191
  workerParams,
173
192
  ports: new Map([[AUTHORSHIP_NETWORK_PORT, params.networkingPort]]),
@@ -205,7 +224,7 @@ const initNetwork = async (importer, params, baseConfig, genesisHeaderHash, netw
205
224
  statesDb: params.rootDb.getStatesDb(),
206
225
  workerParams: networkingConfig,
207
226
  }), params.authorshipPort)
208
- : await spawnNetworkWorker(LmdbWorkerConfig.new({
227
+ : await spawnNetworkWorker(createPersistentWorkerConfig({
209
228
  ...baseConfig,
210
229
  workerParams: networkingConfig,
211
230
  ports: new Map([[AUTHORSHIP_NETWORK_PORT, params.authorshipPort]]),
@@ -222,3 +241,11 @@ const initNetwork = async (importer, params, baseConfig, genesisHeaderHash, netw
222
241
  });
223
242
  return { closeNetwork: finish, networkApi: network, networkWorker: worker };
224
243
  };
244
+ function createPersistentWorkerConfig({ stateBackend, ...params }) {
245
+ switch (stateBackend) {
246
+ case RegularStateBackend.Fjall:
247
+ return FjallWorkerConfig.new(params);
248
+ case RegularStateBackend.Lmdb:
249
+ return LmdbWorkerConfig.new(params);
250
+ }
251
+ }
@@ -5,8 +5,8 @@ import * as importer from "#@typeberry/importer";
5
5
  import * as jamNetwork from "#@typeberry/jam-network";
6
6
  import type { SerializedState } from "#@typeberry/state-merkleization";
7
7
  import { type DirectPort, type DirectWorkerConfig } from "#@typeberry/workers-api";
8
- import { type LmdbWorkerConfig } from "#@typeberry/workers-api-node";
9
- export declare function spawnImporterWorker(config: LmdbWorkerConfig<importer.ImporterConfig>): Promise<{
8
+ import { type PersistentWorkerConfig } from "#@typeberry/workers-api-node";
9
+ export declare function spawnImporterWorker(config: PersistentWorkerConfig<importer.ImporterConfig>): Promise<{
10
10
  importer: import("@typeberry/workers-api").Tx<{
11
11
  getStateEntries: {
12
12
  request: import("@typeberry/codec").Descriptor<import("@typeberry/bytes").Bytes<32> & import("@typeberry/utils").WithOpaque<"HeaderHash">, import("@typeberry/bytes").Bytes<32>>;
@@ -376,7 +376,7 @@ export declare function spawnImporterWorker(config: LmdbWorkerConfig<importer.Im
376
376
  finish: () => Promise<void>;
377
377
  }>;
378
378
  export declare function startImporterDirect(config: DirectWorkerConfig<importer.ImporterConfig, BlocksDb, StatesDb<SerializedState<LeafDb>>>): ReturnType<typeof spawnImporterWorker>;
379
- export declare function spawnNetworkWorker(config: LmdbWorkerConfig<jamNetwork.NetworkingConfig>): Promise<{
379
+ export declare function spawnNetworkWorker(config: PersistentWorkerConfig<jamNetwork.NetworkingConfig>): Promise<{
380
380
  network: import("@typeberry/workers-api").Tx<{
381
381
  newHeader: {
382
382
  request: import("@typeberry/codec").Descriptor<import("@typeberry/hash").WithHash<import("@typeberry/hash").OpaqueHash & import("@typeberry/utils").WithOpaque<"HeaderHash">, import("@typeberry/codec").ViewOf<import("@typeberry/block").Header & import("@typeberry/codec").CodecRecord<import("@typeberry/block").Header>, {
@@ -865,7 +865,7 @@ export declare function spawnNetworkWorker(config: LmdbWorkerConfig<jamNetwork.N
865
865
  export declare function startNetwork(config: DirectWorkerConfig<jamNetwork.NetworkingConfig>, authorshipPort: DirectPort): Promise<Omit<Awaited<ReturnType<typeof spawnNetworkWorker>>, "worker"> & {
866
866
  worker: Worker | null;
867
867
  }>;
868
- export declare function spawnBlockGeneratorWorker(config: LmdbWorkerConfig<blockAuthorship.BlockAuthorshipConfig>): Promise<{
868
+ export declare function spawnBlockGeneratorWorker(config: PersistentWorkerConfig<blockAuthorship.BlockAuthorshipConfig>): Promise<{
869
869
  generator: import("@typeberry/workers-api").Tx<{
870
870
  finish: {
871
871
  request: import("@typeberry/codec").Descriptor<void, void>;
@@ -1 +1 @@
1
- {"version":3,"file":"workers.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/workers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workers.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/workers.ts"],"names":[],"mappings":"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"}
@@ -27,7 +27,27 @@ declare function generateSeal(bandersnatch: BandernsatchWasm, authorKey: Banders
27
27
  export type VrfOutputHash = Opaque<OpaqueHash, "VRF Output Hash">;
28
28
  declare function getVrfOutputHash(bandersnatch: BandernsatchWasm, authorKey: BandersnatchSecretSeed, input: BytesBlob): Promise<Result<VrfOutputHash, null>>;
29
29
  /**
30
- * Generates signed tickets for all attempts at once using batch ring VRF.
30
+ * Batch-generate signed tickets for multiple validators in a single native call,
31
+ * reusing the ring prover setup across all of them. Returns one ticket list per
32
+ * validator, in the same order as `proverKeyIndices`/`secrets`.
31
33
  */
32
- declare function generateTickets(bandersnatch: BandernsatchWasm, ringKeys: BandersnatchKey[], proverKeyIndex: number, key: BandersnatchSecretSeed, entropy: EntropyHash, ticketsPerValidator: number): Promise<Result<SignedTicket[], null>>;
34
+ declare function generateTickets(bandersnatch: BandernsatchWasm, ringKeys: BandersnatchKey[], proverKeyIndices: readonly number[], secrets: readonly BandersnatchSecretSeed[], entropy: EntropyHash, ticketsPerValidator: number): Promise<Result<SignedTicket[][], null>>;
35
+ /**
36
+ * Build the concatenated ring-VRF inputs for ticket generation: one
37
+ * `JAM_TICKET_SEAL || entropy || attempt_byte` input per attempt.
38
+ *
39
+ * Exposed so the worker-pool path can build the same inputs to hand off to a
40
+ * worker thread without re-deriving the layout.
41
+ */
42
+ export declare function buildTicketVrfInputs(entropy: EntropyHash, ticketsPerValidator: number): {
43
+ inputsData: Uint8Array;
44
+ vrfInputDataLen: number;
45
+ };
46
+ /**
47
+ * Parse the raw output of `batchGenerateRingVrfForValidators` into per-validator
48
+ * ticket lists. Records are ordered validator-major, then attempt-major; each
49
+ * record is `status byte || signature`. A malformed batch yields a single error
50
+ * byte. Exposed so the worker-pool path can parse a worker's raw result.
51
+ */
52
+ export declare function parseTicketsBatchOutput(result: Uint8Array, numValidators: number, ticketsPerValidator: number): Result<SignedTicket[][], null>;
33
53
  //# sourceMappingURL=bandersnatch-vrf.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bandersnatch-vrf.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/safrole/bandersnatch-vrf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAsB,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAS,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC9B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAwC/D,QAAA,MAAM,SAAS;;;;;;;;CAQd,CAAC;AAKF,eAAe,SAAS,CAAC;AAIzB,iBAAe,iBAAiB,CAC9B,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,eAAe,EAC1B,SAAS,EAAE,wBAAwB,EACnC,OAAO,EAAE,SAAS,EAClB,qBAAqB,EAAE,SAAS,EAChC,gBAAgB,EAAE,wBAAwB,EAC1C,oBAAoB,EAAE,SAAS,GAC9B,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC,CAkBnD;AAED,iBAAe,UAAU,CACvB,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,eAAe,EAC1B,SAAS,EAAE,wBAAwB,EACnC,OAAO,EAAE,SAAS,EAClB,qBAAqB,EAAE,SAAS,GAC/B,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAapC;AAED,iBAAS,iBAAiB,CACxB,YAAY,EAAE,gBAAgB,EAC9B,UAAU,EAAE,eAAe,EAAE,GAC5B,OAAO,CAAC,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC,CAe7C;AAgBD,iBAAe,aAAa,CAC1B,YAAY,EAAE,gBAAgB,EAC9B,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,oBAAoB,EAC/B,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,WAAW,EAAE,CAAA;CAAE,CAAC,CA0BvD;AAGD,iBAAe,YAAY,CACzB,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,sBAAsB,EACjC,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,MAAM,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC,CAQjD;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;AAGlE,iBAAe,gBAAgB,CAC7B,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,sBAAsB,EACjC,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAQtC;AAKD;;GAEG;AACH,iBAAe,eAAe,CAC5B,YAAY,EAAE,gBAAgB,EAC9B,QAAQ,EAAE,eAAe,EAAE,EAC3B,cAAc,EAAE,MAAM,EACtB,GAAG,EAAE,sBAAsB,EAC3B,OAAO,EAAE,WAAW,EACpB,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,IAAI,CAAC,CAAC,CA0CvC"}
1
+ {"version":3,"file":"bandersnatch-vrf.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/safrole/bandersnatch-vrf.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { SignedTicket, tryAsTicketAttempt } from "#@typeberry/block/tickets.js";
2
2
  import { Bytes, BytesBlob } from "#@typeberry/bytes";
3
+ import { SEED_SIZE } from "#@typeberry/crypto";
3
4
  import { BANDERSNATCH_PROOF_BYTES, BANDERSNATCH_RING_ROOT_BYTES, BANDERSNATCH_VRF_SIGNATURE_BYTES, } from "#@typeberry/crypto/bandersnatch.js";
4
5
  import { HASH_SIZE } from "#@typeberry/hash";
5
6
  import { Result } from "#@typeberry/utils";
@@ -33,6 +34,10 @@ const ringCommitmentCache = [
33
34
  keys: BytesBlob.empty(),
34
35
  value: Promise.resolve(Result.error(null, () => "")),
35
36
  },
37
+ {
38
+ keys: BytesBlob.empty(),
39
+ value: Promise.resolve(Result.error(null, () => "")),
40
+ },
36
41
  ];
37
42
  const FUNCTIONS = {
38
43
  verifySeal,
@@ -122,31 +127,60 @@ async function getVrfOutputHash(bandersnatch, authorKey, input) {
122
127
  // One byte for result discriminator and the rest is the ring VRF signature.
123
128
  const GENERATE_RESULT_ENTRY_LENGTH = 1 + BANDERSNATCH_PROOF_BYTES;
124
129
  /**
125
- * Generates signed tickets for all attempts at once using batch ring VRF.
130
+ * Batch-generate signed tickets for multiple validators in a single native call,
131
+ * reusing the ring prover setup across all of them. Returns one ticket list per
132
+ * validator, in the same order as `proverKeyIndices`/`secrets`.
126
133
  */
127
- async function generateTickets(bandersnatch, ringKeys, proverKeyIndex, key, entropy, ticketsPerValidator) {
128
- // Build VRF inputs: JAM_TICKET_SEAL || entropy || attempt_byte for each attempt
134
+ async function generateTickets(bandersnatch, ringKeys, proverKeyIndices, secrets, entropy, ticketsPerValidator) {
135
+ if (proverKeyIndices.length !== secrets.length) {
136
+ return Result.error(null, () => "proverKeyIndices and secrets must have the same length");
137
+ }
138
+ if (proverKeyIndices.length === 0) {
139
+ return Result.ok([]);
140
+ }
141
+ const { inputsData, vrfInputDataLen } = buildTicketVrfInputs(entropy, ticketsPerValidator);
142
+ const ringKeysData = BytesBlob.blobFromParts(ringKeys.map((k) => k.raw)).raw;
143
+ const secretSeedsData = BytesBlob.blobFromParts(secrets.map((s) => s.raw)).raw;
144
+ const result = await bandersnatch.batchGenerateRingVrfForValidators(ringKeysData, Uint32Array.from(proverKeyIndices), secretSeedsData, SEED_SIZE, inputsData, vrfInputDataLen);
145
+ return parseTicketsBatchOutput(result, proverKeyIndices.length, ticketsPerValidator);
146
+ }
147
+ /**
148
+ * Build the concatenated ring-VRF inputs for ticket generation: one
149
+ * `JAM_TICKET_SEAL || entropy || attempt_byte` input per attempt.
150
+ *
151
+ * Exposed so the worker-pool path can build the same inputs to hand off to a
152
+ * worker thread without re-deriving the layout.
153
+ */
154
+ export function buildTicketVrfInputs(entropy, ticketsPerValidator) {
129
155
  const vrfInputParts = [];
130
156
  for (let attempt = 0; attempt < ticketsPerValidator; attempt++) {
131
157
  vrfInputParts.push(BytesBlob.blobFromParts([JAM_TICKET_SEAL, entropy.raw, Uint8Array.of(attempt)]).raw);
132
158
  }
133
- const attemptLength = 1;
134
- const vrfInputDataLen = JAM_TICKET_SEAL.length + entropy.length + attemptLength;
135
- const inputsData = BytesBlob.blobFromParts(vrfInputParts).raw;
136
- const ringKeysData = BytesBlob.blobFromParts(ringKeys.map((k) => k.raw)).raw;
137
- const result = await bandersnatch.batchGenerateRingVrf(ringKeysData, proverKeyIndex, key.raw, inputsData, vrfInputDataLen);
138
- const tickets = [];
139
- for (let attempt = 0; attempt < ticketsPerValidator; attempt++) {
140
- const offset = attempt * GENERATE_RESULT_ENTRY_LENGTH;
141
- const resultByte = result[offset];
142
- if (resultByte === ResultValues.Error) {
143
- return Result.error(null, () => `Ring VRF proof generation failed for attempt ${attempt}`);
159
+ return {
160
+ inputsData: BytesBlob.blobFromParts(vrfInputParts).raw,
161
+ vrfInputDataLen: JAM_TICKET_SEAL.length + entropy.length + 1,
162
+ };
163
+ }
164
+ /**
165
+ * Parse the raw output of `batchGenerateRingVrfForValidators` into per-validator
166
+ * ticket lists. Records are ordered validator-major, then attempt-major; each
167
+ * record is `status byte || signature`. A malformed batch yields a single error
168
+ * byte. Exposed so the worker-pool path can parse a worker's raw result.
169
+ */
170
+ export function parseTicketsBatchOutput(result, numValidators, ticketsPerValidator) {
171
+ const perValidator = [];
172
+ let offset = 0;
173
+ for (let v = 0; v < numValidators; v++) {
174
+ const tickets = [];
175
+ for (let attempt = 0; attempt < ticketsPerValidator; attempt++) {
176
+ if (result[offset] === ResultValues.Error) {
177
+ return Result.error(null, () => `Ring VRF proof generation failed for validator ${v}, attempt ${attempt}`);
178
+ }
179
+ const signature = Bytes.fromBlob(result.subarray(offset + 1, offset + GENERATE_RESULT_ENTRY_LENGTH), BANDERSNATCH_PROOF_BYTES).asOpaque();
180
+ tickets.push(SignedTicket.create({ attempt: tryAsTicketAttempt(attempt), signature }));
181
+ offset += GENERATE_RESULT_ENTRY_LENGTH;
144
182
  }
145
- const signature = Bytes.fromBlob(new Uint8Array(result.subarray(offset + 1, offset + GENERATE_RESULT_ENTRY_LENGTH)), BANDERSNATCH_PROOF_BYTES).asOpaque();
146
- tickets.push(SignedTicket.create({
147
- attempt: tryAsTicketAttempt(attempt),
148
- signature,
149
- }));
183
+ perValidator.push(tickets);
150
184
  }
151
- return Result.ok(tickets);
185
+ return Result.ok(perValidator);
152
186
  }
@@ -165,11 +165,12 @@ describe("Bandersnatch verification", () => {
165
165
  const ringKeys = secrets.map((secret) => deriveBandersnatchPublicKey(secret));
166
166
  const proverIndex = 0;
167
167
  const entropy = Bytes.fill(HASH_SIZE, 123).asOpaque();
168
- const genResult = await bandersnatchVrf.generateTickets(await bandersnatchWasm, ringKeys, proverIndex, secrets[proverIndex], entropy, 2);
168
+ const genResult = await bandersnatchVrf.generateTickets(await bandersnatchWasm, ringKeys, [proverIndex], [secrets[proverIndex]], entropy, 2);
169
169
  assert.ok(genResult.isOk);
170
170
  const commitment = await bandersnatchVrf.getRingCommitment(await bandersnatchWasm, ringKeys);
171
171
  assert.ok(commitment.isOk);
172
- const verifyResult = await bandersnatchVrf.verifyTickets(await bandersnatchWasm, ringKeys.length, commitment.ok, genResult.ok, entropy);
172
+ assert.strictEqual(genResult.ok.length, 1);
173
+ const verifyResult = await bandersnatchVrf.verifyTickets(await bandersnatchWasm, ringKeys.length, commitment.ok, genResult.ok[0], entropy);
173
174
  assert.ok(verifyResult.isValid, "Generated tickets should pass verification");
174
175
  });
175
176
  });
@@ -8,5 +8,15 @@ export declare class BandernsatchWasm {
8
8
  generateSeal(authorKey: Uint8Array, input: Uint8Array, auxData: Uint8Array): Promise<Uint8Array<ArrayBufferLike>>;
9
9
  getVrfOutputHash(authorKey: Uint8Array, input: Uint8Array): Promise<Uint8Array<ArrayBufferLike>>;
10
10
  batchGenerateRingVrf(ringKeys: Uint8Array, proverKeyIndex: number, secretSeed: Uint8Array, inputsData: Uint8Array, vrfInputDataLen: number): Promise<Uint8Array<ArrayBufferLike>>;
11
+ /**
12
+ * Batch-generate ring VRF tickets for multiple validators in a single call,
13
+ * reusing the ring prover setup across all of them.
14
+ *
15
+ * `secretSeedsData` is the fixed-width concatenation of the validators' secret
16
+ * seeds (each `secretSeedDataLen` bytes); `proverKeyIndices` are their indices
17
+ * within the ring and must have the same count. Output records are ordered
18
+ * validator-major then input-major, each `status byte || signature`.
19
+ */
20
+ batchGenerateRingVrfForValidators(ringKeys: Uint8Array, proverKeyIndices: Uint32Array, secretSeedsData: Uint8Array, secretSeedDataLen: number, inputsData: Uint8Array, vrfInputDataLen: number): Promise<Uint8Array<ArrayBufferLike>>;
11
21
  }
12
22
  //# sourceMappingURL=bandersnatch-wasm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bandersnatch-wasm.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/safrole/bandersnatch-wasm.ts"],"names":[],"mappings":"AAEA,qBAAa,gBAAgB;IAC3B,OAAO;WAEM,GAAG;IAKV,UAAU,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU;IAIjG,iBAAiB,CACrB,SAAS,EAAE,UAAU,EACrB,UAAU,EAAE,UAAU,EACtB,iBAAiB,EAAE,UAAU,EAC7B,cAAc,EAAE,UAAU,EAC1B,WAAW,EAAE,UAAU,EACvB,oBAAoB,EAAE,UAAU;IAY5B,iBAAiB,CAAC,IAAI,EAAE,UAAU;IAIlC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM;IAI1G,YAAY,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU;IAI1E,gBAAgB,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU;IAIzD,oBAAoB,CACxB,QAAQ,EAAE,UAAU,EACpB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,UAAU,EACtB,eAAe,EAAE,MAAM;CAI1B"}
1
+ {"version":3,"file":"bandersnatch-wasm.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/safrole/bandersnatch-wasm.ts"],"names":[],"mappings":"AAEA,qBAAa,gBAAgB;IAC3B,OAAO;WAEM,GAAG;IAKV,UAAU,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU;IAIjG,iBAAiB,CACrB,SAAS,EAAE,UAAU,EACrB,UAAU,EAAE,UAAU,EACtB,iBAAiB,EAAE,UAAU,EAC7B,cAAc,EAAE,UAAU,EAC1B,WAAW,EAAE,UAAU,EACvB,oBAAoB,EAAE,UAAU;IAY5B,iBAAiB,CAAC,IAAI,EAAE,UAAU;IAIlC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM;IAI1G,YAAY,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU;IAI1E,gBAAgB,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU;IAIzD,oBAAoB,CACxB,QAAQ,EAAE,UAAU,EACpB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,UAAU,EACtB,eAAe,EAAE,MAAM;IAKzB;;;;;;;;OAQG;IACG,iCAAiC,CACrC,QAAQ,EAAE,UAAU,EACpB,gBAAgB,EAAE,WAAW,EAC7B,eAAe,EAAE,UAAU,EAC3B,iBAAiB,EAAE,MAAM,EACzB,UAAU,EAAE,UAAU,EACtB,eAAe,EAAE,MAAM;CAW1B"}
@@ -26,4 +26,16 @@ export class BandernsatchWasm {
26
26
  async batchGenerateRingVrf(ringKeys, proverKeyIndex, secretSeed, inputsData, vrfInputDataLen) {
27
27
  return bandersnatchWasm.batchGenerateRingVrf(ringKeys, proverKeyIndex, secretSeed, inputsData, vrfInputDataLen);
28
28
  }
29
+ /**
30
+ * Batch-generate ring VRF tickets for multiple validators in a single call,
31
+ * reusing the ring prover setup across all of them.
32
+ *
33
+ * `secretSeedsData` is the fixed-width concatenation of the validators' secret
34
+ * seeds (each `secretSeedDataLen` bytes); `proverKeyIndices` are their indices
35
+ * within the ring and must have the same count. Output records are ordered
36
+ * validator-major then input-major, each `status byte || signature`.
37
+ */
38
+ async batchGenerateRingVrfForValidators(ringKeys, proverKeyIndices, secretSeedsData, secretSeedDataLen, inputsData, vrfInputDataLen) {
39
+ return bandersnatchWasm.batchGenerateRingVrfForValidators(ringKeys, proverKeyIndices, secretSeedsData, secretSeedDataLen, inputsData, vrfInputDataLen);
40
+ }
29
41
  }
@@ -9,7 +9,8 @@ import { Result } from "#@typeberry/utils";
9
9
  * it delegates to another process that doesn't bother to send the id back over the wire.
10
10
  */
11
11
  export type ValidatedTicket = {
12
- id: EntropyHash | null;
12
+ ticket: SignedTicket;
13
+ id: EntropyHash;
13
14
  };
14
15
  /** Reasons a ticket may fail validation. */
15
16
  export declare enum ValidationError {
@@ -27,20 +28,20 @@ export declare enum ValidationError {
27
28
  * worker via IPC, or short-circuit (Accept/Deny defaults for tests).
28
29
  */
29
30
  export interface TicketValidator {
30
- validate(epochIndex: Epoch, ticket: SignedTicket): Promise<Result<ValidatedTicket, ValidationError>>;
31
+ validate(epochIndex: Epoch, tickets: SignedTicket[]): Promise<Result<ValidatedTicket[], ValidationError>>;
31
32
  }
32
33
  /**
33
34
  * Accepts every ticket without inspection. Useful for unit tests where the validator
34
35
  * isn't the subject under test. Must never be used in production.
35
36
  */
36
37
  export declare class AcceptTicketsValidator implements TicketValidator {
37
- validate(_epochIndex: Epoch, _ticket: SignedTicket): Promise<Result<ValidatedTicket, ValidationError>>;
38
+ validate(_epochIndex: Epoch, ticket: SignedTicket[]): Promise<Result<ValidatedTicket[], ValidationError>>;
38
39
  }
39
40
  /**
40
41
  * Rejects every ticket. Used as the default for any task that needs an explicit, real
41
42
  * validator wired in before it will accept anything from the network.
42
43
  */
43
44
  export declare class DenyTicketsValidator implements TicketValidator {
44
- validate(_epochIndex: Epoch, _ticket: SignedTicket): Promise<Result<ValidatedTicket, ValidationError>>;
45
+ validate(_epochIndex: Epoch, _tickets: SignedTicket[]): Promise<Result<ValidatedTicket[], ValidationError>>;
45
46
  }
46
47
  //# sourceMappingURL=ticket-validator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ticket-validator.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/ticket-pool/ticket-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;CACxB,CAAC;AAEF,4CAA4C;AAC5C,oBAAY,eAAe;IACzB,+CAA+C;IAC/C,YAAY,kBAAkB;IAC9B,oFAAoF;IACpF,oBAAoB,0BAA0B;IAC9C,yEAAyE;IACzE,UAAU,gBAAgB;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC,CAAC;CACtG;AAED;;;GAGG;AACH,qBAAa,sBAAuB,YAAW,eAAe;IACtD,QAAQ,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;CAG7G;AAED;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IACpD,QAAQ,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;CAG7G"}
1
+ {"version":3,"file":"ticket-validator.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/ticket-pool/ticket-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,EAAE,EAAE,WAAW,CAAC;CACjB,CAAC;AAEF,4CAA4C;AAC5C,oBAAY,eAAe;IACzB,+CAA+C;IAC/C,YAAY,kBAAkB;IAC9B,oFAAoF;IACpF,oBAAoB,0BAA0B;IAC9C,yEAAyE;IACzE,UAAU,gBAAgB;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;CAC3G;AAED;;;GAGG;AACH,qBAAa,sBAAuB,YAAW,eAAe;IACtD,QAAQ,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,EAAE,eAAe,CAAC,CAAC;CAQhH;AAED;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IACpD,QAAQ,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,EAAE,eAAe,CAAC,CAAC;CAGlH"}
@@ -1,3 +1,5 @@
1
+ import { Bytes } from "#@typeberry/bytes";
2
+ import { HASH_SIZE } from "#@typeberry/hash";
1
3
  import { Result } from "#@typeberry/utils";
2
4
  /** Reasons a ticket may fail validation. */
3
5
  export var ValidationError;
@@ -14,8 +16,11 @@ export var ValidationError;
14
16
  * isn't the subject under test. Must never be used in production.
15
17
  */
16
18
  export class AcceptTicketsValidator {
17
- async validate(_epochIndex, _ticket) {
18
- return Result.ok({ id: null });
19
+ async validate(_epochIndex, ticket) {
20
+ return Result.ok(ticket.map((ticket) => ({
21
+ ticket,
22
+ id: Bytes.zero(HASH_SIZE).asOpaque(),
23
+ })));
19
24
  }
20
25
  }
21
26
  /**
@@ -23,7 +28,7 @@ export class AcceptTicketsValidator {
23
28
  * validator wired in before it will accept anything from the network.
24
29
  */
25
30
  export class DenyTicketsValidator {
26
- async validate(_epochIndex, _ticket) {
31
+ async validate(_epochIndex, _tickets) {
27
32
  return Result.error(ValidationError.ValidatorUnavailable, () => "no ticket validator wired");
28
33
  }
29
34
  }
@@ -4,6 +4,7 @@ import { tryAsEpoch } from "#@typeberry/block";
4
4
  import { SignedTicket, tryAsTicketAttempt } from "#@typeberry/block/tickets.js";
5
5
  import { Bytes } from "#@typeberry/bytes";
6
6
  import { BANDERSNATCH_PROOF_BYTES } from "#@typeberry/crypto";
7
+ import { HASH_SIZE } from "#@typeberry/hash";
7
8
  import { AcceptTicketsValidator, DenyTicketsValidator, ValidationError } from "./ticket-validator.js";
8
9
  const E1 = tryAsEpoch(1);
9
10
  function makeTicket() {
@@ -13,19 +14,19 @@ function makeTicket() {
13
14
  });
14
15
  }
15
16
  describe("AcceptTicketsValidator", () => {
16
- it("returns ok with null id", async () => {
17
+ it("returns ok with zero id", async () => {
17
18
  const v = new AcceptTicketsValidator();
18
- const res = await v.validate(E1, makeTicket());
19
+ const res = await v.validate(E1, [makeTicket()]);
19
20
  assert.strictEqual(res.isOk, true);
20
21
  if (res.isOk) {
21
- assert.strictEqual(res.ok.id, null);
22
+ assert.strictEqual(res.ok[0].id.toString(), Bytes.zero(HASH_SIZE).toString());
22
23
  }
23
24
  });
24
25
  });
25
26
  describe("DenyTicketsValidator", () => {
26
27
  it("returns ValidatorUnavailable", async () => {
27
28
  const v = new DenyTicketsValidator();
28
- const res = await v.validate(E1, makeTicket());
29
+ const res = await v.validate(E1, [makeTicket()]);
29
30
  assert.strictEqual(res.isError, true);
30
31
  if (res.isError) {
31
32
  assert.strictEqual(res.error, ValidationError.ValidatorUnavailable);
@@ -16,6 +16,8 @@ export type VerifiedTicket = {
16
16
  export declare class VerifiedTicketPool {
17
17
  private readonly perEpoch;
18
18
  private readonly idSets;
19
+ static new(): VerifiedTicketPool;
20
+ private constructor();
19
21
  /** Add pre-verified tickets to the pool, deduping by id. */
20
22
  add(epochIndex: Epoch, verifiedTickets: readonly VerifiedTicket[]): void;
21
23
  /** Returns the verified tickets for the given epoch, or an empty array if none. */
@@ -1 +1 @@
1
- {"version":3,"file":"verified-ticket-pool.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/ticket-pool/verified-ticket-pool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,yFAAyF;AACzF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,EAAE,EAAE,WAAW,CAAC;CACjB,CAAC;AAEF;;;;;;;GAOG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAC/D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IAEjE,4DAA4D;IAC5D,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE,SAAS,cAAc,EAAE,GAAG,IAAI;IAoBxE,mFAAmF;IACnF,WAAW,CAAC,UAAU,EAAE,KAAK,GAAG,SAAS,cAAc,EAAE;CAG1D"}
1
+ {"version":3,"file":"verified-ticket-pool.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/ticket-pool/verified-ticket-pool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,yFAAyF;AACzF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,EAAE,EAAE,WAAW,CAAC;CACjB,CAAC;AAEF;;;;;;;GAOG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAC/D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IAEjE,MAAM,CAAC,GAAG;IAIV,OAAO;IAEP,4DAA4D;IAC5D,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE,SAAS,cAAc,EAAE,GAAG,IAAI;IAoBxE,mFAAmF;IACnF,WAAW,CAAC,UAAU,EAAE,KAAK,GAAG,SAAS,cAAc,EAAE;CAG1D"}
@@ -10,6 +10,10 @@ import { HashSet } from "#@typeberry/collections/hash-set.js";
10
10
  export class VerifiedTicketPool {
11
11
  perEpoch = new Map();
12
12
  idSets = new Map();
13
+ static new() {
14
+ return new VerifiedTicketPool();
15
+ }
16
+ constructor() { }
13
17
  /** Add pre-verified tickets to the pool, deduping by id. */
14
18
  add(epochIndex, verifiedTickets) {
15
19
  if (this.perEpoch.size > 0 && !this.perEpoch.has(epochIndex)) {