@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.
- package/package.json +1 -1
- package/packages/configs/index.d.ts +30 -1
- package/packages/configs/index.d.ts.map +1 -1
- package/packages/configs/index.js +4 -2
- package/packages/configs/typeberry-dev-full.json +29 -0
- package/packages/core/bytes/bytes.d.ts +1 -0
- package/packages/core/bytes/bytes.d.ts.map +1 -1
- package/packages/core/bytes/bytes.js +8 -0
- package/packages/core/collections/sorted-array.d.ts +1 -1
- package/packages/core/collections/sorted-array.d.ts.map +1 -1
- package/packages/core/collections/sorted-array.js +4 -2
- package/packages/core/collections/sorted-array.test.js +10 -0
- package/packages/core/collections/sorted-set.d.ts +1 -1
- package/packages/core/collections/sorted-set.d.ts.map +1 -1
- package/packages/core/collections/sorted-set.js +6 -2
- package/packages/core/collections/sorted-set.test.js +24 -0
- package/packages/core/utils/debug.d.ts +4 -2
- package/packages/core/utils/debug.d.ts.map +1 -1
- package/packages/core/utils/debug.js +18 -13
- package/packages/core/utils/debug.test.js +12 -6
- package/packages/core/utils/index.d.ts +1 -0
- package/packages/core/utils/index.d.ts.map +1 -1
- package/packages/core/utils/index.js +1 -0
- package/packages/core/utils/shutdown.d.ts +18 -0
- package/packages/core/utils/shutdown.d.ts.map +1 -0
- package/packages/core/utils/shutdown.js +3 -0
- package/packages/core/utils/shutdown.node.d.ts +5 -0
- package/packages/core/utils/shutdown.node.d.ts.map +1 -0
- package/packages/core/utils/shutdown.node.js +76 -0
- package/packages/core/utils/shutdown.test.d.ts +2 -0
- package/packages/core/utils/shutdown.test.d.ts.map +1 -0
- package/packages/core/utils/shutdown.test.js +164 -0
- package/packages/extensions/ipc/server.d.ts.map +1 -1
- package/packages/extensions/ipc/server.js +7 -0
- package/packages/jam/config-node/node-config.d.ts +22 -3
- package/packages/jam/config-node/node-config.d.ts.map +1 -1
- package/packages/jam/config-node/node-config.js +33 -6
- package/packages/jam/config-node/node-config.test.js +11 -4
- package/packages/jam/database/index.d.ts +1 -0
- package/packages/jam/database/index.d.ts.map +1 -1
- package/packages/jam/database/index.js +1 -0
- package/packages/jam/database/leaf-db-update.d.ts +1 -0
- package/packages/jam/database/leaf-db-update.d.ts.map +1 -1
- package/packages/jam/database/leaf-db-update.js +22 -5
- package/packages/jam/database/leaf-db-update.test.d.ts +2 -0
- package/packages/jam/database/leaf-db-update.test.d.ts.map +1 -0
- package/packages/jam/database/leaf-db-update.test.js +81 -0
- package/packages/jam/database/serialized-states-db.d.ts +1 -0
- package/packages/jam/database/serialized-states-db.d.ts.map +1 -1
- package/packages/jam/database/serialized-states-db.js +4 -0
- package/packages/jam/database/states.d.ts +11 -0
- package/packages/jam/database/states.d.ts.map +1 -1
- package/packages/jam/database/states.js +3 -0
- package/packages/jam/database/value-refs.d.ts +117 -0
- package/packages/jam/database/value-refs.d.ts.map +1 -0
- package/packages/jam/database/value-refs.js +206 -0
- package/packages/jam/database/value-refs.test.d.ts +2 -0
- package/packages/jam/database/value-refs.test.d.ts.map +1 -0
- package/packages/jam/database/value-refs.test.js +165 -0
- package/packages/jam/database-fjall/blocks.d.ts +25 -0
- package/packages/jam/database-fjall/blocks.d.ts.map +1 -0
- package/packages/jam/database-fjall/blocks.js +86 -0
- package/packages/jam/database-fjall/blocks.test.d.ts +2 -0
- package/packages/jam/database-fjall/blocks.test.d.ts.map +1 -0
- package/packages/jam/database-fjall/blocks.test.js +62 -0
- package/packages/jam/database-fjall/hybrid-states.d.ts +61 -10
- package/packages/jam/database-fjall/hybrid-states.d.ts.map +1 -1
- package/packages/jam/database-fjall/hybrid-states.js +131 -26
- package/packages/jam/database-fjall/hybrid-states.test.js +31 -1
- package/packages/jam/database-fjall/index.d.ts +2 -0
- package/packages/jam/database-fjall/index.d.ts.map +1 -1
- package/packages/jam/database-fjall/index.js +2 -0
- package/packages/jam/database-fjall/root.d.ts +29 -17
- package/packages/jam/database-fjall/root.d.ts.map +1 -1
- package/packages/jam/database-fjall/root.js +33 -13
- package/packages/jam/database-fjall/states.d.ts +31 -0
- package/packages/jam/database-fjall/states.d.ts.map +1 -0
- package/packages/jam/database-fjall/states.js +99 -0
- package/packages/jam/database-fjall/states.test.d.ts +2 -0
- package/packages/jam/database-fjall/states.test.d.ts.map +1 -0
- package/packages/jam/database-fjall/states.test.js +150 -0
- package/packages/jam/database-lmdb/hybrid-states.d.ts +12 -0
- package/packages/jam/database-lmdb/hybrid-states.d.ts.map +1 -1
- package/packages/jam/database-lmdb/hybrid-states.js +45 -4
- package/packages/jam/database-lmdb/states.d.ts +1 -0
- package/packages/jam/database-lmdb/states.d.ts.map +1 -1
- package/packages/jam/database-lmdb/states.js +5 -0
- package/packages/jam/jamnp-s/tasks/ticket-distribution.js +1 -1
- package/packages/jam/node/export.d.ts.map +1 -1
- package/packages/jam/node/export.js +18 -9
- package/packages/jam/node/main-fuzz.d.ts +4 -1
- package/packages/jam/node/main-fuzz.d.ts.map +1 -1
- package/packages/jam/node/main-fuzz.js +127 -55
- package/packages/jam/node/main-importer.d.ts +11 -2
- package/packages/jam/node/main-importer.d.ts.map +1 -1
- package/packages/jam/node/main-importer.js +27 -12
- package/packages/jam/node/main.d.ts.map +1 -1
- package/packages/jam/node/main.js +42 -15
- package/packages/jam/node/workers.d.ts +4 -4
- package/packages/jam/node/workers.d.ts.map +1 -1
- package/packages/jam/safrole/bandersnatch-vrf.d.ts +22 -2
- package/packages/jam/safrole/bandersnatch-vrf.d.ts.map +1 -1
- package/packages/jam/safrole/bandersnatch-vrf.js +54 -20
- package/packages/jam/safrole/bandersnatch-vrf.test.js +3 -2
- package/packages/jam/safrole/bandersnatch-wasm.d.ts +10 -0
- package/packages/jam/safrole/bandersnatch-wasm.d.ts.map +1 -1
- package/packages/jam/safrole/bandersnatch-wasm.js +12 -0
- package/packages/jam/ticket-pool/ticket-validator.d.ts +5 -4
- package/packages/jam/ticket-pool/ticket-validator.d.ts.map +1 -1
- package/packages/jam/ticket-pool/ticket-validator.js +8 -3
- package/packages/jam/ticket-pool/ticket-validator.test.js +5 -4
- package/packages/jam/ticket-pool/verified-ticket-pool.d.ts +2 -0
- package/packages/jam/ticket-pool/verified-ticket-pool.d.ts.map +1 -1
- package/packages/jam/ticket-pool/verified-ticket-pool.js +4 -0
- package/packages/jam/ticket-pool/verified-ticket-pool.test.js +5 -5
- package/packages/workers/api/config.d.ts +2 -2
- package/packages/workers/api/config.d.ts.map +1 -1
- package/packages/workers/api/config.js +1 -1
- package/packages/workers/api/port.d.ts +5 -1
- package/packages/workers/api/port.d.ts.map +1 -1
- package/packages/workers/api/port.js +56 -13
- package/packages/workers/api/port.test.js +35 -0
- package/packages/workers/api-node/config.d.ts +58 -9
- package/packages/workers/api-node/config.d.ts.map +1 -1
- package/packages/workers/api-node/config.js +140 -18
- package/packages/workers/api-node/config.test.js +52 -3
- package/packages/workers/api-node/port.d.ts +3 -0
- package/packages/workers/api-node/port.d.ts.map +1 -1
- package/packages/workers/api-node/port.js +31 -2
- package/packages/workers/api-node/port.test.js +17 -0
- package/packages/workers/api-node/protocol.d.ts +3 -3
- package/packages/workers/api-node/protocol.d.ts.map +1 -1
- package/packages/workers/api-node/protocol.js +18 -12
- package/packages/workers/block-authorship/{generator.d.ts → block-generator.d.ts} +5 -5
- package/packages/workers/block-authorship/block-generator.d.ts.map +1 -0
- package/packages/workers/block-authorship/{generator.js → block-generator.js} +3 -3
- package/packages/workers/block-authorship/block-generator.test.d.ts +2 -0
- package/packages/workers/block-authorship/block-generator.test.d.ts.map +1 -0
- package/packages/workers/block-authorship/{generator.test.js → block-generator.test.js} +8 -8
- package/packages/workers/block-authorship/epoch-authoring-slots.d.ts +35 -0
- package/packages/workers/block-authorship/epoch-authoring-slots.d.ts.map +1 -0
- package/packages/workers/block-authorship/epoch-authoring-slots.js +86 -0
- package/packages/workers/block-authorship/epoch-tracker.d.ts +29 -0
- package/packages/workers/block-authorship/epoch-tracker.d.ts.map +1 -0
- package/packages/workers/block-authorship/epoch-tracker.js +80 -0
- package/packages/workers/block-authorship/index.d.ts.map +1 -1
- package/packages/workers/block-authorship/index.js +1 -1
- package/packages/workers/block-authorship/main.d.ts +3 -0
- package/packages/workers/block-authorship/main.d.ts.map +1 -1
- package/packages/workers/block-authorship/main.js +194 -262
- package/packages/workers/block-authorship/ticket-generator/bootstrap-main.d.ts +2 -0
- package/packages/workers/block-authorship/ticket-generator/bootstrap-main.d.ts.map +1 -0
- package/packages/workers/block-authorship/ticket-generator/bootstrap-main.js +23 -0
- package/packages/workers/block-authorship/ticket-generator/index.d.ts +16 -0
- package/packages/workers/block-authorship/ticket-generator/index.d.ts.map +1 -0
- package/packages/workers/block-authorship/ticket-generator/index.js +62 -0
- package/packages/workers/block-authorship/ticket-generator/protocol.d.ts +50 -0
- package/packages/workers/block-authorship/ticket-generator/protocol.d.ts.map +1 -0
- package/packages/workers/block-authorship/ticket-generator/protocol.js +54 -0
- package/packages/workers/block-authorship/{ticket-generator.d.ts → ticket-generator/ticket-generator.d.ts} +4 -0
- package/packages/workers/block-authorship/ticket-generator/ticket-generator.d.ts.map +1 -0
- package/packages/workers/block-authorship/{ticket-generator.js → ticket-generator/ticket-generator.js} +19 -9
- package/packages/workers/block-authorship/ticket-generator/ticket-generator.test.d.ts.map +1 -0
- package/packages/workers/block-authorship/{ticket-generator.test.js → ticket-generator/ticket-generator.test.js} +13 -9
- package/packages/workers/block-authorship/ticket-generator/worker-pool.d.ts +36 -0
- package/packages/workers/block-authorship/ticket-generator/worker-pool.d.ts.map +1 -0
- package/packages/workers/block-authorship/ticket-generator/worker-pool.js +111 -0
- package/packages/workers/block-authorship/ticket-validator.d.ts +7 -8
- package/packages/workers/block-authorship/ticket-validator.d.ts.map +1 -1
- package/packages/workers/block-authorship/ticket-validator.js +26 -23
- package/packages/workers/comms-authorship-network/protocol.d.ts +4 -4
- package/packages/workers/comms-authorship-network/protocol.d.ts.map +1 -1
- package/packages/workers/comms-authorship-network/protocol.js +4 -5
- package/packages/workers/comms-authorship-network/tickets-message.d.ts +0 -14
- package/packages/workers/comms-authorship-network/tickets-message.d.ts.map +1 -1
- package/packages/workers/comms-authorship-network/tickets-message.js +0 -17
- package/packages/workers/importer/finality.d.ts +2 -0
- package/packages/workers/importer/finality.d.ts.map +1 -1
- package/packages/workers/importer/finality.js +8 -1
- package/packages/workers/importer/importer.d.ts +2 -2
- package/packages/workers/importer/importer.d.ts.map +1 -1
- package/packages/workers/importer/importer.js +6 -5
- package/packages/workers/importer/main.d.ts +1 -1
- package/packages/workers/importer/main.d.ts.map +1 -1
- package/packages/workers/importer/main.js +1 -1
- package/packages/workers/importer/stats.d.ts +1 -3
- package/packages/workers/importer/stats.d.ts.map +1 -1
- package/packages/workers/importer/stats.js +12 -12
- package/packages/workers/jam-network/main.d.ts.map +1 -1
- package/packages/workers/jam-network/main.js +9 -4
- package/packages/workers/block-authorship/generator.d.ts.map +0 -1
- package/packages/workers/block-authorship/generator.test.d.ts +0 -2
- package/packages/workers/block-authorship/generator.test.d.ts.map +0 -1
- package/packages/workers/block-authorship/ticket-generator.d.ts.map +0 -1
- package/packages/workers/block-authorship/ticket-generator.test.d.ts.map +0 -1
- /package/packages/configs/{typeberry-dev.json → typeberry-dev-tiny.json} +0 -0
- /package/packages/workers/block-authorship/{ticket-generator.test.d.ts → ticket-generator/ticket-generator.test.d.ts} +0 -0
|
@@ -2,11 +2,12 @@ import assert from "node:assert";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import { describe, it } from "node:test";
|
|
4
4
|
import { MessageChannel } from "node:worker_threads";
|
|
5
|
+
import { Bytes } from "#@typeberry/bytes";
|
|
5
6
|
import { codec } from "#@typeberry/codec";
|
|
6
7
|
import { tinyChainSpec } from "#@typeberry/config";
|
|
7
|
-
import { Blake2b } from "#@typeberry/hash";
|
|
8
|
+
import { Blake2b, HASH_SIZE } from "#@typeberry/hash";
|
|
8
9
|
import { tryAsU32 } from "#@typeberry/numbers";
|
|
9
|
-
import { configTransferList, HybridWorkerConfig, LmdbWorkerConfig } from "./config.js";
|
|
10
|
+
import { configTransferList, FjallWorkerConfig, HybridWorkerConfig, LmdbWorkerConfig } from "./config.js";
|
|
10
11
|
import { ThreadPort } from "./port.js";
|
|
11
12
|
const spec = tinyChainSpec;
|
|
12
13
|
describe("LmdbWorkerConfig transfer list", () => {
|
|
@@ -40,6 +41,54 @@ describe("LmdbWorkerConfig transfer list", () => {
|
|
|
40
41
|
}
|
|
41
42
|
});
|
|
42
43
|
});
|
|
44
|
+
describe("FjallWorkerConfig transfer list", () => {
|
|
45
|
+
it("surfaces embedded worker ports and marks the backend", async () => {
|
|
46
|
+
const blake2b = await Blake2b.createHasher();
|
|
47
|
+
const [portA, portB] = ThreadPort.pair(spec);
|
|
48
|
+
const config = FjallWorkerConfig.new({
|
|
49
|
+
nodeName: "node",
|
|
50
|
+
chainSpec: spec,
|
|
51
|
+
workerParams: tryAsU32(7),
|
|
52
|
+
dbPath: "db",
|
|
53
|
+
blake2b,
|
|
54
|
+
ports: new Map([["authorship-network", portA]]),
|
|
55
|
+
});
|
|
56
|
+
try {
|
|
57
|
+
const transferable = config.intoTransferable(codec.varU32);
|
|
58
|
+
assert.strictEqual(transferable.databaseBackend, "fjall");
|
|
59
|
+
assert.strictEqual(configTransferList(transferable).length, 1);
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
portA.close();
|
|
63
|
+
portB.close();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
it("opens writable and read-only handles over one shared fjall path", async () => {
|
|
67
|
+
const blake2b = await Blake2b.createHasher();
|
|
68
|
+
const dbPath = fs.mkdtempSync("typeberry-fjall-worker-");
|
|
69
|
+
const config = FjallWorkerConfig.new({
|
|
70
|
+
nodeName: "node",
|
|
71
|
+
chainSpec: spec,
|
|
72
|
+
workerParams: undefined,
|
|
73
|
+
dbPath,
|
|
74
|
+
blake2b,
|
|
75
|
+
});
|
|
76
|
+
let writer = null;
|
|
77
|
+
let reader = null;
|
|
78
|
+
try {
|
|
79
|
+
writer = await config.openDatabase({ readonly: false });
|
|
80
|
+
reader = await config.openDatabase({ readonly: true });
|
|
81
|
+
const best = Bytes.fill(HASH_SIZE, 9).asOpaque();
|
|
82
|
+
await writer.getBlocksDb().setBestHeaderHash(best);
|
|
83
|
+
assert.strictEqual(reader.getBlocksDb().getBestHeaderHash().toString(), best.toString());
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
await reader?.close();
|
|
87
|
+
await writer?.close();
|
|
88
|
+
fs.rmSync(dbPath, { recursive: true, force: true });
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
43
92
|
describe("HybridWorkerConfig", () => {
|
|
44
93
|
// Both persistent backends must construct asynchronously and hand out a
|
|
45
94
|
// working db. fjall is the experimental backend we want to benchmark.
|
|
@@ -57,7 +106,7 @@ describe("HybridWorkerConfig", () => {
|
|
|
57
106
|
ephemeral: true,
|
|
58
107
|
backend,
|
|
59
108
|
});
|
|
60
|
-
const db = config.openDatabase({ readonly: false });
|
|
109
|
+
const db = await config.openDatabase({ readonly: false });
|
|
61
110
|
const states = db.getStatesDb();
|
|
62
111
|
try {
|
|
63
112
|
assert.notStrictEqual(db.getBlocksDb(), undefined);
|
|
@@ -18,6 +18,7 @@ export declare class ThreadPort implements Port {
|
|
|
18
18
|
static pair(spec: ChainSpec): [ThreadPort, ThreadPort];
|
|
19
19
|
readonly threadId: number;
|
|
20
20
|
private readonly events;
|
|
21
|
+
private readonly pendingMessages;
|
|
21
22
|
static new(spec: ChainSpec, port: MessagePort): ThreadPort;
|
|
22
23
|
private constructor();
|
|
23
24
|
static fromTransferable(spec: ChainSpec, { port }: TransferablePort): ThreadPort;
|
|
@@ -28,5 +29,7 @@ export declare class ThreadPort implements Port {
|
|
|
28
29
|
on<T>(event: string, codec: Codec<T>, callback: (msg: Envelope<T>) => void): () => void;
|
|
29
30
|
once<T>(event: string, codec: Codec<T>, callback: (msg: Envelope<T>) => void): () => void;
|
|
30
31
|
postMessage<T>(event: string, codec: Codec<T>, msg: Envelope<T>): void;
|
|
32
|
+
private queuePending;
|
|
33
|
+
private flushPending;
|
|
31
34
|
}
|
|
32
35
|
//# sourceMappingURL=port.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api-node/port.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,WAAW,EAA+B,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,KAAK,KAAK,EAAoB,MAAM,kBAAkB,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api-node/port.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,WAAW,EAA+B,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,KAAK,KAAK,EAAoB,MAAM,kBAAkB,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AAErE,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAIF,qDAAqD;AACrD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC;AACF,qBAAa,UAAW,YAAW,IAAI;IAgBnC,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAhBvB,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC;IAMtD,SAAgB,QAAQ,SAAY;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;IAEhE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW;IAI7C,OAAO;IAmBP,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,EAAE,gBAAgB;IAInE,gBAAgB,IAAI,gBAAgB;IAIpC,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAI3C,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;IAUvF,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;IAoBzF,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAYtE,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,YAAY;CAUrB"}
|
|
@@ -2,7 +2,6 @@ import EventEmitter from "node:events";
|
|
|
2
2
|
import { threadId } from "node:worker_threads";
|
|
3
3
|
import { Decoder, Encoder } from "#@typeberry/codec";
|
|
4
4
|
import { Logger } from "#@typeberry/logger";
|
|
5
|
-
import { check } from "#@typeberry/utils";
|
|
6
5
|
const MESSAGE_KEYS = ["eventName", "responseId", "data"];
|
|
7
6
|
const logger = Logger.new(import.meta.filename, "workers/api");
|
|
8
7
|
export class ThreadPort {
|
|
@@ -14,6 +13,7 @@ export class ThreadPort {
|
|
|
14
13
|
}
|
|
15
14
|
threadId = threadId;
|
|
16
15
|
events = new EventEmitter();
|
|
16
|
+
pendingMessages = new Map();
|
|
17
17
|
static new(spec, port) {
|
|
18
18
|
return new ThreadPort(spec, port);
|
|
19
19
|
}
|
|
@@ -26,7 +26,10 @@ export class ThreadPort {
|
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
const { eventName, responseId, data } = input;
|
|
29
|
-
|
|
29
|
+
if (this.events.listeners(eventName).length === 0) {
|
|
30
|
+
this.queuePending(input);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
30
33
|
this.events.emit(eventName, responseId, data);
|
|
31
34
|
});
|
|
32
35
|
}
|
|
@@ -38,6 +41,7 @@ export class ThreadPort {
|
|
|
38
41
|
}
|
|
39
42
|
close() {
|
|
40
43
|
this.port.close();
|
|
44
|
+
this.pendingMessages.clear();
|
|
41
45
|
}
|
|
42
46
|
createListener(codec, callback) {
|
|
43
47
|
return (responseId, data) => {
|
|
@@ -64,12 +68,22 @@ export class ThreadPort {
|
|
|
64
68
|
on(event, codec, callback) {
|
|
65
69
|
const listener = this.createListener(codec, callback);
|
|
66
70
|
this.events.on(event, listener);
|
|
71
|
+
this.flushPending(event, listener);
|
|
67
72
|
return () => {
|
|
68
73
|
this.events.off(event, listener);
|
|
69
74
|
};
|
|
70
75
|
}
|
|
71
76
|
once(event, codec, callback) {
|
|
72
77
|
const listener = this.createListener(codec, callback);
|
|
78
|
+
const pending = this.pendingMessages.get(event);
|
|
79
|
+
const pendingMessage = pending?.shift();
|
|
80
|
+
if (pending?.length === 0) {
|
|
81
|
+
this.pendingMessages.delete(event);
|
|
82
|
+
}
|
|
83
|
+
if (pendingMessage !== undefined) {
|
|
84
|
+
listener(pendingMessage.responseId, pendingMessage.data);
|
|
85
|
+
return () => { };
|
|
86
|
+
}
|
|
73
87
|
this.events.once(event, listener);
|
|
74
88
|
return () => {
|
|
75
89
|
this.events.off(event, listener);
|
|
@@ -86,6 +100,21 @@ export class ThreadPort {
|
|
|
86
100
|
// always returns owned uint8arrays.
|
|
87
101
|
this.port.postMessage(message, [encoded.raw.buffer]);
|
|
88
102
|
}
|
|
103
|
+
queuePending(msg) {
|
|
104
|
+
const pending = this.pendingMessages.get(msg.eventName) ?? [];
|
|
105
|
+
pending.push(msg);
|
|
106
|
+
this.pendingMessages.set(msg.eventName, pending);
|
|
107
|
+
}
|
|
108
|
+
flushPending(event, listener) {
|
|
109
|
+
const pending = this.pendingMessages.get(event);
|
|
110
|
+
if (pending === undefined) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
this.pendingMessages.delete(event);
|
|
114
|
+
for (const msg of pending) {
|
|
115
|
+
listener(msg.responseId, msg.data);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
89
118
|
}
|
|
90
119
|
function isMessage(data) {
|
|
91
120
|
const isObject = data !== null && typeof data === "object";
|
|
@@ -36,4 +36,21 @@ describe("ThreadPort", () => {
|
|
|
36
36
|
data: tryAsU32(42),
|
|
37
37
|
});
|
|
38
38
|
});
|
|
39
|
+
it("should deliver messages sent before the listener is attached", async () => {
|
|
40
|
+
const tx = ThreadPort.new(spec, channel.port1);
|
|
41
|
+
const rx = ThreadPort.new(spec, channel.port2);
|
|
42
|
+
tx.postMessage("hello", codec.varU32, {
|
|
43
|
+
responseId: "10",
|
|
44
|
+
data: tryAsU32(42),
|
|
45
|
+
});
|
|
46
|
+
await setTimeout(10);
|
|
47
|
+
let received = null;
|
|
48
|
+
rx.on("hello", codec.varU32, (msg) => {
|
|
49
|
+
received = msg;
|
|
50
|
+
});
|
|
51
|
+
assert.deepStrictEqual(received, {
|
|
52
|
+
responseId: "10",
|
|
53
|
+
data: tryAsU32(42),
|
|
54
|
+
});
|
|
55
|
+
});
|
|
39
56
|
});
|
|
@@ -2,7 +2,7 @@ import { type MessagePort, Worker } from "node:worker_threads";
|
|
|
2
2
|
import type { Decode, Encode } from "#@typeberry/codec";
|
|
3
3
|
import { Listener } from "#@typeberry/listener";
|
|
4
4
|
import type { Api, Internal, LousyProtocol } from "#@typeberry/workers-api/types.js";
|
|
5
|
-
import {
|
|
5
|
+
import { type PersistentWorkerConfig, type TransferableConfig } from "./config.js";
|
|
6
6
|
/** Type of the control plane message. */
|
|
7
7
|
export declare enum WorkerControlPlaneMsg {
|
|
8
8
|
/** Transfers a communication port to some other thread. */
|
|
@@ -31,7 +31,7 @@ export type WorkerControlPlane = ({
|
|
|
31
31
|
/**
|
|
32
32
|
* Invoked by the main thread, to spawn a worker thread and initiate communication channel.
|
|
33
33
|
*/
|
|
34
|
-
export declare function spawnWorker<To, From, Params>(protocol: LousyProtocol<To, From>, bootstrapPath: URL, config:
|
|
34
|
+
export declare function spawnWorker<To, From, Params>(protocol: LousyProtocol<To, From>, bootstrapPath: URL, config: PersistentWorkerConfig<Params>, paramsEncoder: Encode<Params>): {
|
|
35
35
|
api: Api<typeof protocol>;
|
|
36
36
|
worker: Worker;
|
|
37
37
|
workerFinished: Promise<void>;
|
|
@@ -40,7 +40,7 @@ export declare function spawnWorker<To, From, Params>(protocol: LousyProtocol<To
|
|
|
40
40
|
* Initialize worker thread by awaiting the config message.
|
|
41
41
|
*/
|
|
42
42
|
export declare function initWorker<To, From, Params>(protocol: LousyProtocol<To, From>, paramsDecoder: Decode<Params>): Promise<{
|
|
43
|
-
config:
|
|
43
|
+
config: PersistentWorkerConfig<Params>;
|
|
44
44
|
comms: Internal<typeof protocol>;
|
|
45
45
|
threadComms: Listener<ThreadComms>;
|
|
46
46
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api-node/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAc,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC3F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAI/C,OAAO,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api-node/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAc,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC3F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAI/C,OAAO,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAEL,KAAK,sBAAsB,EAE3B,KAAK,kBAAkB,EACxB,MAAM,aAAa,CAAC;AAMrB,yCAAyC;AACzC,oBAAY,qBAAqB;IAC/B,2DAA2D;IAC3D,iBAAiB,IAAI;IACrB,sCAAsC;IACtC,MAAM,IAAI;CACX;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,kDAAkD;IAClD,UAAU,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC;AACF,yFAAyF;AACzF,MAAM,MAAM,kBAAkB,GAC1B,CAAC;IACC,wDAAwD;IACxD,IAAI,EAAE,qBAAqB,CAAC,iBAAiB,CAAC;CAC/C,GAAG,WAAW,CAAC,GAChB;IACE,8EAA8E;IAC9E,IAAI,EAAE,qBAAqB,CAAC,MAAM,CAAC;IACnC,sCAAsC;IACtC,UAAU,EAAE,WAAW,CAAC;IACxB,4BAA4B;IAC5B,MAAM,EAAE,kBAAkB,CAAC;CAC5B,CAAC;AAeN;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAC1C,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE,IAAI,CAAC,EACjC,aAAa,EAAE,GAAG,EAClB,MAAM,EAAE,sBAAsB,CAAC,MAAM,CAAC,EACtC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,GAC5B;IACD,GAAG,EAAE,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B,CAoCA;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAC/C,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE,IAAI,CAAC,EACjC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,GAC5B,OAAO,CAAC;IACT,MAAM,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACvC,KAAK,EAAE,QAAQ,CAAC,OAAO,QAAQ,CAAC,CAAC;IACjC,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;CACpC,CAAC,CAwDD"}
|
|
@@ -3,7 +3,7 @@ import { Listener } from "#@typeberry/listener";
|
|
|
3
3
|
import { Level, Logger } from "#@typeberry/logger";
|
|
4
4
|
import { assertNever } from "#@typeberry/utils";
|
|
5
5
|
import { Channel } from "#@typeberry/workers-api";
|
|
6
|
-
import { configTransferList,
|
|
6
|
+
import { configTransferList, persistentConfigFromTransferable, } from "./config.js";
|
|
7
7
|
import { logHeapLimit, workerResourceLimits } from "./host-environment.js";
|
|
8
8
|
import { ThreadPort } from "./port.js";
|
|
9
9
|
const logger = Logger.new(import.meta.filename, "workers");
|
|
@@ -70,13 +70,14 @@ export async function initWorker(protocol, paramsDecoder) {
|
|
|
70
70
|
logger.trace `Worker ${protocol.name} starting.`;
|
|
71
71
|
logHeapLimit(logger, protocol.name);
|
|
72
72
|
return new Promise((resolve, reject) => {
|
|
73
|
-
|
|
73
|
+
const workerParentPort = parentPort;
|
|
74
|
+
if (workerParentPort === null) {
|
|
74
75
|
throw new Error(`Unable to start ${protocol.name} worker. Not running in a worker thread!`);
|
|
75
76
|
}
|
|
76
|
-
|
|
77
|
+
workerParentPort.once("close", () => reject(new Error(`(${protocol.name}) parent port closed too early`)));
|
|
77
78
|
let isResolved = false;
|
|
78
79
|
const threadComms = new Listener();
|
|
79
|
-
|
|
80
|
+
workerParentPort.on("message", async (msg) => {
|
|
80
81
|
if (!isControlPlane(msg)) {
|
|
81
82
|
logger.error `--> (${protocol.name}) received unexpected message: ${msg}`;
|
|
82
83
|
return;
|
|
@@ -93,14 +94,19 @@ export async function initWorker(protocol, paramsDecoder) {
|
|
|
93
94
|
}
|
|
94
95
|
logger.trace `--> (${protocol.name}) received configuration.`;
|
|
95
96
|
isResolved = true;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
try {
|
|
98
|
+
const config = await persistentConfigFromTransferable(paramsDecoder, msg.config);
|
|
99
|
+
const rxPort = ThreadPort.new(config.chainSpec, msg.parentPort);
|
|
100
|
+
const comms = Channel.rx(protocol, rxPort);
|
|
101
|
+
resolve({
|
|
102
|
+
config,
|
|
103
|
+
comms,
|
|
104
|
+
threadComms,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
reject(e);
|
|
109
|
+
}
|
|
104
110
|
return;
|
|
105
111
|
}
|
|
106
112
|
assertNever(msg.kind);
|
|
@@ -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
|
|
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
|
|
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
|
|
39
|
-
static new(args: GeneratorArgs):
|
|
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
|
|
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
|
|
24
|
+
/** Build a block generator from its collaborators. */
|
|
25
25
|
static new(args) {
|
|
26
|
-
return new
|
|
26
|
+
return new BlockGenerator(args);
|
|
27
27
|
}
|
|
28
28
|
constructor(args) {
|
|
29
29
|
this.chainSpec = args.chainSpec;
|
|
@@ -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 {
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { BytesBlob } from "#@typeberry/bytes";
|
|
2
|
+
import { HashDictionary } from "#@typeberry/collections";
|
|
3
|
+
import { deriveBandersnatchPublicKey, deriveEd25519PublicKey } from "#@typeberry/crypto/key-derivation.js";
|
|
4
|
+
import bandersnatchVrf from "#@typeberry/safrole/bandersnatch-vrf.js";
|
|
5
|
+
import { JAM_FALLBACK_SEAL, JAM_TICKET_SEAL } from "#@typeberry/safrole/constants.js";
|
|
6
|
+
import { SafroleSealingKeysKind } from "#@typeberry/state";
|
|
7
|
+
import { asOpaqueType } from "#@typeberry/utils";
|
|
8
|
+
/** A helper class to figure out in which slots in the next epoch we are authoring blocks. */
|
|
9
|
+
export class EpochAuthoringSlots {
|
|
10
|
+
ticketsPerValidator;
|
|
11
|
+
bandersnatch;
|
|
12
|
+
keys;
|
|
13
|
+
static async new(chainSpec, bandersnatch, ownedSecrets) {
|
|
14
|
+
const keys = await derivePublicKeys(ownedSecrets);
|
|
15
|
+
const keysDictionary = new HashDictionary();
|
|
16
|
+
for (const key of keys) {
|
|
17
|
+
keysDictionary.set(key.bandersnatchPublic, key);
|
|
18
|
+
}
|
|
19
|
+
return new EpochAuthoringSlots(chainSpec.ticketsPerValidator, bandersnatch, keysDictionary);
|
|
20
|
+
}
|
|
21
|
+
constructor(ticketsPerValidator, bandersnatch, keys) {
|
|
22
|
+
this.ticketsPerValidator = ticketsPerValidator;
|
|
23
|
+
this.bandersnatch = bandersnatch;
|
|
24
|
+
this.keys = keys;
|
|
25
|
+
}
|
|
26
|
+
getValidatorKeys() {
|
|
27
|
+
return Array.from(this.keys.values());
|
|
28
|
+
}
|
|
29
|
+
getBandersnatchPublicKeys() {
|
|
30
|
+
return Array.from(this.keys.keys());
|
|
31
|
+
}
|
|
32
|
+
async getOurSlotsInKeySeries(sealingKeySeries, entropy) {
|
|
33
|
+
// Fallback (keys) mode. Just find keys that match ours.
|
|
34
|
+
if (sealingKeySeries.kind === SafroleSealingKeysKind.Keys) {
|
|
35
|
+
const sealPayload = getFallbackSealPayload(entropy);
|
|
36
|
+
return sealingKeySeries.keys.map((author) => {
|
|
37
|
+
const key = this.keys.get(author);
|
|
38
|
+
if (key === undefined) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
key,
|
|
43
|
+
sealPayload,
|
|
44
|
+
logId: `key ${key.bandersnatchPublic.toStringTruncated()}`,
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// Tickets mode. Generate own VrfOutputHash for our tickets (cheap) and check if it matches.
|
|
49
|
+
const ownTickets = await this.getOwnTicketIds(entropy);
|
|
50
|
+
const slots = sealingKeySeries.tickets.map((ticket) => ownTickets.get(ticket.id.asOpaque()) ?? null);
|
|
51
|
+
return slots;
|
|
52
|
+
}
|
|
53
|
+
async getOwnTicketIds(entropy) {
|
|
54
|
+
// generate our own tickets first
|
|
55
|
+
const ownTickets = new HashDictionary();
|
|
56
|
+
for (let attempt = 0; attempt < this.ticketsPerValidator; attempt++) {
|
|
57
|
+
const sealPayload = getTicketSealPayload(entropy, attempt);
|
|
58
|
+
for (const key of this.keys.values()) {
|
|
59
|
+
const result = await bandersnatchVrf.getVrfOutputHash(this.bandersnatch, key.bandersnatchSecret, sealPayload);
|
|
60
|
+
if (result.isOk) {
|
|
61
|
+
const ticketId = result.ok.asOpaque();
|
|
62
|
+
ownTickets.set(ticketId, {
|
|
63
|
+
key,
|
|
64
|
+
sealPayload,
|
|
65
|
+
logId: `ticket ${ticketId} (attempt ${attempt})`,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return ownTickets;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function derivePublicKeys(keys) {
|
|
74
|
+
return Promise.all(keys.map(async (secrets) => ({
|
|
75
|
+
bandersnatchSecret: secrets.bandersnatch,
|
|
76
|
+
bandersnatchPublic: deriveBandersnatchPublicKey(secrets.bandersnatch),
|
|
77
|
+
ed25519Secret: secrets.ed25519,
|
|
78
|
+
ed25519Public: await deriveEd25519PublicKey(secrets.ed25519),
|
|
79
|
+
})));
|
|
80
|
+
}
|
|
81
|
+
function getTicketSealPayload(entropy, attempt) {
|
|
82
|
+
return asOpaqueType(BytesBlob.blobFromParts(JAM_TICKET_SEAL, entropy.raw, new Uint8Array([attempt])));
|
|
83
|
+
}
|
|
84
|
+
function getFallbackSealPayload(entropy) {
|
|
85
|
+
return asOpaqueType(BytesBlob.blobFromParts(JAM_FALLBACK_SEAL, entropy.raw));
|
|
86
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type EntropyHash, type Epoch, type TimeSlot } from "#@typeberry/block";
|
|
2
|
+
import type { ChainSpec } from "#@typeberry/config";
|
|
3
|
+
import type { Blake2b } from "#@typeberry/hash";
|
|
4
|
+
import type { Logger } from "#@typeberry/logger";
|
|
5
|
+
import type { BandernsatchWasm } from "#@typeberry/safrole/bandersnatch-wasm.js";
|
|
6
|
+
import { type SafroleSealingKeys, type State } from "#@typeberry/state";
|
|
7
|
+
import { Result } from "#@typeberry/utils";
|
|
8
|
+
import { EpochAuthoringSlots, type SlotSealData } from "./epoch-authoring-slots.js";
|
|
9
|
+
import type { ValidatorSecrets } from "./protocol.js";
|
|
10
|
+
/** Per-epoch data computed once when entering (or resuming into) an epoch. */
|
|
11
|
+
export type EpochData = {
|
|
12
|
+
epoch: Epoch;
|
|
13
|
+
epochLength: number;
|
|
14
|
+
sealingKeySeries: SafroleSealingKeys;
|
|
15
|
+
entropy: EntropyHash;
|
|
16
|
+
slots: Array<SlotSealData | null>;
|
|
17
|
+
};
|
|
18
|
+
export declare class EpochTracker {
|
|
19
|
+
private readonly chainSpec;
|
|
20
|
+
private readonly blake2bHasher;
|
|
21
|
+
readonly authoring: EpochAuthoringSlots;
|
|
22
|
+
static new(chainSpec: ChainSpec, bandersnatch: BandernsatchWasm, blake2bHasher: Blake2b, keys: readonly ValidatorSecrets[]): Promise<EpochTracker>;
|
|
23
|
+
private constructor();
|
|
24
|
+
isEpochChanged(stateTimeSlot: TimeSlot, newTimeSlot: TimeSlot): boolean;
|
|
25
|
+
getEpochData(logger: Logger, state: State, newTimeSlot: TimeSlot): Promise<Result<EpochData, string>>;
|
|
26
|
+
private getSealingKeySeries;
|
|
27
|
+
private logEpochAuthorshipInfo;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=epoch-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"epoch-tracker.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/block-authorship/epoch-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAc,MAAM,kBAAkB,CAAC;AAC3F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAChF,OAAO,EAAE,KAAK,kBAAkB,EAA0B,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,8EAA8E;AAC9E,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,kBAAkB,CAAC;IACrC,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;CACnC,CAAC;AAEF,qBAAa,YAAY;IAYrB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,aAAa;aACd,SAAS,EAAE,mBAAmB;WAbnC,GAAG,CACd,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,gBAAgB,EAC9B,aAAa,EAAE,OAAO,EACtB,IAAI,EAAE,SAAS,gBAAgB,EAAE;IAMnC,OAAO;IAMP,cAAc,CAAC,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,GAAG,OAAO;IAOjE,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YA+B7F,mBAAmB;IAejC,OAAO,CAAC,sBAAsB;CAe/B"}
|