@typeberry/lib 0.8.4 → 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 (217) hide show
  1. package/package.json +6 -4
  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 +96 -0
  67. package/packages/jam/database-fjall/hybrid-states.d.ts.map +1 -0
  68. package/packages/jam/database-fjall/hybrid-states.js +218 -0
  69. package/packages/jam/database-fjall/hybrid-states.test.d.ts +2 -0
  70. package/packages/jam/database-fjall/hybrid-states.test.d.ts.map +1 -0
  71. package/packages/jam/database-fjall/hybrid-states.test.js +113 -0
  72. package/packages/jam/database-fjall/index.d.ts +5 -0
  73. package/packages/jam/database-fjall/index.d.ts.map +1 -0
  74. package/packages/jam/database-fjall/index.js +4 -0
  75. package/packages/jam/database-fjall/root.d.ts +64 -0
  76. package/packages/jam/database-fjall/root.d.ts.map +1 -0
  77. package/packages/jam/database-fjall/root.js +105 -0
  78. package/packages/jam/database-fjall/states.d.ts +31 -0
  79. package/packages/jam/database-fjall/states.d.ts.map +1 -0
  80. package/packages/jam/database-fjall/states.js +99 -0
  81. package/packages/jam/database-fjall/states.test.d.ts +2 -0
  82. package/packages/jam/database-fjall/states.test.d.ts.map +1 -0
  83. package/packages/jam/database-fjall/states.test.js +150 -0
  84. package/packages/jam/database-lmdb/hybrid-states.d.ts +12 -0
  85. package/packages/jam/database-lmdb/hybrid-states.d.ts.map +1 -1
  86. package/packages/jam/database-lmdb/hybrid-states.js +45 -4
  87. package/packages/jam/database-lmdb/states.d.ts +1 -0
  88. package/packages/jam/database-lmdb/states.d.ts.map +1 -1
  89. package/packages/jam/database-lmdb/states.js +5 -0
  90. package/packages/jam/jamnp-s/tasks/ticket-distribution.d.ts +18 -10
  91. package/packages/jam/jamnp-s/tasks/ticket-distribution.d.ts.map +1 -1
  92. package/packages/jam/jamnp-s/tasks/ticket-distribution.js +44 -68
  93. package/packages/jam/jamnp-s/tasks/ticket-distribution.test.js +30 -8
  94. package/packages/jam/node/export.d.ts.map +1 -1
  95. package/packages/jam/node/export.js +18 -9
  96. package/packages/jam/node/main-fuzz.d.ts +4 -1
  97. package/packages/jam/node/main-fuzz.d.ts.map +1 -1
  98. package/packages/jam/node/main-fuzz.js +142 -55
  99. package/packages/jam/node/main-importer.d.ts +15 -3
  100. package/packages/jam/node/main-importer.d.ts.map +1 -1
  101. package/packages/jam/node/main-importer.js +30 -14
  102. package/packages/jam/node/main.d.ts.map +1 -1
  103. package/packages/jam/node/main.js +42 -15
  104. package/packages/jam/node/workers.d.ts +4 -4
  105. package/packages/jam/node/workers.d.ts.map +1 -1
  106. package/packages/jam/safrole/bandersnatch-vrf.d.ts +24 -4
  107. package/packages/jam/safrole/bandersnatch-vrf.d.ts.map +1 -1
  108. package/packages/jam/safrole/bandersnatch-vrf.js +63 -26
  109. package/packages/jam/safrole/bandersnatch-vrf.test.js +12 -9
  110. package/packages/jam/safrole/bandersnatch-wasm.d.ts +10 -0
  111. package/packages/jam/safrole/bandersnatch-wasm.d.ts.map +1 -1
  112. package/packages/jam/safrole/bandersnatch-wasm.js +12 -0
  113. package/packages/jam/safrole/safrole.js +5 -5
  114. package/packages/jam/safrole/safrole.test.js +13 -13
  115. package/packages/jam/ticket-pool/index.d.ts +4 -0
  116. package/packages/jam/ticket-pool/index.d.ts.map +1 -0
  117. package/packages/jam/ticket-pool/index.js +3 -0
  118. package/packages/jam/ticket-pool/pending-ticket-pool.d.ts +30 -0
  119. package/packages/jam/ticket-pool/pending-ticket-pool.d.ts.map +1 -0
  120. package/packages/jam/ticket-pool/pending-ticket-pool.js +56 -0
  121. package/packages/jam/ticket-pool/pending-ticket-pool.test.d.ts +2 -0
  122. package/packages/jam/ticket-pool/pending-ticket-pool.test.d.ts.map +1 -0
  123. package/packages/jam/ticket-pool/pending-ticket-pool.test.js +67 -0
  124. package/packages/jam/ticket-pool/ticket-validator.d.ts +47 -0
  125. package/packages/jam/ticket-pool/ticket-validator.d.ts.map +1 -0
  126. package/packages/jam/ticket-pool/ticket-validator.js +34 -0
  127. package/packages/jam/ticket-pool/ticket-validator.test.d.ts +2 -0
  128. package/packages/jam/ticket-pool/ticket-validator.test.d.ts.map +1 -0
  129. package/packages/jam/ticket-pool/ticket-validator.test.js +35 -0
  130. package/packages/jam/ticket-pool/verified-ticket-pool.d.ts +26 -0
  131. package/packages/jam/ticket-pool/verified-ticket-pool.d.ts.map +1 -0
  132. package/packages/jam/ticket-pool/verified-ticket-pool.js +41 -0
  133. package/packages/jam/ticket-pool/verified-ticket-pool.test.d.ts +2 -0
  134. package/packages/jam/ticket-pool/verified-ticket-pool.test.d.ts.map +1 -0
  135. package/packages/jam/ticket-pool/verified-ticket-pool.test.js +54 -0
  136. package/packages/workers/api/config.d.ts +2 -2
  137. package/packages/workers/api/config.d.ts.map +1 -1
  138. package/packages/workers/api/config.js +1 -1
  139. package/packages/workers/api/port.d.ts +5 -1
  140. package/packages/workers/api/port.d.ts.map +1 -1
  141. package/packages/workers/api/port.js +56 -13
  142. package/packages/workers/api/port.test.js +35 -0
  143. package/packages/workers/api-node/config.d.ts +65 -9
  144. package/packages/workers/api-node/config.d.ts.map +1 -1
  145. package/packages/workers/api-node/config.js +151 -26
  146. package/packages/workers/api-node/config.test.js +88 -2
  147. package/packages/workers/api-node/port.d.ts +3 -0
  148. package/packages/workers/api-node/port.d.ts.map +1 -1
  149. package/packages/workers/api-node/port.js +31 -2
  150. package/packages/workers/api-node/port.test.js +17 -0
  151. package/packages/workers/api-node/protocol.d.ts +3 -3
  152. package/packages/workers/api-node/protocol.d.ts.map +1 -1
  153. package/packages/workers/api-node/protocol.js +18 -12
  154. package/packages/workers/block-authorship/{generator.d.ts → block-generator.d.ts} +5 -5
  155. package/packages/workers/block-authorship/block-generator.d.ts.map +1 -0
  156. package/packages/workers/block-authorship/{generator.js → block-generator.js} +3 -3
  157. package/packages/workers/block-authorship/block-generator.test.d.ts +2 -0
  158. package/packages/workers/block-authorship/block-generator.test.d.ts.map +1 -0
  159. package/packages/workers/block-authorship/{generator.test.js → block-generator.test.js} +8 -8
  160. package/packages/workers/block-authorship/epoch-authoring-slots.d.ts +35 -0
  161. package/packages/workers/block-authorship/epoch-authoring-slots.d.ts.map +1 -0
  162. package/packages/workers/block-authorship/epoch-authoring-slots.js +86 -0
  163. package/packages/workers/block-authorship/epoch-tracker.d.ts +29 -0
  164. package/packages/workers/block-authorship/epoch-tracker.d.ts.map +1 -0
  165. package/packages/workers/block-authorship/epoch-tracker.js +80 -0
  166. package/packages/workers/block-authorship/index.d.ts.map +1 -1
  167. package/packages/workers/block-authorship/index.js +1 -1
  168. package/packages/workers/block-authorship/main.d.ts +3 -0
  169. package/packages/workers/block-authorship/main.d.ts.map +1 -1
  170. package/packages/workers/block-authorship/main.js +198 -316
  171. package/packages/workers/block-authorship/ticket-generator/bootstrap-main.d.ts +2 -0
  172. package/packages/workers/block-authorship/ticket-generator/bootstrap-main.d.ts.map +1 -0
  173. package/packages/workers/block-authorship/ticket-generator/bootstrap-main.js +23 -0
  174. package/packages/workers/block-authorship/ticket-generator/index.d.ts +16 -0
  175. package/packages/workers/block-authorship/ticket-generator/index.d.ts.map +1 -0
  176. package/packages/workers/block-authorship/ticket-generator/index.js +62 -0
  177. package/packages/workers/block-authorship/ticket-generator/protocol.d.ts +50 -0
  178. package/packages/workers/block-authorship/ticket-generator/protocol.d.ts.map +1 -0
  179. package/packages/workers/block-authorship/ticket-generator/protocol.js +54 -0
  180. package/packages/workers/block-authorship/{ticket-generator.d.ts → ticket-generator/ticket-generator.d.ts} +4 -0
  181. package/packages/workers/block-authorship/ticket-generator/ticket-generator.d.ts.map +1 -0
  182. package/packages/workers/block-authorship/{ticket-generator.js → ticket-generator/ticket-generator.js} +19 -9
  183. package/packages/workers/block-authorship/ticket-generator/ticket-generator.test.d.ts.map +1 -0
  184. package/packages/workers/block-authorship/{ticket-generator.test.js → ticket-generator/ticket-generator.test.js} +13 -9
  185. package/packages/workers/block-authorship/ticket-generator/worker-pool.d.ts +36 -0
  186. package/packages/workers/block-authorship/ticket-generator/worker-pool.d.ts.map +1 -0
  187. package/packages/workers/block-authorship/ticket-generator/worker-pool.js +111 -0
  188. package/packages/workers/block-authorship/ticket-validator.d.ts +31 -0
  189. package/packages/workers/block-authorship/ticket-validator.d.ts.map +1 -0
  190. package/packages/workers/block-authorship/ticket-validator.js +59 -0
  191. package/packages/workers/comms-authorship-network/protocol.d.ts +14 -4
  192. package/packages/workers/comms-authorship-network/protocol.d.ts.map +1 -1
  193. package/packages/workers/comms-authorship-network/protocol.js +12 -6
  194. package/packages/workers/comms-authorship-network/tickets-message.d.ts +0 -14
  195. package/packages/workers/comms-authorship-network/tickets-message.d.ts.map +1 -1
  196. package/packages/workers/comms-authorship-network/tickets-message.js +0 -17
  197. package/packages/workers/importer/finality.d.ts +2 -0
  198. package/packages/workers/importer/finality.d.ts.map +1 -1
  199. package/packages/workers/importer/finality.js +8 -1
  200. package/packages/workers/importer/importer.d.ts +2 -2
  201. package/packages/workers/importer/importer.d.ts.map +1 -1
  202. package/packages/workers/importer/importer.js +6 -5
  203. package/packages/workers/importer/main.d.ts +1 -1
  204. package/packages/workers/importer/main.d.ts.map +1 -1
  205. package/packages/workers/importer/main.js +1 -1
  206. package/packages/workers/importer/stats.d.ts +1 -3
  207. package/packages/workers/importer/stats.d.ts.map +1 -1
  208. package/packages/workers/importer/stats.js +12 -12
  209. package/packages/workers/jam-network/main.d.ts.map +1 -1
  210. package/packages/workers/jam-network/main.js +26 -5
  211. package/packages/workers/block-authorship/generator.d.ts.map +0 -1
  212. package/packages/workers/block-authorship/generator.test.d.ts +0 -2
  213. package/packages/workers/block-authorship/generator.test.d.ts.map +0 -1
  214. package/packages/workers/block-authorship/ticket-generator.d.ts.map +0 -1
  215. package/packages/workers/block-authorship/ticket-generator.test.d.ts.map +0 -1
  216. /package/packages/configs/{typeberry-dev.json → typeberry-dev-tiny.json} +0 -0
  217. /package/packages/workers/block-authorship/{ticket-generator.test.d.ts → ticket-generator/ticket-generator.test.d.ts} +0 -0
