@typeberry/lib 0.8.4 → 0.9.0-3f2c45b

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 (129) 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/utils/debug.d.ts +4 -2
  10. package/packages/core/utils/debug.d.ts.map +1 -1
  11. package/packages/core/utils/debug.js +18 -13
  12. package/packages/core/utils/debug.test.js +12 -6
  13. package/packages/jam/config-node/node-config.d.ts +2 -1
  14. package/packages/jam/config-node/node-config.d.ts.map +1 -1
  15. package/packages/jam/config-node/node-config.js +8 -3
  16. package/packages/jam/config-node/node-config.test.js +3 -3
  17. package/packages/jam/database-fjall/hybrid-states.d.ts +82 -0
  18. package/packages/jam/database-fjall/hybrid-states.d.ts.map +1 -0
  19. package/packages/jam/database-fjall/hybrid-states.js +169 -0
  20. package/packages/jam/database-fjall/hybrid-states.test.d.ts +2 -0
  21. package/packages/jam/database-fjall/hybrid-states.test.d.ts.map +1 -0
  22. package/packages/jam/database-fjall/hybrid-states.test.js +113 -0
  23. package/packages/jam/database-fjall/index.d.ts +3 -0
  24. package/packages/jam/database-fjall/index.d.ts.map +1 -0
  25. package/packages/jam/database-fjall/index.js +2 -0
  26. package/packages/jam/database-fjall/root.d.ts +58 -0
  27. package/packages/jam/database-fjall/root.d.ts.map +1 -0
  28. package/packages/jam/database-fjall/root.js +89 -0
  29. package/packages/jam/jamnp-s/tasks/ticket-distribution.d.ts +18 -10
  30. package/packages/jam/jamnp-s/tasks/ticket-distribution.d.ts.map +1 -1
  31. package/packages/jam/jamnp-s/tasks/ticket-distribution.js +44 -68
  32. package/packages/jam/jamnp-s/tasks/ticket-distribution.test.js +30 -8
  33. package/packages/jam/node/main-fuzz.d.ts.map +1 -1
  34. package/packages/jam/node/main-fuzz.js +69 -11
  35. package/packages/jam/node/main-importer.d.ts +13 -3
  36. package/packages/jam/node/main-importer.d.ts.map +1 -1
  37. package/packages/jam/node/main-importer.js +5 -3
  38. package/packages/jam/safrole/bandersnatch-vrf.d.ts +24 -4
  39. package/packages/jam/safrole/bandersnatch-vrf.d.ts.map +1 -1
  40. package/packages/jam/safrole/bandersnatch-vrf.js +63 -26
  41. package/packages/jam/safrole/bandersnatch-vrf.test.js +12 -9
  42. package/packages/jam/safrole/bandersnatch-wasm.d.ts +10 -0
  43. package/packages/jam/safrole/bandersnatch-wasm.d.ts.map +1 -1
  44. package/packages/jam/safrole/bandersnatch-wasm.js +12 -0
  45. package/packages/jam/safrole/safrole.js +5 -5
  46. package/packages/jam/safrole/safrole.test.js +13 -13
  47. package/packages/jam/ticket-pool/index.d.ts +4 -0
  48. package/packages/jam/ticket-pool/index.d.ts.map +1 -0
  49. package/packages/jam/ticket-pool/index.js +3 -0
  50. package/packages/jam/ticket-pool/pending-ticket-pool.d.ts +30 -0
  51. package/packages/jam/ticket-pool/pending-ticket-pool.d.ts.map +1 -0
  52. package/packages/jam/ticket-pool/pending-ticket-pool.js +56 -0
  53. package/packages/jam/ticket-pool/pending-ticket-pool.test.d.ts +2 -0
  54. package/packages/jam/ticket-pool/pending-ticket-pool.test.d.ts.map +1 -0
  55. package/packages/jam/ticket-pool/pending-ticket-pool.test.js +67 -0
  56. package/packages/jam/ticket-pool/ticket-validator.d.ts +47 -0
  57. package/packages/jam/ticket-pool/ticket-validator.d.ts.map +1 -0
  58. package/packages/jam/ticket-pool/ticket-validator.js +34 -0
  59. package/packages/jam/ticket-pool/ticket-validator.test.d.ts +2 -0
  60. package/packages/jam/ticket-pool/ticket-validator.test.d.ts.map +1 -0
  61. package/packages/jam/ticket-pool/ticket-validator.test.js +35 -0
  62. package/packages/jam/ticket-pool/verified-ticket-pool.d.ts +26 -0
  63. package/packages/jam/ticket-pool/verified-ticket-pool.d.ts.map +1 -0
  64. package/packages/jam/ticket-pool/verified-ticket-pool.js +41 -0
  65. package/packages/jam/ticket-pool/verified-ticket-pool.test.d.ts +2 -0
  66. package/packages/jam/ticket-pool/verified-ticket-pool.test.d.ts.map +1 -0
  67. package/packages/jam/ticket-pool/verified-ticket-pool.test.js +54 -0
  68. package/packages/workers/api-node/config.d.ts +21 -6
  69. package/packages/workers/api-node/config.d.ts.map +1 -1
  70. package/packages/workers/api-node/config.js +26 -19
  71. package/packages/workers/api-node/config.test.js +38 -1
  72. package/packages/workers/block-authorship/{generator.d.ts → block-generator.d.ts} +5 -5
  73. package/packages/workers/block-authorship/block-generator.d.ts.map +1 -0
  74. package/packages/workers/block-authorship/{generator.js → block-generator.js} +3 -3
  75. package/packages/workers/block-authorship/block-generator.test.d.ts +2 -0
  76. package/packages/workers/block-authorship/block-generator.test.d.ts.map +1 -0
  77. package/packages/workers/block-authorship/{generator.test.js → block-generator.test.js} +8 -8
  78. package/packages/workers/block-authorship/epoch-authoring-slots.d.ts +35 -0
  79. package/packages/workers/block-authorship/epoch-authoring-slots.d.ts.map +1 -0
  80. package/packages/workers/block-authorship/epoch-authoring-slots.js +86 -0
  81. package/packages/workers/block-authorship/epoch-tracker.d.ts +29 -0
  82. package/packages/workers/block-authorship/epoch-tracker.d.ts.map +1 -0
  83. package/packages/workers/block-authorship/epoch-tracker.js +80 -0
  84. package/packages/workers/block-authorship/index.d.ts.map +1 -1
  85. package/packages/workers/block-authorship/index.js +1 -1
  86. package/packages/workers/block-authorship/main.d.ts +3 -0
  87. package/packages/workers/block-authorship/main.d.ts.map +1 -1
  88. package/packages/workers/block-authorship/main.js +197 -315
  89. package/packages/workers/block-authorship/ticket-generator/bootstrap-main.d.ts +2 -0
  90. package/packages/workers/block-authorship/ticket-generator/bootstrap-main.d.ts.map +1 -0
  91. package/packages/workers/block-authorship/ticket-generator/bootstrap-main.js +23 -0
  92. package/packages/workers/block-authorship/ticket-generator/index.d.ts +16 -0
  93. package/packages/workers/block-authorship/ticket-generator/index.d.ts.map +1 -0
  94. package/packages/workers/block-authorship/ticket-generator/index.js +62 -0
  95. package/packages/workers/block-authorship/ticket-generator/protocol.d.ts +50 -0
  96. package/packages/workers/block-authorship/ticket-generator/protocol.d.ts.map +1 -0
  97. package/packages/workers/block-authorship/ticket-generator/protocol.js +54 -0
  98. package/packages/workers/block-authorship/{ticket-generator.d.ts → ticket-generator/ticket-generator.d.ts} +4 -0
  99. package/packages/workers/block-authorship/ticket-generator/ticket-generator.d.ts.map +1 -0
  100. package/packages/workers/block-authorship/{ticket-generator.js → ticket-generator/ticket-generator.js} +19 -9
  101. package/packages/workers/block-authorship/ticket-generator/ticket-generator.test.d.ts.map +1 -0
  102. package/packages/workers/block-authorship/{ticket-generator.test.js → ticket-generator/ticket-generator.test.js} +13 -9
  103. package/packages/workers/block-authorship/ticket-generator/worker-pool.d.ts +36 -0
  104. package/packages/workers/block-authorship/ticket-generator/worker-pool.d.ts.map +1 -0
  105. package/packages/workers/block-authorship/ticket-generator/worker-pool.js +111 -0
  106. package/packages/workers/block-authorship/ticket-validator.d.ts +31 -0
  107. package/packages/workers/block-authorship/ticket-validator.d.ts.map +1 -0
  108. package/packages/workers/block-authorship/ticket-validator.js +59 -0
  109. package/packages/workers/comms-authorship-network/protocol.d.ts +14 -4
  110. package/packages/workers/comms-authorship-network/protocol.d.ts.map +1 -1
  111. package/packages/workers/comms-authorship-network/protocol.js +12 -6
  112. package/packages/workers/comms-authorship-network/tickets-message.d.ts +0 -14
  113. package/packages/workers/comms-authorship-network/tickets-message.d.ts.map +1 -1
  114. package/packages/workers/comms-authorship-network/tickets-message.js +0 -17
  115. package/packages/workers/importer/importer.d.ts +2 -2
  116. package/packages/workers/importer/importer.d.ts.map +1 -1
  117. package/packages/workers/importer/importer.js +5 -5
  118. package/packages/workers/importer/stats.d.ts +1 -3
  119. package/packages/workers/importer/stats.d.ts.map +1 -1
  120. package/packages/workers/importer/stats.js +12 -12
  121. package/packages/workers/jam-network/main.d.ts.map +1 -1
  122. package/packages/workers/jam-network/main.js +25 -4
  123. package/packages/workers/block-authorship/generator.d.ts.map +0 -1
  124. package/packages/workers/block-authorship/generator.test.d.ts +0 -2
  125. package/packages/workers/block-authorship/generator.test.d.ts.map +0 -1
  126. package/packages/workers/block-authorship/ticket-generator.d.ts.map +0 -1
  127. package/packages/workers/block-authorship/ticket-generator.test.d.ts.map +0 -1
  128. /package/packages/configs/{typeberry-dev.json → typeberry-dev-tiny.json} +0 -0
  129. /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
