@typeberry/lib 0.7.4 → 0.7.5-a88be22
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.js +1 -1
- package/packages/jam/database-lmdb/hybrid-states.d.ts +42 -0
- package/packages/jam/database-lmdb/hybrid-states.d.ts.map +1 -0
- package/packages/jam/database-lmdb/hybrid-states.js +105 -0
- package/packages/jam/database-lmdb/hybrid-states.test.d.ts +2 -0
- package/packages/jam/database-lmdb/hybrid-states.test.d.ts.map +1 -0
- package/packages/jam/database-lmdb/hybrid-states.test.js +88 -0
- package/packages/jam/database-lmdb/index.d.ts +1 -0
- package/packages/jam/database-lmdb/index.d.ts.map +1 -1
- package/packages/jam/database-lmdb/index.js +1 -0
- package/packages/jam/database-lmdb/root.d.ts.map +1 -1
- package/packages/jam/database-lmdb/root.js +4 -0
- package/packages/jam/node/main-fuzz.d.ts.map +1 -1
- package/packages/jam/node/main-fuzz.js +6 -5
- package/packages/jam/node/main-importer.d.ts +2 -0
- package/packages/jam/node/main-importer.d.ts.map +1 -1
- package/packages/jam/node/main-importer.js +23 -10
- package/packages/jam/node/main.d.ts.map +1 -1
- package/packages/jam/node/main.js +1 -0
- package/packages/workers/api-node/config.d.ts +35 -0
- package/packages/workers/api-node/config.d.ts.map +1 -1
- package/packages/workers/api-node/config.js +52 -1
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@ export const DEFAULT_CONFIG = "default";
|
|
|
15
15
|
export const NODE_DEFAULTS = {
|
|
16
16
|
name: isBrowser() ? "browser" : os.hostname(),
|
|
17
17
|
config: [DEFAULT_CONFIG],
|
|
18
|
-
pvm: PvmBackend.
|
|
18
|
+
pvm: PvmBackend.Ananas,
|
|
19
19
|
};
|
|
20
20
|
/** Chain spec chooser. */
|
|
21
21
|
export var KnownChainSpec;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { HeaderHash, StateRootHash } from "#@typeberry/block";
|
|
2
|
+
import type { ChainSpec } from "#@typeberry/config";
|
|
3
|
+
import { type InitStatesDb, LeafDb, type StatesDb, StateUpdateError } from "#@typeberry/database";
|
|
4
|
+
import type { Blake2b } from "#@typeberry/hash";
|
|
5
|
+
import type { ServicesUpdate, State } from "#@typeberry/state";
|
|
6
|
+
import { SerializedState, type StateEntries } from "#@typeberry/state-merkleization";
|
|
7
|
+
import { OK, Result } from "#@typeberry/utils";
|
|
8
|
+
/**
|
|
9
|
+
* Hybrid serialized-states db.
|
|
10
|
+
*
|
|
11
|
+
* States (leafs) are kept in-memory, but large values are persisted to lmdb.
|
|
12
|
+
* Reads go straight to lmdb, which keeps its own page cache.
|
|
13
|
+
* NOTE: this DB is designed for long fuzzing and to be used with pruning to
|
|
14
|
+
* keep the heap usage bounded.
|
|
15
|
+
*/
|
|
16
|
+
export declare class HybridSerializedStates implements StatesDb<SerializedState<LeafDb>>, InitStatesDb<StateEntries> {
|
|
17
|
+
private readonly spec;
|
|
18
|
+
private readonly blake2b;
|
|
19
|
+
private readonly root;
|
|
20
|
+
private readonly inMemStates;
|
|
21
|
+
private readonly lmdbValues;
|
|
22
|
+
private readonly valuesDb;
|
|
23
|
+
static new({ spec, blake2b, dbPath, readOnly, ephemeral, }: {
|
|
24
|
+
spec: ChainSpec;
|
|
25
|
+
blake2b: Blake2b;
|
|
26
|
+
dbPath: string;
|
|
27
|
+
readOnly?: boolean;
|
|
28
|
+
ephemeral?: boolean;
|
|
29
|
+
}): HybridSerializedStates;
|
|
30
|
+
private constructor();
|
|
31
|
+
insertInitialState(headerHash: HeaderHash, entries: StateEntries): Promise<Result<OK, StateUpdateError>>;
|
|
32
|
+
updateAndSetState(header: HeaderHash, state: SerializedState<LeafDb>, update: Partial<State & ServicesUpdate>): Promise<Result<OK, StateUpdateError>>;
|
|
33
|
+
getStateRoot(state: SerializedState<LeafDb>): Promise<StateRootHash>;
|
|
34
|
+
getState(header: HeaderHash): SerializedState<LeafDb> | null;
|
|
35
|
+
markUnused(header: HeaderHash): void;
|
|
36
|
+
close(): Promise<void>;
|
|
37
|
+
/** Write new large values to LMDB in one transaction. */
|
|
38
|
+
private writeValues;
|
|
39
|
+
/** Read a value from LMDB. */
|
|
40
|
+
private readValue;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=hybrid-states.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hybrid-states.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/database-lmdb/hybrid-states.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGlE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,KAAK,YAAY,EACjB,MAAM,EACN,KAAK,QAAQ,EACb,gBAAgB,EAGjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EACL,eAAe,EACf,KAAK,YAAY,EAGlB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG9C;;;;;;;GAOG;AACH,qBAAa,sBAAuB,YAAW,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,YAAY,CAAC;IAwBxG,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAzBvB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyE;IACrG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IAEnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IAEpC,MAAM,CAAC,GAAG,CAAC,EACT,IAAI,EACJ,OAAO,EACP,MAAM,EACN,QAAQ,EACR,SAAS,GACV,EAAE;QACD,IAAI,EAAE,SAAS,CAAC;QAChB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB;IAKD,OAAO;IASD,kBAAkB,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;IAcxG,iBAAiB,CACrB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,eAAe,CAAC,MAAM,CAAC,EAC9B,MAAM,EAAE,OAAO,CAAC,KAAK,GAAG,cAAc,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;IAkBlC,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC;IAI1E,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,GAAG,IAAI;IAS5D,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAM9B,KAAK;IAKX,yDAAyD;YAC3C,WAAW;IAgBzB,8BAA8B;IAC9B,OAAO,CAAC,SAAS;CAOlB"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { HashDictionary, SortedSet } from "#@typeberry/collections";
|
|
2
|
+
import { LeafDb, StateUpdateError, updateLeafs, } from "#@typeberry/database";
|
|
3
|
+
import { SerializedState, StateEntryUpdateAction, serializeStateUpdate, } from "#@typeberry/state-merkleization";
|
|
4
|
+
import { leafComparator } from "#@typeberry/trie";
|
|
5
|
+
import { OK, Result } from "#@typeberry/utils";
|
|
6
|
+
import { LmdbRoot } from "./root.js";
|
|
7
|
+
/**
|
|
8
|
+
* Hybrid serialized-states db.
|
|
9
|
+
*
|
|
10
|
+
* States (leafs) are kept in-memory, but large values are persisted to lmdb.
|
|
11
|
+
* Reads go straight to lmdb, which keeps its own page cache.
|
|
12
|
+
* NOTE: this DB is designed for long fuzzing and to be used with pruning to
|
|
13
|
+
* keep the heap usage bounded.
|
|
14
|
+
*/
|
|
15
|
+
export class HybridSerializedStates {
|
|
16
|
+
spec;
|
|
17
|
+
blake2b;
|
|
18
|
+
root;
|
|
19
|
+
inMemStates = HashDictionary.new();
|
|
20
|
+
lmdbValues;
|
|
21
|
+
// A single shared values accessor reused by every `LeafDb` we hand out.
|
|
22
|
+
valuesDb;
|
|
23
|
+
static new({ spec, blake2b, dbPath, readOnly, ephemeral, }) {
|
|
24
|
+
const root = LmdbRoot.new(dbPath, readOnly, ephemeral);
|
|
25
|
+
return new HybridSerializedStates(spec, blake2b, root);
|
|
26
|
+
}
|
|
27
|
+
constructor(spec, blake2b, root) {
|
|
28
|
+
this.spec = spec;
|
|
29
|
+
this.blake2b = blake2b;
|
|
30
|
+
this.root = root;
|
|
31
|
+
this.lmdbValues = this.root.subDb("values");
|
|
32
|
+
this.valuesDb = { get: (key) => this.readValue(key) };
|
|
33
|
+
}
|
|
34
|
+
async insertInitialState(headerHash, entries) {
|
|
35
|
+
const { values, leafs } = updateLeafs(SortedSet.fromArray(leafComparator, []), this.blake2b, Array.from(entries, (x) => [StateEntryUpdateAction.Insert, x[0], x[1]]));
|
|
36
|
+
const res = await this.writeValues(values);
|
|
37
|
+
if (res.isError) {
|
|
38
|
+
return res;
|
|
39
|
+
}
|
|
40
|
+
this.inMemStates.set(headerHash, leafs);
|
|
41
|
+
return Result.ok(OK);
|
|
42
|
+
}
|
|
43
|
+
async updateAndSetState(header, state, update) {
|
|
44
|
+
const updatedValues = serializeStateUpdate(this.spec, this.blake2b, update);
|
|
45
|
+
// Clone the leaf set before mutating: the previous state keeps using its own.
|
|
46
|
+
const newLeafs = SortedSet.fromSortedArray(leafComparator, state.backend.leafs.array);
|
|
47
|
+
const { values, leafs } = updateLeafs(newLeafs, this.blake2b, updatedValues);
|
|
48
|
+
const res = await this.writeValues(values);
|
|
49
|
+
if (res.isError) {
|
|
50
|
+
// Leave the caller's state untouched: its new leaves would reference
|
|
51
|
+
// values that never reached disk.
|
|
52
|
+
return res;
|
|
53
|
+
}
|
|
54
|
+
// Re-create the lookup with the shared values accessor only once the new
|
|
55
|
+
// values are durably written.
|
|
56
|
+
state.updateBackend(LeafDb.fromLeaves(leafs, this.valuesDb));
|
|
57
|
+
this.inMemStates.set(header, leafs);
|
|
58
|
+
return Result.ok(OK);
|
|
59
|
+
}
|
|
60
|
+
async getStateRoot(state) {
|
|
61
|
+
return state.backend.getStateRoot(this.blake2b);
|
|
62
|
+
}
|
|
63
|
+
getState(header) {
|
|
64
|
+
const leafs = this.inMemStates.get(header);
|
|
65
|
+
if (leafs === undefined) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const leafDb = LeafDb.fromLeaves(leafs, this.valuesDb);
|
|
69
|
+
return SerializedState.new(this.spec, this.blake2b, leafDb);
|
|
70
|
+
}
|
|
71
|
+
markUnused(header) {
|
|
72
|
+
// We only remove the state from memory - values are not pruned at all,
|
|
73
|
+
// but since they are stored on disk we should be safe.
|
|
74
|
+
this.inMemStates.delete(header);
|
|
75
|
+
}
|
|
76
|
+
async close() {
|
|
77
|
+
await this.lmdbValues.close();
|
|
78
|
+
await this.root.close();
|
|
79
|
+
}
|
|
80
|
+
/** Write new large values to LMDB in one transaction. */
|
|
81
|
+
async writeValues(values) {
|
|
82
|
+
if (values.length === 0) {
|
|
83
|
+
return Result.ok(OK);
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
await this.lmdbValues.transaction(() => {
|
|
87
|
+
for (const [hash, val] of values) {
|
|
88
|
+
this.lmdbValues.put(hash.raw, val.raw);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
return Result.error(StateUpdateError.Commit, () => `Failed to commit values: ${e}`);
|
|
94
|
+
}
|
|
95
|
+
return Result.ok(OK);
|
|
96
|
+
}
|
|
97
|
+
/** Read a value from LMDB. */
|
|
98
|
+
readValue(key) {
|
|
99
|
+
const val = this.lmdbValues.get(key.raw);
|
|
100
|
+
if (val === undefined) {
|
|
101
|
+
throw new Error(`Missing value at key: ${key}`);
|
|
102
|
+
}
|
|
103
|
+
return val;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hybrid-states.test.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/database-lmdb/hybrid-states.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// packages/jam/database-lmdb/hybrid-states.test.ts
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import { afterEach, before, beforeEach, describe, it } from "node:test";
|
|
5
|
+
import { Bytes, BytesBlob } from "#@typeberry/bytes";
|
|
6
|
+
import { tinyChainSpec } from "#@typeberry/config";
|
|
7
|
+
import { Blake2b, HASH_SIZE } from "#@typeberry/hash";
|
|
8
|
+
import { InMemoryState } from "#@typeberry/state";
|
|
9
|
+
import { StateEntries } from "#@typeberry/state-merkleization";
|
|
10
|
+
import { deepEqual, OK, Result } from "#@typeberry/utils";
|
|
11
|
+
import { HybridSerializedStates } from "./hybrid-states.js";
|
|
12
|
+
let blake2b;
|
|
13
|
+
before(async () => {
|
|
14
|
+
blake2b = await Blake2b.createHasher();
|
|
15
|
+
});
|
|
16
|
+
function createTempDir(suffix = "hybrid") {
|
|
17
|
+
return fs.mkdtempSync(`typeberry-${suffix}`);
|
|
18
|
+
}
|
|
19
|
+
describe("Hybrid serialized states", () => {
|
|
20
|
+
const spec = tinyChainSpec;
|
|
21
|
+
const headerHash = Bytes.zero(HASH_SIZE).asOpaque();
|
|
22
|
+
let dbPath = "";
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
dbPath = createTempDir();
|
|
25
|
+
});
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
fs.rmSync(dbPath, { recursive: true });
|
|
28
|
+
});
|
|
29
|
+
it("round-trips an initial state through the on-disk values store", async () => {
|
|
30
|
+
const states = HybridSerializedStates.new({
|
|
31
|
+
spec,
|
|
32
|
+
blake2b,
|
|
33
|
+
dbPath,
|
|
34
|
+
});
|
|
35
|
+
try {
|
|
36
|
+
const empty = InMemoryState.empty(spec);
|
|
37
|
+
const serialized = StateEntries.serializeInMemory(spec, blake2b, empty);
|
|
38
|
+
const expectedRoot = serialized.getRootHash(blake2b);
|
|
39
|
+
const res = await states.insertInitialState(headerHash, serialized);
|
|
40
|
+
deepEqual(res, Result.ok(OK));
|
|
41
|
+
const state = states.getState(headerHash);
|
|
42
|
+
assert.ok(state !== null);
|
|
43
|
+
const stateRoot = await states.getStateRoot(state);
|
|
44
|
+
assert.strictEqual(`${stateRoot}`, `${expectedRoot}`);
|
|
45
|
+
deepEqual(InMemoryState.copyFrom(spec, state, new Map()), empty);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
await states.close();
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
it("reads large values back from disk", async () => {
|
|
52
|
+
const states = HybridSerializedStates.new({ spec, blake2b, dbPath });
|
|
53
|
+
try {
|
|
54
|
+
// > 32 bytes => stored in the values db (not embedded in the leaf).
|
|
55
|
+
const big1 = BytesBlob.blobFromString("x".repeat(100));
|
|
56
|
+
const big2 = BytesBlob.blobFromString("y".repeat(100));
|
|
57
|
+
const key1 = Bytes.fill(HASH_SIZE, 1).asOpaque();
|
|
58
|
+
const key2 = Bytes.fill(HASH_SIZE, 2).asOpaque();
|
|
59
|
+
const entries = StateEntries.fromEntriesUnsafe([
|
|
60
|
+
[key1, big1],
|
|
61
|
+
[key2, big2],
|
|
62
|
+
]);
|
|
63
|
+
const res = await states.insertInitialState(headerHash, entries);
|
|
64
|
+
deepEqual(res, Result.ok(OK));
|
|
65
|
+
const state = states.getState(headerHash);
|
|
66
|
+
assert.ok(state !== null);
|
|
67
|
+
assert.strictEqual(`${state.backend.get(key2)}`, `${big2}`);
|
|
68
|
+
assert.strictEqual(`${state.backend.get(key1)}`, `${big1}`);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
await states.close();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
it("drops the leaf set on markUnused while values stay on disk", async () => {
|
|
75
|
+
const states = HybridSerializedStates.new({ spec, blake2b, dbPath });
|
|
76
|
+
try {
|
|
77
|
+
const empty = InMemoryState.empty(spec);
|
|
78
|
+
const serialized = StateEntries.serializeInMemory(spec, blake2b, empty);
|
|
79
|
+
await states.insertInitialState(headerHash, serialized);
|
|
80
|
+
assert.ok(states.getState(headerHash) !== null);
|
|
81
|
+
states.markUnused(headerHash);
|
|
82
|
+
assert.strictEqual(states.getState(headerHash), null);
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
await states.close();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/database-lmdb/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/database-lmdb/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/database-lmdb/root.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,MAAM,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;AAExD,uDAAuD;AACvD,qBAAa,QAAQ;IACnB,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAErD,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,UAAQ,EAAE,SAAS,UAAQ;IAI9D,OAAO;
|
|
1
|
+
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/database-lmdb/root.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,MAAM,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;AAExD,uDAAuD;AACvD,qBAAa,QAAQ;IACnB,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAErD,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,UAAQ,EAAE,SAAS,UAAQ;IAI9D,OAAO;IAkBP,+CAA+C;IAC/C,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;IAI1B,gDAAgD;IAC1C,KAAK;CAGZ"}
|
|
@@ -7,6 +7,10 @@ export class LmdbRoot {
|
|
|
7
7
|
}
|
|
8
8
|
constructor(dbPath, readOnly = false, ephemeral = false) {
|
|
9
9
|
this.db = lmdb.open(dbPath, {
|
|
10
|
+
// experimental options
|
|
11
|
+
mapSize: 256 * 1024 * 1024 * 1024, // 256G max db size
|
|
12
|
+
useWritemap: ephemeral,
|
|
13
|
+
pageSize: 8192,
|
|
10
14
|
// For ephemeral databases (e.g. the fuzz target, which wipes on every reset)
|
|
11
15
|
// durability is pointless, so we skip fsync and skip compressing the large
|
|
12
16
|
// per-block leaf blobs. Both are pure overhead there and dominate the cost.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main-fuzz.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main-fuzz.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,WAAW,EAAmB,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAOrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,aAAa,EAAE,SAAS,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,uBAAuB,EAAE,OAAO,CAAC;CAClC,CAAC;AAOF;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CASpF;AAED,iFAAiF;AACjF,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5D;AAED,wBAAgB,cAAc;;;;EAM7B;AAED,wBAAsB,QAAQ,CAAC,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,
|
|
1
|
+
{"version":3,"file":"main-fuzz.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main-fuzz.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,WAAW,EAAmB,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAOrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,aAAa,EAAE,SAAS,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,uBAAuB,EAAE,OAAO,CAAC;CAClC,CAAC;AAOF;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CASpF;AAED,iFAAiF;AACjF,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5D;AAED,wBAAgB,cAAc;;;;EAM7B;AAED,wBAAsB,QAAQ,CAAC,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,uBAyGxF"}
|
|
@@ -81,8 +81,6 @@ export async function mainFuzz(fuzzConfig, withRelPath) {
|
|
|
81
81
|
await finish;
|
|
82
82
|
}
|
|
83
83
|
const buildNode = (databaseBasePath) => {
|
|
84
|
-
// Enable state/blocks pruning only when running in memory.
|
|
85
|
-
// For disk backend, we store everything.
|
|
86
84
|
const isPersistent = databaseBasePath !== undefined;
|
|
87
85
|
return mainImporter({
|
|
88
86
|
...config,
|
|
@@ -99,11 +97,14 @@ export async function mainFuzz(fuzzConfig, withRelPath) {
|
|
|
99
97
|
network: null,
|
|
100
98
|
}, withRelPath, {
|
|
101
99
|
initGenesisFromAncestry: fuzzConfig.initGenesisFromAncestry,
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
// Hybrid keeps leaf sets in RAM, so they must be windowed exactly
|
|
101
|
+
// like the in-memory backend; only the large values live on disk.
|
|
102
|
+
dummyFinalityDepth: 100,
|
|
103
|
+
pruneBlocks: true,
|
|
104
104
|
// The fuzz db is wiped on every reset, so durability is pointless:
|
|
105
|
-
// skip fsync + compression to cut the per-block
|
|
105
|
+
// skip fsync + compression to cut the per-block value write cost.
|
|
106
106
|
ephemeralDb: isPersistent,
|
|
107
|
+
stateBackend: isPersistent ? "hybrid" : "lmdb",
|
|
107
108
|
});
|
|
108
109
|
};
|
|
109
110
|
if (fuzzDbBase !== undefined) {
|
|
@@ -6,6 +6,8 @@ export type ImporterOptions = {
|
|
|
6
6
|
pruneBlocks?: boolean;
|
|
7
7
|
/** Open the LMDB database without fsync/compression. Only safe for throwaway dbs (e.g. fuzzing). */
|
|
8
8
|
ephemeralDb?: boolean;
|
|
9
|
+
/** Persistent backend to use when `databaseBasePath` is set. Defaults to full LMDB. */
|
|
10
|
+
stateBackend?: "lmdb" | "hybrid";
|
|
9
11
|
};
|
|
10
12
|
export declare function mainImporter(config: JamConfig, withRelPath: (v: string) => string, options?: ImporterOptions): Promise<NodeApi>;
|
|
11
13
|
//# sourceMappingURL=main-importer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main-importer.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main-importer.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oGAAoG;IACpG,WAAW,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"main-importer.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main-importer.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oGAAoG;IACpG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;CAClC,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,CA+FlB"}
|
|
@@ -5,7 +5,7 @@ import { Blake2b, HASH_SIZE } from "#@typeberry/hash";
|
|
|
5
5
|
import { createImporter, ImporterConfig } from "#@typeberry/importer";
|
|
6
6
|
import { tryAsU16 } from "#@typeberry/numbers";
|
|
7
7
|
import { CURRENT_SUITE, CURRENT_VERSION, Result, resultToString, version } from "#@typeberry/utils";
|
|
8
|
-
import { InMemWorkerConfig, LmdbWorkerConfig } from "#@typeberry/workers-api-node";
|
|
8
|
+
import { HybridWorkerConfig, InMemWorkerConfig, LmdbWorkerConfig } from "#@typeberry/workers-api-node";
|
|
9
9
|
import { getChainSpec, getDatabasePath, initializeDatabase, logger } from "./common.js";
|
|
10
10
|
const zeroHash = Bytes.zero(HASH_SIZE).asOpaque();
|
|
11
11
|
export async function mainImporter(config, withRelPath, options = {}) {
|
|
@@ -15,6 +15,10 @@ export async function mainImporter(config, withRelPath, options = {}) {
|
|
|
15
15
|
logger.info `🎸 Starting importer: ${config.nodeName}.`;
|
|
16
16
|
logger.info `🖥️ PVM Backend: ${PvmBackend[config.pvmBackend]}.`;
|
|
17
17
|
logger.info `🐇 Bandersnatch ${bandesnatchNative.isOk ? "native 🚀" : `using wasm: ${bandesnatchNative.error}`}`;
|
|
18
|
+
// Single source of truth for the states db backend: drives both the log line
|
|
19
|
+
// below and the worker config picked further down.
|
|
20
|
+
const dbBackend = config.node.databaseBasePath === undefined ? "in-memory" : (options.stateBackend ?? "lmdb");
|
|
21
|
+
logger.info `🗄️ States DB: ${dbBackend}.`;
|
|
18
22
|
const chainSpec = getChainSpec(config.node.flavor);
|
|
19
23
|
const blake2b = await Blake2b.createHasher();
|
|
20
24
|
const nodeName = config.nodeName;
|
|
@@ -24,21 +28,30 @@ export async function mainImporter(config, withRelPath, options = {}) {
|
|
|
24
28
|
dummyFinalityDepth: tryAsU16(options.dummyFinalityDepth ?? 0),
|
|
25
29
|
pruneBlocks: options.pruneBlocks ?? false,
|
|
26
30
|
});
|
|
27
|
-
const workerConfig =
|
|
31
|
+
const workerConfig = dbBackend === "in-memory"
|
|
28
32
|
? InMemWorkerConfig.new({
|
|
29
33
|
nodeName,
|
|
30
34
|
chainSpec,
|
|
31
35
|
blake2b,
|
|
32
36
|
workerParams,
|
|
33
37
|
})
|
|
34
|
-
:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
: dbBackend === "hybrid"
|
|
39
|
+
? HybridWorkerConfig.new({
|
|
40
|
+
nodeName,
|
|
41
|
+
chainSpec,
|
|
42
|
+
blake2b,
|
|
43
|
+
dbPath,
|
|
44
|
+
workerParams,
|
|
45
|
+
ephemeral: options.ephemeralDb ?? false,
|
|
46
|
+
})
|
|
47
|
+
: LmdbWorkerConfig.new({
|
|
48
|
+
nodeName,
|
|
49
|
+
chainSpec,
|
|
50
|
+
blake2b,
|
|
51
|
+
dbPath,
|
|
52
|
+
workerParams,
|
|
53
|
+
ephemeral: options.ephemeralDb ?? false,
|
|
54
|
+
});
|
|
42
55
|
// Initialize the database with genesis state and block if there isn't one.
|
|
43
56
|
logger.info `🛢️ Opening database at ${dbPath}`;
|
|
44
57
|
const rootDb = workerConfig.openDatabase({ readonly: false });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAc,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEzF,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,mBAAmB,CAAC;AAe/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAkC,MAAM,EAAW,MAAM,kBAAkB,CAAC;AAKnF,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,iBAAiB,CAAC;AAWhE,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAChE,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;IACtE,oBAAoB,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,wBAAsB,IAAI,CACxB,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAClC,SAAS,EAAE,SAAS,GAAG,IAAI,GAC1B,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/node/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAc,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEzF,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,mBAAmB,CAAC;AAe/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAkC,MAAM,EAAW,MAAM,kBAAkB,CAAC;AAKnF,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,iBAAiB,CAAC;AAWhE,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAChE,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;IACtE,oBAAoB,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,wBAAsB,IAAI,CACxB,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAClC,SAAS,EAAE,SAAS,GAAG,IAAI,GAC1B,OAAO,CAAC,OAAO,CAAC,CA2KlB"}
|
|
@@ -29,6 +29,7 @@ export async function main(config, withRelPath, telemetry) {
|
|
|
29
29
|
const blake2b = await Blake2b.createHasher();
|
|
30
30
|
const nodeName = config.nodeName;
|
|
31
31
|
const isInMemory = config.node.databaseBasePath === undefined;
|
|
32
|
+
logger.info `🗄️ States DB: ${isInMemory ? "in-memory" : "lmdb"}.`;
|
|
32
33
|
const { dbPath, genesisHeaderHash } = getDatabasePath(blake2b, nodeName, config.node.chainSpec.genesisHeader, withRelPath(config.node.databaseBasePath ?? "<in-memory>"));
|
|
33
34
|
const baseConfig = { nodeName, chainSpec, blake2b, dbPath };
|
|
34
35
|
const importerParams = {
|
|
@@ -71,4 +71,39 @@ export declare class InMemWorkerConfig<T = undefined> implements WorkerConfig<T,
|
|
|
71
71
|
readonly: boolean;
|
|
72
72
|
}): RootDb<BlocksDb, SerializedStatesDb>;
|
|
73
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Hybrid worker config for the fuzz target: in-memory blocks and leaf sets,
|
|
76
|
+
* but large values persisted to LMDB.
|
|
77
|
+
*
|
|
78
|
+
* Like `InMemWorkerConfig`, the blocks and leaf sets are shared across the
|
|
79
|
+
* 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
|
|
81
|
+
* here and closed by `HybridSerializedStates.close()` at importer teardown.
|
|
82
|
+
*
|
|
83
|
+
* In-process only: it holds shared mutable state (the in-memory leaf
|
|
84
|
+
* dictionary) and so is not thread-transferable. The fuzz target runs the
|
|
85
|
+
* importer in-process via `createImporter`, not in a spawned worker.
|
|
86
|
+
*/
|
|
87
|
+
export declare class HybridWorkerConfig<T = undefined> implements WorkerConfig<T, BlocksDb, SerializedStatesDb> {
|
|
88
|
+
readonly nodeName: string;
|
|
89
|
+
readonly chainSpec: ChainSpec;
|
|
90
|
+
readonly workerParams: T;
|
|
91
|
+
readonly blake2b: Blake2b;
|
|
92
|
+
readonly dbPath: string;
|
|
93
|
+
readonly ephemeral: boolean;
|
|
94
|
+
static new<T>({ nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral, }: {
|
|
95
|
+
nodeName: string;
|
|
96
|
+
chainSpec: ChainSpec;
|
|
97
|
+
workerParams: T;
|
|
98
|
+
blake2b: Blake2b;
|
|
99
|
+
dbPath: string;
|
|
100
|
+
ephemeral?: boolean;
|
|
101
|
+
}): HybridWorkerConfig<T>;
|
|
102
|
+
private readonly blocks;
|
|
103
|
+
private readonly states;
|
|
104
|
+
private constructor();
|
|
105
|
+
openDatabase(_options?: {
|
|
106
|
+
readonly: boolean;
|
|
107
|
+
}): RootDb<BlocksDb, SerializedStatesDb>;
|
|
108
|
+
}
|
|
74
109
|
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api-node/config.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/api-node/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
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 { LmdbBlocks, LmdbRoot, LmdbStates } from "#@typeberry/database-lmdb";
|
|
4
|
+
import { HybridSerializedStates, LmdbBlocks, LmdbRoot, LmdbStates } from "#@typeberry/database-lmdb";
|
|
5
5
|
import { Blake2b } from "#@typeberry/hash";
|
|
6
6
|
import { ThreadPort } from "./port.js";
|
|
7
7
|
/** A worker config that's usable in node.js and uses LMDB database backend. */
|
|
@@ -105,3 +105,54 @@ export class InMemWorkerConfig {
|
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Hybrid worker config for the fuzz target: in-memory blocks and leaf sets,
|
|
110
|
+
* but large values persisted to LMDB.
|
|
111
|
+
*
|
|
112
|
+
* Like `InMemWorkerConfig`, the blocks and leaf sets are shared across the
|
|
113
|
+
* open/close/reopen dance that genesis init performs, so `openDatabase`
|
|
114
|
+
* returns the same instances and a no-op close. The LMDB root is opened once
|
|
115
|
+
* here and closed by `HybridSerializedStates.close()` at importer teardown.
|
|
116
|
+
*
|
|
117
|
+
* In-process only: it holds shared mutable state (the in-memory leaf
|
|
118
|
+
* dictionary) and so is not thread-transferable. The fuzz target runs the
|
|
119
|
+
* importer in-process via `createImporter`, not in a spawned worker.
|
|
120
|
+
*/
|
|
121
|
+
export class HybridWorkerConfig {
|
|
122
|
+
nodeName;
|
|
123
|
+
chainSpec;
|
|
124
|
+
workerParams;
|
|
125
|
+
blake2b;
|
|
126
|
+
dbPath;
|
|
127
|
+
ephemeral;
|
|
128
|
+
static new({ nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral = false, }) {
|
|
129
|
+
return new HybridWorkerConfig(nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral);
|
|
130
|
+
}
|
|
131
|
+
blocks;
|
|
132
|
+
states;
|
|
133
|
+
constructor(nodeName, chainSpec, workerParams, blake2b, dbPath, ephemeral) {
|
|
134
|
+
this.nodeName = nodeName;
|
|
135
|
+
this.chainSpec = chainSpec;
|
|
136
|
+
this.workerParams = workerParams;
|
|
137
|
+
this.blake2b = blake2b;
|
|
138
|
+
this.dbPath = dbPath;
|
|
139
|
+
this.ephemeral = ephemeral;
|
|
140
|
+
this.blocks = InMemoryBlocks.new();
|
|
141
|
+
this.states = HybridSerializedStates.new({
|
|
142
|
+
spec: this.chainSpec,
|
|
143
|
+
blake2b: this.blake2b,
|
|
144
|
+
dbPath: this.dbPath,
|
|
145
|
+
ephemeral: this.ephemeral,
|
|
146
|
+
readOnly: false,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
openDatabase(_options = { readonly: true }) {
|
|
150
|
+
return {
|
|
151
|
+
getBlocksDb: () => this.blocks,
|
|
152
|
+
getStatesDb: () => this.states,
|
|
153
|
+
// Leaf sets and blocks live in memory; the LMDB values store is closed
|
|
154
|
+
// via states.close() at importer teardown, so this is a no-op.
|
|
155
|
+
close: async () => { },
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|