@@ -0,0 +1,34 @@
1
+ import { Bytes } from "#@typeberry/bytes";
2
+ import { HASH_SIZE } from "#@typeberry/hash";
3
+ import { Result } from "#@typeberry/utils";
4
+ /** Reasons a ticket may fail validation. */
5
+ export var ValidationError;
6
+ (function (ValidationError) {
7
+ /** Verifier rejected the signature / proof. */
8
+ ValidationError["InvalidProof"] = "invalid_proof";
9
+ /** Validator could not run (e.g. state unavailable, transient internal failure). */
10
+ ValidationError["ValidatorUnavailable"] = "validator_unavailable";
11
+ /** Ticket is for an epoch outside the validator's window of interest. */
12
+ ValidationError["WrongEpoch"] = "wrong_epoch";
13
+ })(ValidationError || (ValidationError = {}));
14
+ /**
15
+ * Accepts every ticket without inspection. Useful for unit tests where the validator
16
+ * isn't the subject under test. Must never be used in production.
17
+ */
18
+ export class AcceptTicketsValidator {
19
+ async validate(_epochIndex, ticket) {
20
+ return Result.ok(ticket.map((ticket) => ({
21
+ ticket,
22
+ id: Bytes.zero(HASH_SIZE).asOpaque(),
23
+ })));
24
+ }
25
+ }
26
+ /**
27
+ * Rejects every ticket. Used as the default for any task that needs an explicit, real
28
+ * validator wired in before it will accept anything from the network.
29
+ */
30
+ export class DenyTicketsValidator {
31
+ async validate(_epochIndex, _tickets) {
32
+ return Result.error(ValidationError.ValidatorUnavailable, () => "no ticket validator wired");
33
+ }
34
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ticket-validator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket-validator.test.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/ticket-pool/ticket-validator.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import assert from "node:assert";
2
+ import { describe, it } from "node:test";
3
+ import { tryAsEpoch } from "#@typeberry/block";
4
+ import { SignedTicket, tryAsTicketAttempt } from "#@typeberry/block/tickets.js";
5
+ import { Bytes } from "#@typeberry/bytes";
6
+ import { BANDERSNATCH_PROOF_BYTES } from "#@typeberry/crypto";
7
+ import { HASH_SIZE } from "#@typeberry/hash";
8
+ import { AcceptTicketsValidator, DenyTicketsValidator, ValidationError } from "./ticket-validator.js";
9
+ const E1 = tryAsEpoch(1);
10
+ function makeTicket() {
11
+ return SignedTicket.create({
12
+ attempt: tryAsTicketAttempt(0),
13
+ signature: Bytes.zero(BANDERSNATCH_PROOF_BYTES).asOpaque(),
14
+ });
15
+ }
16
+ describe("AcceptTicketsValidator", () => {
17
+ it("returns ok with zero id", async () => {
18
+ const v = new AcceptTicketsValidator();
19
+ const res = await v.validate(E1, [makeTicket()]);
20
+ assert.strictEqual(res.isOk, true);
21
+ if (res.isOk) {
22
+ assert.strictEqual(res.ok[0].id.toString(), Bytes.zero(HASH_SIZE).toString());
23
+ }
24
+ });
25
+ });
26
+ describe("DenyTicketsValidator", () => {
27
+ it("returns ValidatorUnavailable", async () => {
28
+ const v = new DenyTicketsValidator();
29
+ const res = await v.validate(E1, [makeTicket()]);
30
+ assert.strictEqual(res.isError, true);
31
+ if (res.isError) {
32
+ assert.strictEqual(res.error, ValidationError.ValidatorUnavailable);
33
+ }
34
+ });
35
+ });
@@ -0,0 +1,26 @@
1
+ import type { EntropyHash, Epoch } from "#@typeberry/block";
2
+ import type { SignedTicket } from "#@typeberry/block/tickets.js";
3
+ /** A ticket the validator already verified, paired with the entropy hash (ticket id). */
4
+ export type VerifiedTicket = {
5
+ ticket: SignedTicket;
6
+ id: EntropyHash;
7
+ };
8
+ /**
9
+ * In-memory pool of verified tickets for the current epoch, keyed by ticket id.
10
+ *
11
+ * Used on the authorship side. Tickets are stored per epoch and deduplicated by their
12
+ * computed entropy hash (so duplicates arriving via different peers / paths are coalesced
13
+ * cheaply). The pool only ever needs to hold tickets for one epoch at a time; switching
14
+ * to a new epoch clears everything older.
15
+ */
16
+ export declare class VerifiedTicketPool {
17
+ private readonly perEpoch;
18
+ private readonly idSets;
19
+ static new(): VerifiedTicketPool;
20
+ private constructor();
21
+ /** Add pre-verified tickets to the pool, deduping by id. */
22
+ add(epochIndex: Epoch, verifiedTickets: readonly VerifiedTicket[]): void;
23
+ /** Returns the verified tickets for the given epoch, or an empty array if none. */
24
+ getForEpoch(epochIndex: Epoch): readonly VerifiedTicket[];
25
+ }
26
+ //# sourceMappingURL=verified-ticket-pool.d.ts.map
@@ -0,0 +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,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"}
@@ -0,0 +1,41 @@
1
+ import { HashSet } from "#@typeberry/collections/hash-set.js";
2
+ /**
3
+ * In-memory pool of verified tickets for the current epoch, keyed by ticket id.
4
+ *
5
+ * Used on the authorship side. Tickets are stored per epoch and deduplicated by their
6
+ * computed entropy hash (so duplicates arriving via different peers / paths are coalesced
7
+ * cheaply). The pool only ever needs to hold tickets for one epoch at a time; switching
8
+ * to a new epoch clears everything older.
9
+ */
10
+ export class VerifiedTicketPool {
11
+ perEpoch = new Map();
12
+ idSets = new Map();
13
+ static new() {
14
+ return new VerifiedTicketPool();
15
+ }
16
+ constructor() { }
17
+ /** Add pre-verified tickets to the pool, deduping by id. */
18
+ add(epochIndex, verifiedTickets) {
19
+ if (this.perEpoch.size > 0 && !this.perEpoch.has(epochIndex)) {
20
+ this.perEpoch.clear();
21
+ this.idSets.clear();
22
+ }
23
+ const existing = this.perEpoch.get(epochIndex) ?? [];
24
+ let idSet = this.idSets.get(epochIndex) ?? null;
25
+ if (idSet === null) {
26
+ idSet = HashSet.new();
27
+ this.idSets.set(epochIndex, idSet);
28
+ }
29
+ for (const entry of verifiedTickets) {
30
+ if (!idSet.has(entry.id)) {
31
+ existing.push(entry);
32
+ idSet.insert(entry.id);
33
+ }
34
+ }
35
+ this.perEpoch.set(epochIndex, existing);
36
+ }
37
+ /** Returns the verified tickets for the given epoch, or an empty array if none. */
38
+ getForEpoch(epochIndex) {
39
+ return this.perEpoch.get(epochIndex) ?? [];
40
+ }
41
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=verified-ticket-pool.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verified-ticket-pool.test.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/ticket-pool/verified-ticket-pool.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,54 @@
1
+ import assert from "node:assert";
2
+ import { describe, it } from "node:test";
3
+ import { tryAsEpoch } from "#@typeberry/block";
4
+ import { SignedTicket, tryAsTicketAttempt } from "#@typeberry/block/tickets.js";
5
+ import { Bytes } from "#@typeberry/bytes";
6
+ import { BANDERSNATCH_PROOF_BYTES } from "#@typeberry/crypto";
7
+ import { HASH_SIZE } from "#@typeberry/hash";
8
+ import { VerifiedTicketPool } from "./verified-ticket-pool.js";
9
+ const E1 = tryAsEpoch(1);
10
+ const E2 = tryAsEpoch(2);
11
+ function makeTicket(seed) {
12
+ const sig = Bytes.zero(BANDERSNATCH_PROOF_BYTES);
13
+ sig.raw[0] = seed;
14
+ return SignedTicket.create({
15
+ attempt: tryAsTicketAttempt(0),
16
+ signature: sig.asOpaque(),
17
+ });
18
+ }
19
+ function makeId(byte) {
20
+ return Bytes.fill(HASH_SIZE, byte).asOpaque();
21
+ }
22
+ describe("VerifiedTicketPool", () => {
23
+ it("starts empty", () => {
24
+ const pool = VerifiedTicketPool.new();
25
+ assert.deepStrictEqual(pool.getForEpoch(E1), []);
26
+ });
27
+ it("adds and retrieves tickets per epoch", () => {
28
+ const pool = VerifiedTicketPool.new();
29
+ pool.add(E1, [{ ticket: makeTicket(1), id: makeId(0xaa) }]);
30
+ assert.strictEqual(pool.getForEpoch(E1).length, 1);
31
+ assert.deepStrictEqual(pool.getForEpoch(E2), []);
32
+ });
33
+ it("dedups by id", () => {
34
+ const pool = VerifiedTicketPool.new();
35
+ const id = makeId(0x01);
36
+ pool.add(E1, [{ ticket: makeTicket(1), id }]);
37
+ pool.add(E1, [{ ticket: makeTicket(2), id }]);
38
+ assert.strictEqual(pool.getForEpoch(E1).length, 1);
39
+ assert.strictEqual(pool.getForEpoch(E1)[0].ticket.signature.raw[0], 1);
40
+ });
41
+ it("clears previous epochs when a new epoch is added", () => {
42
+ const pool = VerifiedTicketPool.new();
43
+ pool.add(E1, [{ ticket: makeTicket(1), id: makeId(1) }]);
44
+ pool.add(E2, [{ ticket: makeTicket(2), id: makeId(2) }]);
45
+ assert.deepStrictEqual(pool.getForEpoch(E1), []);
46
+ assert.strictEqual(pool.getForEpoch(E2).length, 1);
47
+ });
48
+ it("appends across multiple add() calls for the same epoch", () => {
49
+ const pool = VerifiedTicketPool.new();
50
+ pool.add(E1, [{ ticket: makeTicket(1), id: makeId(1) }]);
51
+ pool.add(E1, [{ ticket: makeTicket(2), id: makeId(2) }]);
52
+ assert.strictEqual(pool.getForEpoch(E1).length, 2);
53
+ });
54
+ });
@@ -11,7 +11,7 @@ export interface WorkerConfig<TParams = void, TBlocks = BlocksDb, TStates = Stat
11
11
  /** Open database. */
12
12
  openDatabase(options?: {
13
13
  readonly: boolean;
14
- }): RootDb<TBlocks, TStates>;
14
+ }): Promise<RootDb<TBlocks, TStates>>;
15
15
  }
