@typeberry/jam 0.5.8-857ec24 → 0.5.8-b3da767
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/bootstrap-importer.mjs +130 -4
- package/bootstrap-importer.mjs.map +1 -1
- package/index.js +151 -11
- package/index.js.map +1 -1
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -152750,6 +152750,9 @@ class InMemorySerializedStates {
|
|
|
152750
152750
|
});
|
|
152751
152751
|
return serialized_state_SerializedState.new(this.spec, this.blake2b, leafDb);
|
|
152752
152752
|
}
|
|
152753
|
+
markUnused(header) {
|
|
152754
|
+
this.db.delete(header);
|
|
152755
|
+
}
|
|
152753
152756
|
async close() { }
|
|
152754
152757
|
}
|
|
152755
152758
|
|
|
@@ -152806,6 +152809,9 @@ class InMemoryStates {
|
|
|
152806
152809
|
}
|
|
152807
152810
|
return InMemoryState.copyFrom(this.spec, state, state.intoServicesData());
|
|
152808
152811
|
}
|
|
152812
|
+
markUnused(header) {
|
|
152813
|
+
this.db.delete(header);
|
|
152814
|
+
}
|
|
152809
152815
|
async close() { }
|
|
152810
152816
|
}
|
|
152811
152817
|
|
|
@@ -153050,6 +153056,9 @@ class LmdbStates {
|
|
|
153050
153056
|
}
|
|
153051
153057
|
return serialized_state_SerializedState.new(this.spec, this.blake2b, leafDbResult.ok);
|
|
153052
153058
|
}
|
|
153059
|
+
markUnused(header) {
|
|
153060
|
+
this.states.remove(header.raw);
|
|
153061
|
+
}
|
|
153053
153062
|
async close() {
|
|
153054
153063
|
await Promise.all([this.states.close(), this.values.close()]);
|
|
153055
153064
|
}
|
|
@@ -166533,6 +166542,113 @@ class TransitionHasher {
|
|
|
166533
166542
|
|
|
166534
166543
|
|
|
166535
166544
|
|
|
166545
|
+
;// CONCATENATED MODULE: ./packages/workers/importer/finality.ts
|
|
166546
|
+
|
|
166547
|
+
const finality_logger = logger_Logger.new(import.meta.filename, "finality");
|
|
166548
|
+
/**
|
|
166549
|
+
* A simple finalizer that considers a block finalized when N blocks
|
|
166550
|
+
* have been built on top of it.
|
|
166551
|
+
*
|
|
166552
|
+
* Maintains an array of fork chains starting from the last finalized block.
|
|
166553
|
+
* When any chain reaches `depth`, the earliest blocks are finalized and
|
|
166554
|
+
* dead forks (branching from before the finalized point) are discarded.
|
|
166555
|
+
*/
|
|
166556
|
+
class DummyFinalizer {
|
|
166557
|
+
blocks;
|
|
166558
|
+
depth;
|
|
166559
|
+
lastFinalizedHash;
|
|
166560
|
+
unfinalized = [];
|
|
166561
|
+
static create(blocks, depth) {
|
|
166562
|
+
return new DummyFinalizer(blocks, depth);
|
|
166563
|
+
}
|
|
166564
|
+
constructor(blocks, depth) {
|
|
166565
|
+
this.blocks = blocks;
|
|
166566
|
+
this.depth = depth;
|
|
166567
|
+
this.lastFinalizedHash = blocks.getBestHeaderHash();
|
|
166568
|
+
finality_logger.info `🦭 Dummy Finalizer running with depth=${depth}`;
|
|
166569
|
+
}
|
|
166570
|
+
onBlockImported(headerHash) {
|
|
166571
|
+
const header = this.blocks.getHeader(headerHash);
|
|
166572
|
+
if (header === null) {
|
|
166573
|
+
return null;
|
|
166574
|
+
}
|
|
166575
|
+
const parentHash = header.parentHeaderHash.materialize();
|
|
166576
|
+
// Try to attach the block to an existing chain at its tip.
|
|
166577
|
+
let extendedChain = null;
|
|
166578
|
+
for (const chain of this.unfinalized) {
|
|
166579
|
+
if (chain.length > 0 && chain[chain.length - 1].isEqualTo(parentHash)) {
|
|
166580
|
+
chain.push(headerHash);
|
|
166581
|
+
extendedChain = chain;
|
|
166582
|
+
break;
|
|
166583
|
+
}
|
|
166584
|
+
}
|
|
166585
|
+
if (extendedChain === null) {
|
|
166586
|
+
if (this.lastFinalizedHash.isEqualTo(parentHash)) {
|
|
166587
|
+
// Parent is the finalized block — start a new chain.
|
|
166588
|
+
const newChain = [headerHash];
|
|
166589
|
+
this.unfinalized.push(newChain);
|
|
166590
|
+
extendedChain = newChain;
|
|
166591
|
+
}
|
|
166592
|
+
else {
|
|
166593
|
+
// Fork from the middle of an existing chain — copy the prefix and branch.
|
|
166594
|
+
for (const chain of this.unfinalized) {
|
|
166595
|
+
const forkIdx = chain.findIndex((h) => h.isEqualTo(parentHash));
|
|
166596
|
+
if (forkIdx !== -1) {
|
|
166597
|
+
const newChain = [...chain.slice(0, forkIdx + 1), headerHash];
|
|
166598
|
+
this.unfinalized.push(newChain);
|
|
166599
|
+
extendedChain = newChain;
|
|
166600
|
+
break;
|
|
166601
|
+
}
|
|
166602
|
+
}
|
|
166603
|
+
}
|
|
166604
|
+
}
|
|
166605
|
+
if (extendedChain === null) {
|
|
166606
|
+
// Orphan block — cannot attach to any known chain.
|
|
166607
|
+
return null;
|
|
166608
|
+
}
|
|
166609
|
+
// Check if the extended chain is long enough to trigger finality.
|
|
166610
|
+
// A chain of length N has N-1 blocks built on top of chain[0].
|
|
166611
|
+
// We finalize chain[0] when there are >= depth blocks after it,
|
|
166612
|
+
// i.e. chain.length > depth.
|
|
166613
|
+
if (extendedChain.length <= this.depth) {
|
|
166614
|
+
return null;
|
|
166615
|
+
}
|
|
166616
|
+
// The newly finalized block sits at index (length - 1 - depth).
|
|
166617
|
+
const finalizedIdx = extendedChain.length - 1 - this.depth;
|
|
166618
|
+
const finalizedHash = extendedChain[finalizedIdx];
|
|
166619
|
+
// Collect prunable hashes and rebuild the unfinalized set.
|
|
166620
|
+
// The previously finalized block's state is no longer needed.
|
|
166621
|
+
const prunable = [this.lastFinalizedHash];
|
|
166622
|
+
const newUnfinalized = [];
|
|
166623
|
+
for (const chain of this.unfinalized) {
|
|
166624
|
+
// Find the finalized block in this chain.
|
|
166625
|
+
const finIdx = chain.findIndex((h) => h.isEqualTo(finalizedHash));
|
|
166626
|
+
if (finIdx !== -1) {
|
|
166627
|
+
// Chain contains the finalized block — it's still alive.
|
|
166628
|
+
// Prune states for blocks before the finalized block.
|
|
166629
|
+
for (let i = 0; i < finIdx; i++) {
|
|
166630
|
+
prunable.push(chain[i]);
|
|
166631
|
+
}
|
|
166632
|
+
// Keep blocks after the finalized block.
|
|
166633
|
+
const remaining = chain.slice(finIdx + 1);
|
|
166634
|
+
if (remaining.length > 0) {
|
|
166635
|
+
newUnfinalized.push(remaining);
|
|
166636
|
+
}
|
|
166637
|
+
}
|
|
166638
|
+
else {
|
|
166639
|
+
// Dead fork — branches from a block that is no longer finalized.
|
|
166640
|
+
// Prune all its states.
|
|
166641
|
+
for (const h of chain) {
|
|
166642
|
+
prunable.push(h);
|
|
166643
|
+
}
|
|
166644
|
+
}
|
|
166645
|
+
}
|
|
166646
|
+
this.lastFinalizedHash = finalizedHash;
|
|
166647
|
+
this.unfinalized = newUnfinalized;
|
|
166648
|
+
return { finalizedHash, prunableStateHashes: prunable };
|
|
166649
|
+
}
|
|
166650
|
+
}
|
|
166651
|
+
|
|
166536
166652
|
;// CONCATENATED MODULE: ./packages/workers/importer/metrics.ts
|
|
166537
166653
|
|
|
166538
166654
|
|
|
@@ -166757,6 +166873,14 @@ class Importer {
|
|
|
166757
166873
|
logger.log `${timerDb()}`;
|
|
166758
166874
|
// finally update the best block
|
|
166759
166875
|
await this.blocks.setBestHeaderHash(headerHash);
|
|
166876
|
+
// check for finality and prune old states
|
|
166877
|
+
const finality = this.options.finalizer?.onBlockImported(headerHash) ?? null;
|
|
166878
|
+
if (finality !== null) {
|
|
166879
|
+
this.logger.info `🦭 Finalized block: ${finality.finalizedHash} (${finality.prunableStateHashes.length} to prune)`;
|
|
166880
|
+
for (const hash of finality.prunableStateHashes) {
|
|
166881
|
+
this.states.markUnused(hash);
|
|
166882
|
+
}
|
|
166883
|
+
}
|
|
166760
166884
|
return result_Result.ok(new WithHash(headerHash, block.header.view()));
|
|
166761
166885
|
}
|
|
166762
166886
|
getBestStateRootHash() {
|
|
@@ -166798,6 +166922,7 @@ function extractTimeSlot(block) {
|
|
|
166798
166922
|
|
|
166799
166923
|
|
|
166800
166924
|
|
|
166925
|
+
|
|
166801
166926
|
const main_logger = logger_Logger.new(import.meta.filename, "importer");
|
|
166802
166927
|
const keccakHasher = KeccakHasher.create();
|
|
166803
166928
|
const blake2b = blake2b_Blake2b.createHasher();
|
|
@@ -166807,8 +166932,13 @@ async function createImporter(config, options = {}) {
|
|
|
166807
166932
|
const pvm = config.workerParams.pvm;
|
|
166808
166933
|
const blocks = db.getBlocksDb();
|
|
166809
166934
|
const states = db.getStatesDb();
|
|
166935
|
+
const dummyFinalityDepth = config.workerParams.dummyFinalityDepth ?? 0;
|
|
166936
|
+
const finalizer = dummyFinalityDepth > 0 ? DummyFinalizer.create(blocks, dummyFinalityDepth) : undefined;
|
|
166810
166937
|
const hasher = new TransitionHasher(await keccakHasher, await blake2b);
|
|
166811
|
-
const importer = new Importer(chainSpec, pvm, hasher, main_logger, blocks, states,
|
|
166938
|
+
const importer = new Importer(chainSpec, pvm, hasher, main_logger, blocks, states, {
|
|
166939
|
+
...options,
|
|
166940
|
+
finalizer,
|
|
166941
|
+
});
|
|
166812
166942
|
return {
|
|
166813
166943
|
importer,
|
|
166814
166944
|
db,
|
|
@@ -166926,6 +167056,7 @@ const protocol_protocol = createProtocol("importer", {
|
|
|
166926
167056
|
});
|
|
166927
167057
|
class ImporterConfig {
|
|
166928
167058
|
pvm;
|
|
167059
|
+
dummyFinalityDepth;
|
|
166929
167060
|
static Codec = codec_codec.Class(ImporterConfig, {
|
|
166930
167061
|
pvm: codec_codec.u8.convert((i) => tryAsU8(i), (o) => {
|
|
166931
167062
|
if (o === PvmBackend.BuiltIn) {
|
|
@@ -166936,12 +167067,16 @@ class ImporterConfig {
|
|
|
166936
167067
|
}
|
|
166937
167068
|
throw new Error(`Invalid PvmBackend: ${o}`);
|
|
166938
167069
|
}),
|
|
167070
|
+
dummyFinalityDepth: codec_codec.u16,
|
|
166939
167071
|
});
|
|
166940
|
-
static create({ pvm }) {
|
|
166941
|
-
return new ImporterConfig(pvm);
|
|
167072
|
+
static create({ pvm, dummyFinalityDepth }) {
|
|
167073
|
+
return new ImporterConfig(pvm, dummyFinalityDepth);
|
|
166942
167074
|
}
|
|
166943
|
-
constructor(pvm
|
|
167075
|
+
constructor(pvm,
|
|
167076
|
+
/** Dummy finality depth. 0 means disabled, any positive value enables dummy finality with that depth. */
|
|
167077
|
+
dummyFinalityDepth = numbers_tryAsU16(0)) {
|
|
166944
167078
|
this.pvm = pvm;
|
|
167079
|
+
this.dummyFinalityDepth = dummyFinalityDepth;
|
|
166945
167080
|
}
|
|
166946
167081
|
}
|
|
166947
167082
|
|
|
@@ -170304,6 +170439,7 @@ async function node_main_main(config, withRelPath, telemetry) {
|
|
|
170304
170439
|
...baseConfig,
|
|
170305
170440
|
workerParams: ImporterConfig.create({
|
|
170306
170441
|
pvm: config.pvmBackend,
|
|
170442
|
+
dummyFinalityDepth: numbers_tryAsU16(config.devValidatorIndex !== null ? 100 : 0),
|
|
170307
170443
|
}),
|
|
170308
170444
|
};
|
|
170309
170445
|
const importerConfig = isInMemory
|
|
@@ -170498,6 +170634,7 @@ const initNetwork = async (importer, params, baseConfig, genesisHeaderHash, netw
|
|
|
170498
170634
|
|
|
170499
170635
|
|
|
170500
170636
|
|
|
170637
|
+
|
|
170501
170638
|
const zeroHash = bytes_Bytes.zero(hash_HASH_SIZE).asOpaque();
|
|
170502
170639
|
async function mainImporter(config, withRelPath, options = {}) {
|
|
170503
170640
|
await initAll();
|
|
@@ -170510,23 +170647,23 @@ async function mainImporter(config, withRelPath, options = {}) {
|
|
|
170510
170647
|
const blake2b = await blake2b_Blake2b.createHasher();
|
|
170511
170648
|
const nodeName = config.nodeName;
|
|
170512
170649
|
const { dbPath, genesisHeaderHash } = getDatabasePath(blake2b, config.nodeName, config.node.chainSpec.genesisHeader, withRelPath(config.node.databaseBasePath ?? "<in-memory>"));
|
|
170650
|
+
const workerParams = ImporterConfig.create({
|
|
170651
|
+
pvm: config.pvmBackend,
|
|
170652
|
+
dummyFinalityDepth: numbers_tryAsU16(options.dummyFinalityDepth ?? 0),
|
|
170653
|
+
});
|
|
170513
170654
|
const workerConfig = config.node.databaseBasePath === undefined
|
|
170514
170655
|
? InMemWorkerConfig.new({
|
|
170515
170656
|
nodeName,
|
|
170516
170657
|
chainSpec,
|
|
170517
170658
|
blake2b,
|
|
170518
|
-
workerParams
|
|
170519
|
-
pvm: config.pvmBackend,
|
|
170520
|
-
},
|
|
170659
|
+
workerParams,
|
|
170521
170660
|
})
|
|
170522
170661
|
: config_LmdbWorkerConfig.new({
|
|
170523
170662
|
nodeName,
|
|
170524
170663
|
chainSpec,
|
|
170525
170664
|
blake2b,
|
|
170526
170665
|
dbPath,
|
|
170527
|
-
workerParams
|
|
170528
|
-
pvm: config.pvmBackend,
|
|
170529
|
-
},
|
|
170666
|
+
workerParams,
|
|
170530
170667
|
});
|
|
170531
170668
|
// Initialize the database with genesis state and block if there isn't one.
|
|
170532
170669
|
common_logger.info `🛢️ Opening database at ${dbPath}`;
|
|
@@ -170635,7 +170772,10 @@ async function mainFuzz(fuzzConfig, withRelPath) {
|
|
|
170635
170772
|
},
|
|
170636
170773
|
ancestry,
|
|
170637
170774
|
network: null,
|
|
170638
|
-
}, withRelPath, {
|
|
170775
|
+
}, withRelPath, {
|
|
170776
|
+
initGenesisFromAncestry: fuzzConfig.initGenesisFromAncestry,
|
|
170777
|
+
dummyFinalityDepth: 10_000,
|
|
170778
|
+
});
|
|
170639
170779
|
runningNode = newNode;
|
|
170640
170780
|
return await newNode.getBestStateRootHash();
|
|
170641
170781
|
},
|