@typeberry/lib 0.9.0-6850f84 → 0.9.0-a723180
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/jam/config-node/node-config.d.ts +20 -2
- package/packages/jam/config-node/node-config.d.ts.map +1 -1
- package/packages/jam/config-node/node-config.js +25 -3
- package/packages/jam/config-node/node-config.test.js +8 -1
- package/packages/jam/database/serialized-states-db.d.ts +4 -1
- package/packages/jam/database/serialized-states-db.d.ts.map +1 -1
- package/packages/jam/database/serialized-states-db.js +17 -5
- package/packages/jam/database/serialized-states-db.test.d.ts +2 -0
- package/packages/jam/database/serialized-states-db.test.d.ts.map +1 -0
- package/packages/jam/database/serialized-states-db.test.js +109 -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.map +1 -1
- package/packages/jam/database-fjall/hybrid-states.js +11 -2
- package/packages/jam/database-fjall/hybrid-states.test.js +94 -2
- 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 +14 -8
- package/packages/jam/database-fjall/root.d.ts.map +1 -1
- package/packages/jam/database-fjall/root.js +25 -9
- 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.test.js +94 -2
- package/packages/jam/node/export.d.ts.map +1 -1
- package/packages/jam/node/export.js +18 -9
- package/packages/jam/node/main-importer.d.ts +4 -2
- package/packages/jam/node/main-importer.d.ts.map +1 -1
- package/packages/jam/node/main-importer.js +26 -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/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 +45 -4
- package/packages/workers/api-node/config.d.ts.map +1 -1
- package/packages/workers/api-node/config.js +127 -9
- 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/main.js +1 -1
- package/packages/workers/importer/finality.d.ts +4 -0
- package/packages/workers/importer/finality.d.ts.map +1 -1
- package/packages/workers/importer/finality.js +10 -1
- package/packages/workers/importer/finality.test.js +6 -0
- package/packages/workers/importer/importer.d.ts.map +1 -1
- package/packages/workers/importer/importer.js +3 -0
- 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/jam-network/main.js +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/export.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/export.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,wBAAsB,YAAY,CAAC,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,iBAoG9G"}
|
|
@@ -3,9 +3,10 @@ import path from "node:path";
|
|
|
3
3
|
import { Block as BlockCodec } from "#@typeberry/block";
|
|
4
4
|
import { Bytes } from "#@typeberry/bytes";
|
|
5
5
|
import { Encoder } from "#@typeberry/codec";
|
|
6
|
+
import { RegularStateBackend } from "#@typeberry/config-node";
|
|
6
7
|
import { Blake2b, HASH_SIZE } from "#@typeberry/hash";
|
|
7
8
|
import { Logger } from "#@typeberry/logger";
|
|
8
|
-
import { LmdbWorkerConfig } from "#@typeberry/workers-api-node";
|
|
9
|
+
import { FjallWorkerConfig, LmdbWorkerConfig } from "#@typeberry/workers-api-node";
|
|
9
10
|
import { getChainSpec, getDatabasePath } from "./common.js";
|
|
10
11
|
export async function exportBlocks(jamNodeConfig, output, withRelPath) {
|
|
11
12
|
const logger = Logger.new(import.meta.filename, "export");
|
|
@@ -29,14 +30,22 @@ export async function exportBlocks(jamNodeConfig, output, withRelPath) {
|
|
|
29
30
|
const blake2b = await Blake2b.createHasher();
|
|
30
31
|
const chainSpec = getChainSpec(jamNodeConfig.node.flavor);
|
|
31
32
|
const { dbPath } = getDatabasePath(blake2b, jamNodeConfig.nodeName, jamNodeConfig.node.chainSpec.genesisHeader, withRelPath(jamNodeConfig.node.databaseBasePath));
|
|
32
|
-
const config =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
const config = jamNodeConfig.node.stateBackend === RegularStateBackend.Fjall
|
|
34
|
+
? FjallWorkerConfig.new({
|
|
35
|
+
nodeName: jamNodeConfig.nodeName,
|
|
36
|
+
chainSpec,
|
|
37
|
+
blake2b,
|
|
38
|
+
dbPath,
|
|
39
|
+
workerParams: undefined,
|
|
40
|
+
})
|
|
41
|
+
: LmdbWorkerConfig.new({
|
|
42
|
+
nodeName: jamNodeConfig.nodeName,
|
|
43
|
+
chainSpec,
|
|
44
|
+
blake2b,
|
|
45
|
+
dbPath,
|
|
46
|
+
workerParams: undefined,
|
|
47
|
+
});
|
|
48
|
+
const rootDb = await config.openDatabase();
|
|
40
49
|
const blocks = rootDb.getBlocksDb();
|
|
41
50
|
logger.info `📖 Gathering blocks...`;
|
|
42
51
|
const hashes = [];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type FjallValuesSession } from "#@typeberry/workers-api-node";
|
|
2
2
|
import type { JamConfig } from "./jam-config.js";
|
|
3
3
|
import type { NodeApi } from "./main.js";
|
|
4
|
-
export type StateBackend = "lmdb" | "lmdb-hybrid" | "fjall-hybrid";
|
|
4
|
+
export type StateBackend = "lmdb" | "fjall" | "lmdb-hybrid" | "fjall-hybrid";
|
|
5
5
|
export type ImporterOptions = {
|
|
6
6
|
initGenesisFromAncestry?: boolean;
|
|
7
7
|
dummyFinalityDepth?: number;
|
|
@@ -9,7 +9,9 @@ export type ImporterOptions = {
|
|
|
9
9
|
/** Open the database without fsync/compression. Only safe for throwaway dbs (e.g. fuzzing). */
|
|
10
10
|
ephemeral?: boolean;
|
|
11
11
|
/**
|
|
12
|
-
* Persistent backend used when `databaseBasePath` is set. Defaults to
|
|
12
|
+
* Persistent backend used when `databaseBasePath` is set. Defaults to config's backend (fjall unless overridden).
|
|
13
|
+
*
|
|
14
|
+
* lmdb and lmdb-hybrid are deprecated and retained as explicit fallbacks.
|
|
13
15
|
*/
|
|
14
16
|
stateBackend?: StateBackend;
|
|
15
17
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main-importer.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main-importer.ts"],"names":[],"mappings":"AASA,OAAO,EACL,KAAK,kBAAkB,
|
|
1
|
+
{"version":3,"file":"main-importer.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main-importer.ts"],"names":[],"mappings":"AASA,OAAO,EACL,KAAK,kBAAkB,EAKxB,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,aAAa,GAAG,cAAc,CAAC;AAE7E,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC,CAAC;AAEF,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAClC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,OAAO,CAAC,CAqHlB"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Bytes } from "#@typeberry/bytes";
|
|
2
2
|
import { PvmBackend } from "#@typeberry/config";
|
|
3
|
-
import { KnownChainSpec } from "#@typeberry/config-node";
|
|
3
|
+
import { KnownChainSpec, RegularStateBackend } from "#@typeberry/config-node";
|
|
4
4
|
import { bandersnatch, initWasm } from "#@typeberry/crypto";
|
|
5
5
|
import { Blake2b, HASH_SIZE } from "#@typeberry/hash";
|
|
6
6
|
import { createImporter, ImporterConfig } from "#@typeberry/importer";
|
|
7
7
|
import { tryAsU16 } from "#@typeberry/numbers";
|
|
8
8
|
import { CURRENT_SUITE, CURRENT_VERSION, Result, resultToString, version } from "#@typeberry/utils";
|
|
9
|
-
import { HybridWorkerConfig, InMemWorkerConfig, LmdbWorkerConfig, } from "#@typeberry/workers-api-node";
|
|
9
|
+
import { FjallWorkerConfig, HybridWorkerConfig, InMemWorkerConfig, LmdbWorkerConfig, } from "#@typeberry/workers-api-node";
|
|
10
10
|
import { getChainSpec, getDatabasePath, initializeDatabase, logger } from "./common.js";
|
|
11
11
|
const zeroHash = Bytes.zero(HASH_SIZE).asOpaque();
|
|
12
12
|
export async function mainImporter(config, withRelPath, options = {}) {
|
|
@@ -18,8 +18,13 @@ export async function mainImporter(config, withRelPath, options = {}) {
|
|
|
18
18
|
logger.info `🐇 Bandersnatch ${bandesnatchNative.isOk ? "native 🚀" : `using wasm: ${bandesnatchNative.error}`}`;
|
|
19
19
|
// Single source of truth for the states db backend: drives both the log line
|
|
20
20
|
// below and the worker config picked further down.
|
|
21
|
-
const dbBackend = config.node.databaseBasePath === undefined
|
|
21
|
+
const dbBackend = config.node.databaseBasePath === undefined
|
|
22
|
+
? "in-memory"
|
|
23
|
+
: (options.stateBackend ?? config.node.stateBackend ?? RegularStateBackend.Fjall);
|
|
22
24
|
logger.info `🗄️ States DB: ${dbBackend}.`;
|
|
25
|
+
if (dbBackend === "lmdb" || dbBackend === "lmdb-hybrid") {
|
|
26
|
+
logger.warn `🗄️ The ${dbBackend} state backend is deprecated. Use fjall unless you need a temporary fallback.`;
|
|
27
|
+
}
|
|
23
28
|
const chainSpec = getChainSpec(config.node.flavor);
|
|
24
29
|
const blake2b = await Blake2b.createHasher();
|
|
25
30
|
const nodeName = config.nodeName;
|
|
@@ -51,17 +56,26 @@ export async function mainImporter(config, withRelPath, options = {}) {
|
|
|
51
56
|
backend: dbBackend === "lmdb-hybrid" ? "lmdb" : "fjall",
|
|
52
57
|
sharedFjallSession: options.sharedFjallSession,
|
|
53
58
|
})
|
|
54
|
-
:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
: dbBackend === "fjall"
|
|
60
|
+
? FjallWorkerConfig.new({
|
|
61
|
+
nodeName,
|
|
62
|
+
chainSpec,
|
|
63
|
+
blake2b,
|
|
64
|
+
dbPath,
|
|
65
|
+
workerParams,
|
|
66
|
+
ephemeral,
|
|
67
|
+
})
|
|
68
|
+
: LmdbWorkerConfig.new({
|
|
69
|
+
nodeName,
|
|
70
|
+
chainSpec,
|
|
71
|
+
blake2b,
|
|
72
|
+
dbPath,
|
|
73
|
+
workerParams,
|
|
74
|
+
ephemeral,
|
|
75
|
+
});
|
|
62
76
|
// Initialize the database with genesis state and block if there isn't one.
|
|
63
77
|
logger.info `🛢️ Opening database at ${dbPath}`;
|
|
64
|
-
const rootDb = workerConfig.openDatabase({ readonly: false });
|
|
78
|
+
const rootDb = await workerConfig.openDatabase({ readonly: false });
|
|
65
79
|
await initializeDatabase(chainSpec, blake2b, genesisHeaderHash, rootDb, config.node.chainSpec, config.ancestry, {
|
|
66
80
|
initGenesisFromAncestry: options.initGenesisFromAncestry,
|
|
67
81
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAc,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEzF,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAc,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEzF,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,mBAAmB,CAAC;AAgB/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAkC,MAAM,EAAW,MAAM,kBAAkB,CAAC;AAYnF,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,iBAAiB,CAAC;AAWhE,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAChE,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;IACtE,oBAAoB,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,wBAAsB,IAAI,CACxB,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAClC,SAAS,EAAE,SAAS,GAAG,IAAI,GAC1B,OAAO,CAAC,OAAO,CAAC,CA2LlB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isMainThread } from "node:worker_threads";
|
|
2
2
|
import { AUTHORSHIP_NETWORK_PORT } from "#@typeberry/comms-authorship-network";
|
|
3
3
|
import { PvmBackend } from "#@typeberry/config";
|
|
4
|
+
import { RegularStateBackend } from "#@typeberry/config-node";
|
|
4
5
|
import { initWasm } from "#@typeberry/crypto";
|
|
5
6
|
import { deriveBandersnatchSecretKey, deriveEd25519SecretKey, trivialSeed, } from "#@typeberry/crypto/key-derivation.js";
|
|
6
7
|
import { Blake2b } from "#@typeberry/hash";
|
|
@@ -10,7 +11,7 @@ import { Listener } from "#@typeberry/listener";
|
|
|
10
11
|
import { tryAsU16, tryAsU32 } from "#@typeberry/numbers";
|
|
11
12
|
import { CURRENT_SUITE, CURRENT_VERSION, Result, version } from "#@typeberry/utils";
|
|
12
13
|
import { DirectPort, DirectWorkerConfig } from "#@typeberry/workers-api";
|
|
13
|
-
import { InMemWorkerConfig, LmdbWorkerConfig, logHostEnvironment, ThreadPort } from "#@typeberry/workers-api-node";
|
|
14
|
+
import { FjallWorkerConfig, InMemWorkerConfig, LmdbWorkerConfig, logHostEnvironment, ThreadPort, } from "#@typeberry/workers-api-node";
|
|
14
15
|
import { getChainSpec, getDatabasePath, initializeDatabase, logger } from "./common.js";
|
|
15
16
|
import { initializeExtensions } from "./extensions.js";
|
|
16
17
|
import * as metrics from "./metrics.js";
|
|
@@ -29,9 +30,12 @@ export async function main(config, withRelPath, telemetry) {
|
|
|
29
30
|
const blake2b = await Blake2b.createHasher();
|
|
30
31
|
const nodeName = config.nodeName;
|
|
31
32
|
const isInMemory = config.node.databaseBasePath === undefined;
|
|
32
|
-
logger.info `🗄️ States DB: ${isInMemory ? "in-memory" :
|
|
33
|
+
logger.info `🗄️ States DB: ${isInMemory ? "in-memory" : config.node.stateBackend}.`;
|
|
34
|
+
if (!isInMemory && config.node.stateBackend === RegularStateBackend.Lmdb) {
|
|
35
|
+
logger.warn `🗄️ The lmdb state backend is deprecated. Use state_backend="fjall" unless you need a temporary fallback.`;
|
|
36
|
+
}
|
|
33
37
|
const { dbPath, genesisHeaderHash } = getDatabasePath(blake2b, nodeName, config.node.chainSpec.genesisHeader, withRelPath(config.node.databaseBasePath ?? "<in-memory>"));
|
|
34
|
-
const baseConfig = { nodeName, chainSpec, blake2b, dbPath };
|
|
38
|
+
const baseConfig = { nodeName, chainSpec, blake2b, dbPath, stateBackend: config.node.stateBackend };
|
|
35
39
|
const importerParams = {
|
|
36
40
|
...baseConfig,
|
|
37
41
|
workerParams: ImporterConfig.create({
|
|
@@ -42,16 +46,29 @@ export async function main(config, withRelPath, telemetry) {
|
|
|
42
46
|
};
|
|
43
47
|
const importerConfig = isInMemory
|
|
44
48
|
? { isInMemory, config: InMemWorkerConfig.new(importerParams) }
|
|
45
|
-
: { isInMemory, config:
|
|
49
|
+
: { isInMemory, config: createPersistentWorkerConfig(importerParams) };
|
|
46
50
|
// Initialize the database with genesis state and block if there isn't one.
|
|
47
51
|
logger.info `🛢️ Opening database at ${dbPath}`;
|
|
48
|
-
const rootDb = importerConfig.config.openDatabase({ readonly: false });
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
const rootDb = await importerConfig.config.openDatabase({ readonly: false });
|
|
53
|
+
try {
|
|
54
|
+
await initializeDatabase(chainSpec, blake2b, genesisHeaderHash, rootDb, config.node.chainSpec, config.ancestry);
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
try {
|
|
58
|
+
await rootDb.close();
|
|
59
|
+
}
|
|
60
|
+
catch (closeError) {
|
|
61
|
+
logger.warn `Failed to close database after initialization error: ${closeError}`;
|
|
62
|
+
}
|
|
63
|
+
throw e;
|
|
64
|
+
}
|
|
65
|
+
// fjall-js shares the engine explicitly and requires every handle to close.
|
|
66
|
+
// Keep lmdb's historical main-thread handle open until shutdown.
|
|
67
|
+
let mainRootDb = rootDb;
|
|
68
|
+
if (!importerConfig.isInMemory && config.node.stateBackend === RegularStateBackend.Fjall) {
|
|
69
|
+
await rootDb.close();
|
|
70
|
+
mainRootDb = null;
|
|
71
|
+
}
|
|
55
72
|
// Start block importer
|
|
56
73
|
let importer;
|
|
57
74
|
let closeImporter;
|
|
@@ -138,8 +155,10 @@ export async function main(config, withRelPath, telemetry) {
|
|
|
138
155
|
await closeImporter();
|
|
139
156
|
logger.log `[main] ☠️ Closing the extensions`;
|
|
140
157
|
closeExtensions();
|
|
141
|
-
|
|
142
|
-
|
|
158
|
+
if (mainRootDb !== null) {
|
|
159
|
+
logger.log `[main] 🛢️ Closing the database`;
|
|
160
|
+
await mainRootDb.close();
|
|
161
|
+
}
|
|
143
162
|
logger.log `[main] 📳 Closing telemetry`;
|
|
144
163
|
await telemetry?.close();
|
|
145
164
|
logger.info `[main] ✅ Done.`;
|
|
@@ -167,7 +186,7 @@ const initAuthorship = async (importer, isAuthoring, isFastForward, params, base
|
|
|
167
186
|
statesDb: params.rootDb.getStatesDb(),
|
|
168
187
|
workerParams,
|
|
169
188
|
}), params.networkingPort)
|
|
170
|
-
: await spawnBlockGeneratorWorker(
|
|
189
|
+
: await spawnBlockGeneratorWorker(createPersistentWorkerConfig({
|
|
171
190
|
...baseConfig,
|
|
172
191
|
workerParams,
|
|
173
192
|
ports: new Map([[AUTHORSHIP_NETWORK_PORT, params.networkingPort]]),
|
|
@@ -205,7 +224,7 @@ const initNetwork = async (importer, params, baseConfig, genesisHeaderHash, netw
|
|
|
205
224
|
statesDb: params.rootDb.getStatesDb(),
|
|
206
225
|
workerParams: networkingConfig,
|
|
207
226
|
}), params.authorshipPort)
|
|
208
|
-
: await spawnNetworkWorker(
|
|
227
|
+
: await spawnNetworkWorker(createPersistentWorkerConfig({
|
|
209
228
|
...baseConfig,
|
|
210
229
|
workerParams: networkingConfig,
|
|
211
230
|
ports: new Map([[AUTHORSHIP_NETWORK_PORT, params.authorshipPort]]),
|
|
@@ -222,3 +241,11 @@ const initNetwork = async (importer, params, baseConfig, genesisHeaderHash, netw
|
|
|
222
241
|
});
|
|
223
242
|
return { closeNetwork: finish, networkApi: network, networkWorker: worker };
|
|
224
243
|
};
|
|
244
|
+
function createPersistentWorkerConfig({ stateBackend, ...params }) {
|
|
245
|
+
switch (stateBackend) {
|
|
246
|
+
case RegularStateBackend.Fjall:
|
|
247
|
+
return FjallWorkerConfig.new(params);
|
|
248
|
+
case RegularStateBackend.Lmdb:
|
|
249
|
+
return LmdbWorkerConfig.new(params);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
@@ -5,8 +5,8 @@ import * as importer from "#@typeberry/importer";
|
|
|
5
5
|
import * as jamNetwork from "#@typeberry/jam-network";
|
|
6
6
|
import type { SerializedState } from "#@typeberry/state-merkleization";
|
|
7
7
|
import { type DirectPort, type DirectWorkerConfig } from "#@typeberry/workers-api";
|
|
8
|
-
import { type
|
|
9
|
-
export declare function spawnImporterWorker(config:
|
|
8
|
+
import { type PersistentWorkerConfig } from "#@typeberry/workers-api-node";
|
|
9
|
+
export declare function spawnImporterWorker(config: PersistentWorkerConfig<importer.ImporterConfig>): Promise<{
|
|
10
10
|
importer: import("@typeberry/workers-api").Tx<{
|
|
11
11
|
getStateEntries: {
|
|
12
12
|
request: import("@typeberry/codec").Descriptor<import("@typeberry/bytes").Bytes<32> & import("@typeberry/utils").WithOpaque<"HeaderHash">, import("@typeberry/bytes").Bytes<32>>;
|
|
@@ -376,7 +376,7 @@ export declare function spawnImporterWorker(config: LmdbWorkerConfig<importer.Im
|
|
|
376
376
|
finish: () => Promise<void>;
|
|
377
377
|
}>;
|
|
378
378
|
export declare function startImporterDirect(config: DirectWorkerConfig<importer.ImporterConfig, BlocksDb, StatesDb<SerializedState<LeafDb>>>): ReturnType<typeof spawnImporterWorker>;
|
|
379
|
-
export declare function spawnNetworkWorker(config:
|
|
379
|
+
export declare function spawnNetworkWorker(config: PersistentWorkerConfig<jamNetwork.NetworkingConfig>): Promise<{
|
|
380
380
|
network: import("@typeberry/workers-api").Tx<{
|
|
381
381
|
newHeader: {
|
|
382
382
|
request: import("@typeberry/codec").Descriptor<import("@typeberry/hash").WithHash<import("@typeberry/hash").OpaqueHash & import("@typeberry/utils").WithOpaque<"HeaderHash">, import("@typeberry/codec").ViewOf<import("@typeberry/block").Header & import("@typeberry/codec").CodecRecord<import("@typeberry/block").Header>, {
|
|
@@ -865,7 +865,7 @@ export declare function spawnNetworkWorker(config: LmdbWorkerConfig<jamNetwork.N
|
|
|
865
865
|
export declare function startNetwork(config: DirectWorkerConfig<jamNetwork.NetworkingConfig>, authorshipPort: DirectPort): Promise<Omit<Awaited<ReturnType<typeof spawnNetworkWorker>>, "worker"> & {
|
|
866
866
|
worker: Worker | null;
|
|
867
867
|
}>;
|
|
868
|
-
export declare function spawnBlockGeneratorWorker(config:
|
|
868
|
+
export declare function spawnBlockGeneratorWorker(config: PersistentWorkerConfig<blockAuthorship.BlockAuthorshipConfig>): Promise<{
|
|
869
869
|
generator: import("@typeberry/workers-api").Tx<{
|
|
870
870
|
finish: {
|
|
871
871
|
request: import("@typeberry/codec").Descriptor<void, void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workers.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/workers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,eAAe,MAAM,6BAA6B,CAAC;AAE/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAW,KAAK,UAAU,EAAE,KAAK,kBAAkB,EAAmB,MAAM,wBAAwB,CAAC;AAC5G,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"workers.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/workers.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;
|
|
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"}
|
|
@@ -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
|
|
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;
|
|
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
|
-
|
|
9
|
+
inbound;
|
|
10
|
+
outbound;
|
|
10
11
|
threadId = 0;
|
|
11
12
|
/** Create a pair of symmetrical inter-connected ports. */
|
|
12
13
|
static pair() {
|
|
13
|
-
const
|
|
14
|
-
|
|
14
|
+
const left = createPortState();
|
|
15
|
+
const right = createPortState();
|
|
16
|
+
return [new DirectPort(left, right), new DirectPort(right, left)];
|
|
15
17
|
}
|
|
16
|
-
constructor(
|
|
17
|
-
this.
|
|
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.
|
|
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.
|
|
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.
|
|
47
|
-
this.
|
|
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
|
});
|
|
@@ -7,7 +7,15 @@ import { Blake2b } from "#@typeberry/hash";
|
|
|
7
7
|
import type { WorkerConfig } from "#@typeberry/workers-api";
|
|
8
8
|
import { ThreadPort, type TransferablePort } from "./port.js";
|
|
9
9
|
export { FjallValuesSession };
|
|
10
|
-
/**
|
|
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
|
+
*/
|
|
11
19
|
export declare class LmdbWorkerConfig<T = void> implements WorkerConfig<T, BlocksDb, SerializedStatesDb> {
|
|
12
20
|
readonly nodeName: string;
|
|
13
21
|
readonly chainSpec: ChainSpec;
|
|
@@ -30,18 +38,51 @@ export declare class LmdbWorkerConfig<T = void> implements WorkerConfig<T, Block
|
|
|
30
38
|
private constructor();
|
|
31
39
|
openDatabase(options?: {
|
|
32
40
|
readonly: boolean;
|
|
33
|
-
}): 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>>;
|
|
34
71
|
/** Convert this config into a thread-transferable object. */
|
|
35
72
|
intoTransferable(paramsCodec: Encode<T>): TransferableConfig;
|
|
36
73
|
}
|
|
37
74
|
/** Config that's safe to transfer between worker threads. */
|
|
38
75
|
export type TransferableConfig = {
|
|
76
|
+
databaseBackend: PersistentBackend;
|
|
39
77
|
nodeName: string;
|
|
40
78
|
chainSpec: ChainSpec;
|
|
41
79
|
workerParams: Uint8Array;
|
|
42
80
|
dbPath: string;
|
|
43
81
|
workerPorts: [string, TransferablePort][];
|
|
82
|
+
cacheSizeBytes?: number;
|
|
44
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>>;
|
|
45
86
|
/**
|
|
46
87
|
* Collect the transferable objects (communication ports) embedded in a config.
|
|
47
88
|
*
|
|
@@ -71,7 +112,7 @@ export declare class InMemWorkerConfig<T = undefined> implements WorkerConfig<T,
|
|
|
71
112
|
private constructor();
|
|
72
113
|
openDatabase(_options?: {
|
|
73
114
|
readonly: boolean;
|
|
74
|
-
}): RootDb<BlocksDb, SerializedStatesDb
|
|
115
|
+
}): Promise<RootDb<BlocksDb, SerializedStatesDb>>;
|
|
75
116
|
}
|
|
76
117
|
/** Persistent values store backing the hybrid config. */
|
|
77
118
|
export type HybridBackend = "lmdb" | "fjall";
|
|
@@ -121,6 +162,6 @@ export declare class HybridWorkerConfig<T = undefined> implements WorkerConfig<T
|
|
|
121
162
|
private constructor();
|
|
122
163
|
openDatabase(_options?: {
|
|
123
164
|
readonly: boolean;
|
|
124
|
-
}): RootDb<BlocksDb, SerializedStatesDb
|
|
165
|
+
}): Promise<RootDb<BlocksDb, SerializedStatesDb>>;
|
|
125
166
|
}
|
|
126
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":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,KAAK,MAAM,EAAW,KAAK,MAAM,EAAW,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EACL,KAAK,QAAQ,EAGb,KAAK,MAAM,EACX,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api-node/config.ts"],"names":[],"mappings":"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"}
|