16
16
  /**
17
17
  * Worker config with in-thread database.
@@ -32,6 +32,6 @@ export declare class DirectWorkerConfig<TParams = void, TBlocks = BlocksDb, TSta
32
32
  private constructor();
33
33
  openDatabase(_options?: {
34
34
  readonly: boolean;
35
- }): RootDb<TBlocks, TStates>;
35
+ }): Promise<RootDb<TBlocks, TStates>>;
36
36
  }
37
37
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEtE,kCAAkC;AAClC,MAAM,WAAW,YAAY,CAAC,OAAO,GAAG,IAAI,EAAE,OAAO,GAAG,QAAQ,EAAE,OAAO,GAAG,QAAQ;IAClF,iBAAiB;IACjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kBAAkB;IAClB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,yBAAyB;IACzB,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAE/B,qBAAqB;IACrB,YAAY,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;CACzE;AAED;;GAEG;AACH,qBAAa,kBAAkB,CAAC,OAAO,GAAG,IAAI,EAAE,OAAO,GAAG,QAAQ,EAAE,OAAO,GAAG,QAAQ,CACpF,YAAW,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;aAmBhC,QAAQ,EAAE,MAAM;aAChB,SAAS,EAAE,SAAS;aACpB,YAAY,EAAE,OAAO;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IArB3B,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAClB,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,YAAY,EAAE,MAAM,GACrB,EAAE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,SAAS,CAAC;QACrB,QAAQ,EAAE,CAAC,CAAC;QACZ,QAAQ,EAAE,CAAC,CAAC;QACZ,YAAY,EAAE,CAAC,CAAC;KACjB,GAAG,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAI/B,OAAO;IAQP,YAAY,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC;CAOzE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEtE,kCAAkC;AAClC,MAAM,WAAW,YAAY,CAAC,OAAO,GAAG,IAAI,EAAE,OAAO,GAAG,QAAQ,EAAE,OAAO,GAAG,QAAQ;IAClF,iBAAiB;IACjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kBAAkB;IAClB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,yBAAyB;IACzB,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAE/B,qBAAqB;IACrB,YAAY,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;CAClF;AAED;;GAEG;AACH,qBAAa,kBAAkB,CAAC,OAAO,GAAG,IAAI,EAAE,OAAO,GAAG,QAAQ,EAAE,OAAO,GAAG,QAAQ,CACpF,YAAW,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;aAmBhC,QAAQ,EAAE,MAAM;aAChB,SAAS,EAAE,SAAS;aACpB,YAAY,EAAE,OAAO;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IArB3B,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAClB,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,YAAY,EAAE,MAAM,GACrB,EAAE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,SAAS,CAAC;QACrB,QAAQ,EAAE,CAAC,CAAC;QACZ,QAAQ,EAAE,CAAC,CAAC;QACZ,YAAY,EAAE,CAAC,CAAC;KACjB,GAAG,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAI/B,OAAO;IAQD,YAAY,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;CAOxF"}
@@ -17,7 +17,7 @@ export class DirectWorkerConfig {
17
17
  this.blocksDb = blocksDb;
18
18
  this.statesDb = statesDb;
19
19
  }
20
- openDatabase(_options) {
20
+ async openDatabase(_options) {
21
21
  return {
22
22
  getBlocksDb: () => this.blocksDb,
23
23
  getStatesDb: () => this.statesDb,
@@ -44,7 +44,8 @@ export interface Port {
44
44
  * so there is no need for any serialization - we simply pass the data.
45
45
  */