+ });
@@ -2,10 +2,12 @@ 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
+ /** Worker config for node.js, backed by the LMDB database. */
9
11
  export declare class LmdbWorkerConfig<T = void> implements WorkerConfig<T, BlocksDb, SerializedStatesDb> {
10
12
  readonly nodeName: string;
11
13
  readonly chainSpec: ChainSpec;
@@ -71,13 +73,18 @@ export declare class InMemWorkerConfig<T = undefined> implements WorkerConfig<T,
71
73
  readonly: boolean;
72
74
  }): RootDb<BlocksDb, SerializedStatesDb>;
73
75
  }
76
+ /** Persistent values store backing the hybrid config. */
77
+ export type HybridBackend = "lmdb" | "fjall";
74
78
  /**
75
79
  * Hybrid worker config for the fuzz target: in-memory blocks and leaf sets,
76
- * but large values persisted to LMDB.
80
+ * but large values persisted to disk. The `backend` picks where the values go
81
+ * (lmdb or fjall).
82
+ *
83
+ * fjall opens its keyspace asynchronously, that is why `new` here is async.
77
84
  *
78
85
  * Like `InMemWorkerConfig`, the blocks and leaf sets are shared across the
79
86
  * 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
87
+ * returns the same instances and a no-op close. The values store is opened once
81
88
  * here and closed by `HybridSerializedStates.close()` at importer teardown.
82
89
  *
83
90
  * In-process only: it holds shared mutable state (the in-memory leaf
@@ -92,7 +99,8 @@ export declare class HybridWorkerConfig<T = undefined> implements WorkerConfig<T
92
99
  readonly dbPath: string;
93
100
  readonly ephemeral: boolean;
94
101
  readonly compression: boolean;
95
- static new<T>({ nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral, compression, }: {
102
+ private readonly states;
103
+ static new<T>({ nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral, compression, backend, sharedFjallSession, }: {
96
104
  nodeName: string;
97
105
  chainSpec: ChainSpec;
98
106
  workerParams: T;
@@ -100,9 +108,16 @@ export declare class HybridWorkerConfig<T = undefined> implements WorkerConfig<T
100
108
  dbPath: string;
101
109
  ephemeral?: boolean;
102
110
  compression?: boolean;
103
- }): HybridWorkerConfig<T>;
111
+ backend?: HybridBackend;
112
+ /**
113
+ * Reuse an already-open fjall values session instead of opening a fresh
114
+ * keyspace. The fuzz target opens one per run and passes it on every reset,
115
+ * so only the in-memory blocks/leaf sets are rebuilt per vector. Ignored
116
+ * unless `backend === "fjall"`.
117
+ */
118
+ sharedFjallSession?: FjallValuesSession;
119
+ }): Promise<HybridWorkerConfig<T>>;
104
120
  private readonly blocks;