46
46
  export declare class DirectPort implements Port {
47
- private readonly events;
47
+ private readonly inbound;
48
+ private readonly outbound;
48
49
  readonly threadId = 0;
49
50
  /** Create a pair of symmetrical inter-connected ports. */
50
51
  static pair(): [DirectPort, DirectPort];
@@ -54,5 +55,8 @@ export declare class DirectPort implements Port {
54
55
  once<T>(event: string, _codec: Codec<T>, callback: (msg: Envelope<T>) => void): () => void;
55
56
  postMessage<T>(event: string, _codec: Codec<T>, msg: Envelope<T>): void;
56
57
  close(): void;
58
+ private queuePending;
59
+ private flushPending;
60
+ private closeState;
57
61
  }
58
62
  //# sourceMappingURL=port.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api/port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAG9C;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,CAAC;CACT,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,IAAI;IACnB,0BAA0B;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,0FAA0F;IAC1F,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAE5C;;;;OAIG;IACH,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAExF;;;;OAIG;IACH,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAE1F,2EAA2E;IAC3E,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAEvE,yCAAyC;IACzC,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,IAAI;IASjB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAR3C,QAAQ,CAAC,QAAQ,KAAK;IAEtB,0DAA0D;IAC1D,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC;IAKvC,OAAO;IAEP,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAI3C,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;IAYxF,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;IAY1F,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAIvE,KAAK;CAIN"}
1
+ {"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api/port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAG9C;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,CAAC;CACT,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,IAAI;IACnB,0BAA0B;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,0FAA0F;IAC1F,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAE5C;;;;OAIG;IACH,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAExF;;;;OAIG;IACH,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAE1F,2EAA2E;IAC3E,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAEvE,yCAAyC;IACzC,KAAK,IAAI,IAAI,CAAC;CACf;AAOD;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,IAAI;IAWnC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAX3B,QAAQ,CAAC,QAAQ,KAAK;IAEtB,0DAA0D;IAC1D,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC;IAMvC,OAAO;IAKP,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAI3C,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;IAaxF,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;IAuB1F,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAQvE,KAAK;IAKL,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,UAAU;CAKnB"}
@@ -6,27 +6,31 @@ import { EventEmitter } from "eventemitter3";
6
6
  * so there is no need for any serialization - we simply pass the data.
7
7
  */
8
8
  export class DirectPort {
9
- events;
9
+ inbound;
10
+ outbound;
10
11
  threadId = 0;
11
12
  /** Create a pair of symmetrical inter-connected ports. */
12
13
  static pair() {
13
- const events = new EventEmitter();
14
- return [new DirectPort(events), new DirectPort(events)];
14
+ const left = createPortState();
15
+ const right = createPortState();
16
+ return [new DirectPort(left, right), new DirectPort(right, left)];
15
17
  }
16
- constructor(events) {
17
- this.events = events;
18
+ constructor(inbound, outbound) {
19
+ this.inbound = inbound;
20
+ this.outbound = outbound;
18
21
  }
19
22
  onClose(callback) {
20
- this.events.on("error", callback);
23
+ this.inbound.events.on("error", callback);
21
24
  }
22
25
  on(event, _codec, callback) {
23
26
  const trigger = (args) => {
24
27
  // we simply cast the args, since there is no encoding involved.
25
28
  callback(args);
26
29
  };
27
- this.events.on(event, trigger);
30
+ this.inbound.events.on(event, trigger);
31
+ this.flushPending(event, trigger);
28
32
  return () => {
29
- this.events.off(event, trigger);
33
+ this.inbound.events.off(event, trigger);
30
34
  };
31
35
  }
32
36
  once(event, _codec, callback) {
@@ -34,16 +38,55 @@ export class DirectPort {
34
38
  // we simply cast the args, since there is no encoding involved.
35
39
  callback(args);
36
40
  };
37
- this.events.once(event, trigger);
41
+ const pending = this.inbound.pendingMessages.get(event);
42
+ const pendingMessage = pending?.shift();
43
+ if (pending?.length === 0) {
44
+ this.inbound.pendingMessages.delete(event);
45
+ }
46
+ if (pendingMessage !== undefined) {
47
+ trigger(pendingMessage);
48
+ return () => { };
49
+ }
50
+ this.inbound.events.once(event, trigger);
38
51
  return () => {
39
- this.events.off(event, trigger);
52
+ this.inbound.events.off(event, trigger);
40
53
  };
41
54
  }
42
55
  postMessage(event, _codec, msg) {
43
- this.events.emit(event, msg);
56
+ if (this.outbound.events.listenerCount(event) === 0) {
57
+ this.queuePending(event, msg);
58
+ return;
59
+ }
60
+ this.outbound.events.emit(event, msg);
44
61
  }
45
62
  close() {
46
- this.events.emit("error", new Error("closing channel"));
47
- this.events.removeAllListeners();
63
+ this.closeState(this.inbound);
64
+ this.closeState(this.outbound);
48
65
  }
66
+ queuePending(event, msg) {
67
+ const pending = this.outbound.pendingMessages.get(event) ?? [];
68
+ pending.push(msg);
69
+ this.outbound.pendingMessages.set(event, pending);
70
+ }
71
+ flushPending(event, trigger) {
72
+ const pending = this.inbound.pendingMessages.get(event);
73
+ if (pending === undefined) {
74
+ return;
75
+ }
76
+ this.inbound.pendingMessages.delete(event);
77
+ for (const msg of pending) {
78
+ trigger(msg);
79
+ }
80
+ }
81
+ closeState(state) {
82
+ state.events.emit("error", new Error("closing channel"));
83
+ state.events.removeAllListeners();
84
+ state.pendingMessages.clear();
85
+ }
86
+ }
87
+ function createPortState() {
88
+ return {
89
+ events: new EventEmitter(),
90
+ pendingMessages: new Map(),
91
+ };
49
92
  }
@@ -25,4 +25,39 @@ describe("DirectPort", () => {
25
25
  data: tryAsU32(10),
26
26
  });
27
27
  });
28
+ it("should deliver messages sent before the listener is attached", () => {
29
+ const [txPort, rxPort] = DirectPort.pair();
30
+ txPort.postMessage("hello", codec.u32, {
31
+ responseId: "10",
32
+ data: tryAsU32(10),
33
+ });
34
+ let receivedMessage = null;
35
+ rxPort.on("hello", codec.u32, (msg) => {
36
+ receivedMessage = msg;
37
+ });
38
+ assert.deepStrictEqual(receivedMessage, {
39
+ responseId: "10",
40
+ data: tryAsU32(10),
41
+ });
42
+ });
43
+ it("should not let the sender consume its own pending message", () => {
44
+ const [txPort, rxPort] = DirectPort.pair();
45
+ txPort.postMessage("hello", codec.u32, {
46
+ responseId: "10",
47
+ data: tryAsU32(10),
48
+ });
49
+ let senderMessage = null;
50
+ txPort.on("hello", codec.u32, (msg) => {
51
+ senderMessage = msg;
52
+ });
53
+ assert.deepStrictEqual(senderMessage, null);
54
+ let receiverMessage = null;
55
+ rxPort.on("hello", codec.u32, (msg) => {
56
+ receiverMessage = msg;
57
+ });
58
+ assert.deepStrictEqual(receiverMessage, {
59
+ responseId: "10",
60
+ data: tryAsU32(10),
61
+ });
62
+ });
28
63
  });