105
- private readonly states;
106
121
  private constructor();
107
122
  openDatabase(_options?: {
108
123
  readonly: boolean;
@@ -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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"}
@@ -1,10 +1,14 @@
1
1
  import { Decoder, Encoder } from "#@typeberry/codec";
2
2
  import { ChainSpec } from "#@typeberry/config";
3
3
  import { InMemoryBlocks, InMemorySerializedStates, } from "#@typeberry/database";
4
- import { HybridSerializedStates, LmdbBlocks, LmdbRoot, LmdbStates } from "#@typeberry/database-lmdb";
4
+ import { HybridSerializedStates as FjallHybridSerializedStates, FjallValuesSession } from "#@typeberry/database-fjall";
5
+ import { LmdbBlocks, HybridSerializedStates as LmdbHybridSerializedStates, LmdbRoot, LmdbStates, } from "#@typeberry/database-lmdb";
5
6
  import { Blake2b } from "#@typeberry/hash";
6
7
  import { ThreadPort } from "./port.js";
7
- /** A worker config that's usable in node.js and uses LMDB database backend. */
8
+ // Re-exported so the fuzz target can open one values session per run and reuse
9
+ // it across resets (see `HybridWorkerConfig` / `mainFuzz`).
10
+ export { FjallValuesSession };
11
+ /** Worker config for node.js, backed by the LMDB database. */
8
12
  export class LmdbWorkerConfig {
9
13
  nodeName;
10
14
  chainSpec;
@@ -32,7 +36,7 @@ export class LmdbWorkerConfig {
32
36
  });
33
37
  }
34
38
  constructor(nodeName, chainSpec, workerParams, dbPath, blake2b, ports,
35
- // When set, the underlying LMDB skips fsync. Only safe for throwaway
39
+ // When set, the underlying database skips fsync. Only safe for throwaway
36
40
  // databases (the fuzz target wipes on reset). Not transferred to worker
37
41
  // threads, so the durable main node path always gets the default.
38
42
  ephemeral = false) {
@@ -110,11 +114,14 @@ export class InMemWorkerConfig {
110
114
  }
111
115
  /**
112
116
  * Hybrid worker config for the fuzz target: in-memory blocks and leaf sets,
113
- * but large values persisted to LMDB.
117
+ * but large values persisted to disk. The `backend` picks where the values go
118
+ * (lmdb or fjall).
119
+ *
120
+ * fjall opens its keyspace asynchronously, that is why `new` here is async.
114
121
  *
115
122
  * Like `InMemWorkerConfig`, the blocks and leaf sets are shared across the
116
123
  * open/close/reopen dance that genesis init performs, so `openDatabase`
117
- * returns the same instances and a no-op close. The LMDB root is opened once
124
+ * returns the same instances and a no-op close. The values store is opened once
118
125
  * here and closed by `HybridSerializedStates.close()` at importer teardown.
119
126
  *
120
127
  * In-process only: it holds shared mutable state (the in-memory leaf
@@ -129,12 +136,19 @@ export class HybridWorkerConfig {
129
136
  dbPath;
130
137
  ephemeral;
131
138
  compression;
132
- static new({ nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral = false, compression = true, }) {
133
- return new HybridWorkerConfig(nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral, compression);
139
+ states;
140
+ static async new({ nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral = false, compression = true, backend = "lmdb", sharedFjallSession, }) {
141
+ // The values store is created once here and shared across reopen. When a
142
+ // session is given (fuzz reset reuse) we wrap it instead of opening a new one.
143
+ const states = backend === "fjall"
144
+ ? sharedFjallSession !== undefined
145
+ ? FjallHybridSerializedStates.fromSession(chainSpec, blake2b, sharedFjallSession)
146
+ : await FjallHybridSerializedStates.new({ spec: chainSpec, blake2b, dbPath, ephemeral })
147
+ : LmdbHybridSerializedStates.new({ spec: chainSpec, blake2b, dbPath, ephemeral, compression, readOnly: false });
148
+ return new HybridWorkerConfig(nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral, compression, states);
134
149
  }
135
150
  blocks;
136
- states;
137
- constructor(nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral, compression = true) {
151
+ constructor(nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral, compression, states) {
138
152
  this.nodeName = nodeName;
139
153
  this.chainSpec = chainSpec;
140
154
  this.workerParams = workerParams;
@@ -142,22 +156,15 @@ export class HybridWorkerConfig {
142
156
  this.dbPath = dbPath;
143
157
  this.ephemeral = ephemeral;
144
158
  this.compression = compression;
159
+ this.states = states;
145
160
  this.blocks = InMemoryBlocks.new();
146
- this.states = HybridSerializedStates.new({
147
- spec: this.chainSpec,
148
- blake2b: this.blake2b,
149
- dbPath: this.dbPath,
150
- ephemeral: this.ephemeral,
151
- compression: this.compression,
152
- readOnly: false,
153
- });
154
161
  }
155
162
  openDatabase(_options = { readonly: true }) {
156
163
  return {
157
164
  getBlocksDb: () => this.blocks,
158
165
  getStatesDb: () => this.states,
159
- // Leaf sets and blocks live in memory; the LMDB values store is closed
160
- // via states.close() at importer teardown, so this is a no-op.
166
+ // Leaf sets and blocks live in memory; the values store is closed via
167
+ // states.close() at importer teardown, so this is a no-op.
161
168
  close: async () => { },
162
169
  };
163
170
  }
@@ -1,11 +1,12 @@
1
1
  import assert from "node:assert";
2
+ import * as fs from "node:fs";
2
3
  import { describe, it } from "node:test";
3
4
  import { MessageChannel } from "node:worker_threads";
4
5
  import { codec } from "#@typeberry/codec";
5
6
  import { tinyChainSpec } from "#@typeberry/config";
6
7
  import { Blake2b } from "#@typeberry/hash";
7
8
  import { tryAsU32 } from "#@typeberry/numbers";
8
- import { configTransferList, LmdbWorkerConfig } from "./config.js";
9
+ import { configTransferList, HybridWorkerConfig, LmdbWorkerConfig } from "./config.js";
9
10
  import { ThreadPort } from "./port.js";
10
11
  const spec = tinyChainSpec;
11
12
  describe("LmdbWorkerConfig transfer list", () => {
@@ -39,3 +40,39 @@ describe("LmdbWorkerConfig transfer list", () => {
39
40
  }
40
41
  });
41
42
  });
43
+ describe("HybridWorkerConfig", () => {
44
+ // Both persistent backends must construct asynchronously and hand out a
45
+ // working db. fjall is the experimental backend we want to benchmark.
46
+ for (const backend of ["lmdb", "fjall"]) {
47
+ it(`constructs and opens a ${backend}-backed hybrid db`, async () => {
48
+ const blake2b = await Blake2b.createHasher();
49
+ const dbPath = fs.mkdtempSync(`typeberry-hybrid-${backend}-`);
50
+ try {
51
+ const config = await HybridWorkerConfig.new({
52
+ nodeName: "node",
53
+ chainSpec: spec,
54
+ workerParams: undefined,
55
+ blake2b,
56
+ dbPath,
57
+ ephemeral: true,
58
+ backend,
59
+ });
60
+ const db = config.openDatabase({ readonly: false });
61
+ const states = db.getStatesDb();
62
+ try {
63
+ assert.notStrictEqual(db.getBlocksDb(), undefined);
64
+ assert.notStrictEqual(states, undefined);
65
+ }
66
+ finally {
67
+ // The values store owns the on-disk resources (the no-op db.close()
68
+ // does not), so close it explicitly to release the fjall keyspace.
69
+ await states.close();
70
+ await db.close();
71
+ }
72
+ }
73
+ finally {
74
+ fs.rmSync(dbPath, { recursive: true, force: true });
75
+ }
76
+ });
77
+ }
78
+ });
@@ -18,7 +18,7 @@ import { type Opaque } from "#@typeberry/utils";
18
18
  *
19
19
  */
20
20
  export type BlockSealInput = Opaque<BytesBlob, "Seal">;
21
- /** Construction arguments for {@link Generator}. */
21
+ /** Construction arguments for `BlockGenerator`. */
22
22
  export type GeneratorArgs = {
23
23
  chainSpec: ChainSpec;
24
24
  bandersnatch: BandernsatchWasm;
@@ -27,7 +27,7 @@ export type GeneratorArgs = {
27
27
  blocks: BlocksDb;
28
28
  states: StatesDb;
29
29
  };
30
- export declare class Generator {
30
+ export declare class BlockGenerator {
31
31
  private readonly metrics;
32
32
  readonly chainSpec: ChainSpec;
33
33
  readonly bandersnatch: BandernsatchWasm;
@@ -35,8 +35,8 @@ export declare class Generator {
35
35
  readonly blake2b: Blake2b;
36
36
  private readonly blocks;
37
37
  private readonly states;
38
- /** Build a {@link Generator} from its collaborators. */
39
- static new(args: GeneratorArgs): Generator;
38
+ /** Build a block generator from its collaborators. */
39
+ static new(args: GeneratorArgs): BlockGenerator;
40
40
  private constructor();
41
41
  private getLastHeaderAndState;
42
42
  nextBlockView(validatorIndex: ValidatorIndex, bandersnatchSecret: BandersnatchSecretSeed, sealPayload: BlockSealInput, timeSlot: TimeSlot, pendingTickets?: {
@@ -71,4 +71,4 @@ export declare class Generator {
71
71
  id: EntropyHash;
72
72
  }[]): Promise<Block>;
73
73
  }
74
- //# sourceMappingURL=generator.d.ts.map
74
+ //# sourceMappingURL=block-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-generator.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/block-authorship/block-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,KAAK,WAAW,EAIhB,KAAK,QAAQ,EACb,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,2BAA2B,CAAC;AAEtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAS,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAoC,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAClG,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAIvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAGhF,OAAO,EAAqB,KAAK,MAAM,EAAU,MAAM,kBAAkB,CAAC;AAM1E;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAEvD,mDAAmD;AACnD,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,QAAQ,CAAC;CAClB,CAAC;AAEF,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;IAEnE,SAAgB,SAAS,EAAE,SAAS,CAAC;IACrC,SAAgB,YAAY,EAAE,gBAAgB,CAAC;IAC/C,SAAgB,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC;IAClD,SAAgB,OAAO,EAAE,OAAO,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAElC,sDAAsD;IACtD,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa;IAI9B,OAAO;IAUP,OAAO,CAAC,qBAAqB;IAYvB,aAAa,CACjB,cAAc,EAAE,cAAc,EAC9B,kBAAkB,EAAE,sBAAsB,EAC1C,WAAW,EAAE,cAAc,EAC3B,QAAQ,EAAE,QAAQ,EAClB,cAAc,GAAE;QAAE,MAAM,EAAE,YAAY,CAAC;QAAC,EAAE,EAAE,WAAW,CAAA;KAAE,EAAO,GAC/D,OAAO,CAAC,SAAS,CAAC;IAKrB;;;;;;;;;OASG;YACW,cAAc;IAiB5B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,uBAAuB;IA4BzB,SAAS,CACb,cAAc,EAAE,cAAc,EAC9B,kBAAkB,EAAE,sBAAsB,EAC1C,WAAW,EAAE,cAAc,EAC3B,QAAQ,EAAE,QAAQ,EAClB,cAAc,GAAE;QAAE,MAAM,EAAE,YAAY,CAAC;QAAC,EAAE,EAAE,WAAW,CAAA;KAAE,EAAO;CAqGnE"}
@@ -13,7 +13,7 @@ import { asOpaqueType, now, Result } from "#@typeberry/utils";
13
13
  import * as metrics from "./metrics.js";
14
14
  const EMPTY_AUX_DATA = BytesBlob.empty();
15
15
  const logger = Logger.new(import.meta.filename, "author");
16
- export class Generator {
16
+ export class BlockGenerator {
17
17
  metrics;
18
18
  chainSpec;
19
19
  bandersnatch;
@@ -21,9 +21,9 @@ export class Generator {
21
21
  blake2b;
22
22
  blocks;
23
23
  states;
24
- /** Build a {@link Generator} from its collaborators. */
24
+ /** Build a block generator from its collaborators. */
25
25
  static new(args) {
26
- return new Generator(args);
26
+ return new BlockGenerator(args);
27
27
  }
28
28
  constructor(args) {
29
29
  this.chainSpec = args.chainSpec;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=block-generator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-generator.test.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/block-authorship/block-generator.test.ts"],"names":[],"mappings":""}
@@ -13,7 +13,7 @@ import { JAM_FALLBACK_SEAL } from "#@typeberry/safrole/constants.js";
13
13
  import { VALIDATOR_META_BYTES, ValidatorData } from "#@typeberry/state";
14
14
  import { SafroleSealingKeysKind } from "#@typeberry/state/safrole-data.js";
15
15
  import { asOpaqueType, deepEqual, Result } from "#@typeberry/utils";
16
- import { Generator } from "./generator.js";
16
+ import { BlockGenerator } from "./block-generator.js";
17
17
  // Test validator data - need 6 validators to match tinyChainSpec.validatorsCount
18
18
  const validatorDataArray = [
19
19
  {
@@ -157,7 +157,7 @@ describe("Generator", () => {
157
157
  const state = createMockState(0);
158
158
  const blocksDb = createMockBlocksDb(MOCK_PARENT_HASH);
159
159
  const statesDb = createMockStatesDb(state);
160
- const generator = Generator.new({
160
+ const generator = BlockGenerator.new({
161
161
  chainSpec: tinyChainSpec,
162
162
  bandersnatch,
163
163
  keccakHasher,
@@ -180,7 +180,7 @@ describe("Generator", () => {
180
180
  const state = createMockState(0);
181
181
  const blocksDb = createMockBlocksDb(MOCK_PARENT_HASH);
182
182
  const statesDb = createMockStatesDb(state);
183
- const generator = Generator.new({
183
+ const generator = BlockGenerator.new({
184
184
  chainSpec: tinyChainSpec,
185
185
  bandersnatch,
186
186
  keccakHasher,
@@ -225,7 +225,7 @@ describe("Generator", () => {
225
225
  const state = createMockState(9);
226
226
  const blocksDb = createMockBlocksDb(MOCK_PARENT_HASH);
227
227
  const statesDb = createMockStatesDb(state);
228
- const generator = Generator.new({
228
+ const generator = BlockGenerator.new({
229
229
  chainSpec: tinyChainSpec,
230
230
  bandersnatch,
231
231
  keccakHasher,
@@ -262,7 +262,7 @@ describe("Generator", () => {
262
262
  };
263
263
  const blocksDb = createMockBlocksDb(MOCK_PARENT_HASH);
264
264
  const statesDb = createMockStatesDb(state);
265
- const generator = Generator.new({
265
+ const generator = BlockGenerator.new({
266
266
  chainSpec: tinyChainSpec,
267
267
  bandersnatch,
268
268
  keccakHasher,
@@ -300,7 +300,7 @@ describe("Generator", () => {
300
300
  const state = createMockState(0);
301
301
  const blocksDb = createMockBlocksDb(MOCK_PARENT_HASH);
302
302
  const statesDb = createMockStatesDb(state);
303
- const generator = Generator.new({
303
+ const generator = BlockGenerator.new({
304
304
  chainSpec: tinyChainSpec,
305
305
  bandersnatch,
306
306
  keccakHasher,
@@ -338,7 +338,7 @@ describe("Generator", () => {
338
338
  const state = createMockState(0);
339
339
  const blocksDb = createMockBlocksDb(MOCK_PARENT_HASH);
340
340
  const statesDb = createMockStatesDb(state);
341
- const generator = Generator.new({
341
+ const generator = BlockGenerator.new({
342
342
  chainSpec: tinyChainSpec,
343
343
  bandersnatch,
344
344
  keccakHasher,
@@ -384,7 +384,7 @@ describe("Generator", () => {
384
384
  const state = createMockState(lastSlotOfEpoch0);
385
385
  const blocksDb = createMockBlocksDb(MOCK_PARENT_HASH);
386
386
  const statesDb = createMockStatesDb(state);
387
- const generator = Generator.new({
387
+ const generator = BlockGenerator.new({
388
388
  chainSpec: tinyChainSpec,
389
389
  bandersnatch,
390
390
  keccakHasher,
@@ -0,0 +1,35 @@
1
+ import type { EntropyHash } from "#@typeberry/block";
2
+ import type { ChainSpec } from "#@typeberry/config";
3
+ import type { BandersnatchKey, BandersnatchSecretSeed, Ed25519Key, Ed25519SecretSeed } from "#@typeberry/crypto";
4
+ import type { BandernsatchWasm } from "#@typeberry/safrole/bandersnatch-wasm.js";
5
+ import { type SafroleSealingKeys } from "#@typeberry/state";
6
+ import type { BlockSealInput } from "./block-generator.js";
7
+ import type { ValidatorSecrets } from "./protocol.js";
8
+ type ValidatorPrivateKeys = {
9
+ bandersnatchSecret: BandersnatchSecretSeed;
10
+ ed25519Secret: Ed25519SecretSeed;
11
+ };
12
+ type ValidatorPublicKeys = {
13
+ bandersnatchPublic: BandersnatchKey;
14
+ ed25519Public: Ed25519Key;
15
+ };
16
+ type ValidatorKeys = ValidatorPrivateKeys & ValidatorPublicKeys;
17
+ export type SlotSealData = {
18
+ key: ValidatorKeys;
19
+ sealPayload: BlockSealInput;
20
+ logId: string;
21
+ };
22
+ /** A helper class to figure out in which slots in the next epoch we are authoring blocks. */
23
+ export declare class EpochAuthoringSlots {
24
+ private readonly ticketsPerValidator;
25
+ private readonly bandersnatch;
26
+ private readonly keys;
27
+ static new(chainSpec: ChainSpec, bandersnatch: BandernsatchWasm, ownedSecrets: readonly ValidatorSecrets[]): Promise<EpochAuthoringSlots>;
28
+ private constructor();
29
+ getValidatorKeys(): ValidatorKeys[];
30
+ getBandersnatchPublicKeys(): (import("@typeberry/bytes").Bytes<32> & import("@typeberry/utils").WithOpaque<"BandersnatchKey">)[];
31
+ getOurSlotsInKeySeries(sealingKeySeries: SafroleSealingKeys, entropy: EntropyHash): Promise<Array<SlotSealData | null>>;
32
+ private getOwnTicketIds;
33
+ }
34
+ export {};
35
+ //# sourceMappingURL=epoch-authoring-slots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epoch-authoring-slots.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/block-authorship/epoch-authoring-slots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGhH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAEhF,OAAO,EAAE,KAAK,kBAAkB,EAA0B,MAAM,kBAAkB,CAAC;AAEnF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,KAAK,oBAAoB,GAAG;IAC1B,kBAAkB,EAAE,sBAAsB,CAAC;IAC3C,aAAa,EAAE,iBAAiB,CAAC;CAClC,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,kBAAkB,EAAE,eAAe,CAAC;IACpC,aAAa,EAAE,UAAU,CAAC;CAC3B,CAAC;AAEF,KAAK,aAAa,GAAG,oBAAoB,GAAG,mBAAmB,CAAC;AAEhE,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,aAAa,CAAC;IACnB,WAAW,EAAE,cAAc,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,6FAA6F;AAC7F,qBAAa,mBAAmB;IAY5B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI;WAbV,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,SAAS,gBAAgB,EAAE;IAUhH,OAAO;IAMP,gBAAgB;IAIhB,yBAAyB;IAInB,sBAAsB,CAC1B,gBAAgB,EAAE,kBAAkB,EACpC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;YAuBxB,eAAe;CAmB9B"}