@@ -2,10 +2,20 @@ import type { MessagePort } from "node:worker_threads";
2
2
  import { type Decode, type Encode } from "#@typeberry/codec";
3
3
  import { ChainSpec } from "#@typeberry/config";
4
4
  import { type BlocksDb, type RootDb, type SerializedStatesDb } from "#@typeberry/database";
5
+ import { FjallValuesSession } from "#@typeberry/database-fjall";
5
6
  import { Blake2b } from "#@typeberry/hash";
6
7
  import type { WorkerConfig } from "#@typeberry/workers-api";
7
8
  import { ThreadPort, type TransferablePort } from "./port.js";
8
- /** A worker config that's usable in node.js and uses LMDB database backend. */
9
+ export { FjallValuesSession };
10
+ /** Persistent regular-node backend. */
11
+ export type PersistentBackend = "lmdb" | "fjall";
12
+ /** Transferable worker config for persistent regular-node workers. */
13
+ export type PersistentWorkerConfig<T> = LmdbWorkerConfig<T> | FjallWorkerConfig<T>;
14
+ /**
15
+ * Worker config for node.js, backed by the LMDB database.
16
+ *
17
+ * @deprecated lmdb is retained as an explicit fallback. Use `FjallWorkerConfig` for regular nodes.
18
+ */
9
19
  export declare class LmdbWorkerConfig<T = void> implements WorkerConfig<T, BlocksDb, SerializedStatesDb> {
10
20
  readonly nodeName: string;
11
21
  readonly chainSpec: ChainSpec;
@@ -28,18 +38,51 @@ export declare class LmdbWorkerConfig<T = void> implements WorkerConfig<T, Block
28
38
  private constructor();
29
39
  openDatabase(options?: {
30
40
  readonly: boolean;
31
- }): RootDb<BlocksDb, SerializedStatesDb>;
41
+ }): Promise<RootDb<BlocksDb, SerializedStatesDb>>;
42
+ /** Convert this config into a thread-transferable object. */
43
+ intoTransferable(paramsCodec: Encode<T>): TransferableConfig;
44
+ }
45
+ /** Worker config for node.js, backed by a shared fjall engine. */
46
+ export declare class FjallWorkerConfig<T = void> implements WorkerConfig<T, BlocksDb, SerializedStatesDb> {
47
+ readonly nodeName: string;
48
+ readonly chainSpec: ChainSpec;
49
+ readonly workerParams: T;
50
+ readonly dbPath: string;
51
+ readonly blake2b: Blake2b;
52
+ readonly ports: Map<string, ThreadPort>;
53
+ readonly ephemeral: boolean;
54
+ readonly cacheSizeBytes: number | undefined;
55
+ static new<T>({ nodeName, chainSpec, workerParams, dbPath, blake2b, ports, ephemeral, cacheSizeBytes, }: {
56
+ nodeName: string;
57
+ chainSpec: ChainSpec;
58
+ workerParams: T;
59
+ dbPath: string;
60
+ blake2b: Blake2b;
61
+ ports?: Map<string, ThreadPort>;
62
+ ephemeral?: boolean;
63
+ cacheSizeBytes?: number;
64
+ }): FjallWorkerConfig<T>;
65
+ /** Restore node config from a transferable config object. */
66
+ static fromTransferable<T>(decodeParams: Decode<T>, config: TransferableConfig): Promise<FjallWorkerConfig<T>>;
67
+ private constructor();
68
+ openDatabase(options?: {
69
+ readonly: boolean;
70
+ }): Promise<RootDb<BlocksDb, SerializedStatesDb>>;
32
71
  /** Convert this config into a thread-transferable object. */
33
72
  intoTransferable(paramsCodec: Encode<T>): TransferableConfig;
34
73
  }
35
74
  /** Config that's safe to transfer between worker threads. */
36
75
  export type TransferableConfig = {
76
+ databaseBackend: PersistentBackend;
37
77
  nodeName: string;
38
78
  chainSpec: ChainSpec;
39
79
  workerParams: Uint8Array;
40
80
  dbPath: string;
41
81
  workerPorts: [string, TransferablePort][];
82
+ cacheSizeBytes?: number;
42
83
  };
84
+ /** Restore a persistent worker config from its transferable form. */
85
+ export declare function persistentConfigFromTransferable<T>(decodeParams: Decode<T>, config: TransferableConfig): Promise<PersistentWorkerConfig<T>>;
43
86
  /**
44
87
  * Collect the transferable objects (communication ports) embedded in a config.
45
88
  *
@@ -69,15 +112,20 @@ export declare class InMemWorkerConfig<T = undefined> implements WorkerConfig<T,
69
112
  private constructor();
70
113
  openDatabase(_options?: {
71
114
  readonly: boolean;
72
- }): RootDb<BlocksDb, SerializedStatesDb>;
115
+ }): Promise<RootDb<BlocksDb, SerializedStatesDb>>;
73
116
  }
117
+ /** Persistent values store backing the hybrid config. */
118
+ export type HybridBackend = "lmdb" | "fjall";
74
119
  /**
75
120
  * Hybrid worker config for the fuzz target: in-memory blocks and leaf sets,
76
- * but large values persisted to LMDB.
121
+ * but large values persisted to disk. The `backend` picks where the values go
122
+ * (lmdb or fjall).
123
+ *
124
+ * fjall opens its keyspace asynchronously, that is why `new` here is async.
77
125
  *
78
126
  * Like `InMemWorkerConfig`, the blocks and leaf sets are shared across the
79
127
  * open/close/reopen dance that genesis init performs, so `openDatabase`
80
- * returns the same instances and a no-op close. The LMDB root is opened once
128
+ * returns the same instances and a no-op close. The values store is opened once
81
129
  * here and closed by `HybridSerializedStates.close()` at importer teardown.
82
130
  *
83
131
  * In-process only: it holds shared mutable state (the in-memory leaf
@@ -92,7 +140,8 @@ export declare class HybridWorkerConfig<T = undefined> implements WorkerConfig<T
92
140
  readonly dbPath: string;
93
141
  readonly ephemeral: boolean;
94
142
  readonly compression: boolean;
95
- static new<T>({ nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral, compression, }: {
143
+ private readonly states;
144
+ static new<T>({ nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral, compression, backend, sharedFjallSession, }: {
96
145
  nodeName: string;
97
146
  chainSpec: ChainSpec;
98
147
  workerParams: T;
@@ -100,12 +149,19 @@ export declare class HybridWorkerConfig<T = undefined> implements WorkerConfig<T
100
149
  dbPath: string;
101
150
  ephemeral?: boolean;
102
151
  compression?: boolean;
103
- }): HybridWorkerConfig<T>;
152
+ backend?: HybridBackend;
153
+ /**
154
+ * Reuse an already-open fjall values session instead of opening a fresh
155
+ * keyspace. The fuzz target opens one per run and passes it on every reset,
156
+ * so only the in-memory blocks/leaf sets are rebuilt per vector. Ignored
157
+ * unless `backend === "fjall"`.
158
+ */
159
+ sharedFjallSession?: FjallValuesSession;
160
+ }): Promise<HybridWorkerConfig<T>>;
104
161
  private readonly blocks;
105
- private readonly states;
106
162
  private constructor();
107
163
  openDatabase(_options?: {
108
164
  readonly: boolean;
109
- }): RootDb<BlocksDb, SerializedStatesDb>;
165
+ }): Promise<RootDb<BlocksDb, SerializedStatesDb>>;
110
166
  }
111
167
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api-node/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api-node/config.ts"],"names":[],"mappings":"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"}