@typeberry/lib 0.8.3-43d8627 → 0.8.3-7d6da6f
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/core/utils/debug.d.ts +12 -2
- package/packages/core/utils/debug.d.ts.map +1 -1
- package/packages/core/utils/debug.js +20 -3
- package/packages/jam/transition/chain-stf.d.ts +2 -1
- package/packages/jam/transition/chain-stf.d.ts.map +1 -1
- package/packages/jam/transition/chain-stf.js +4 -2
- package/packages/workers/importer/events-logger.d.ts +33 -0
- package/packages/workers/importer/events-logger.d.ts.map +1 -0
- package/packages/workers/importer/events-logger.js +50 -0
- package/packages/workers/importer/importer.d.ts +3 -1
- package/packages/workers/importer/importer.d.ts.map +1 -1
- package/packages/workers/importer/importer.js +41 -33
package/package.json
CHANGED
|
@@ -39,8 +39,18 @@ export declare function assertNever(value: never): never;
|
|
|
39
39
|
export declare function assertEmpty<T extends Record<string, never>>(value: T): void;
|
|
40
40
|
/** Debug print an object. */
|
|
41
41
|
export declare function inspect<T>(val: T): string;
|
|
42
|
-
/**
|
|
43
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Utility function to measure time taken for some operation [ms].
|
|
44
|
+
*
|
|
45
|
+
* To reduce allocations, each timer can only track one entry.
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
export declare function measure(id: string): () => {
|
|
49
|
+
id: string;
|
|
50
|
+
start: number;
|
|
51
|
+
duration(): number;
|
|
52
|
+
toString(): string;
|
|
53
|
+
};
|
|
44
54
|
/**
|
|
45
55
|
* Format current process memory usage as a human readable string.
|
|
46
56
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../../../packages/core/utils/debug.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,YAExB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG,cAA6F,CAAC;AAE9G;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CACnB,OAAO,EAAE,oBAAoB,EAC7B,SAAS,EAAE,OAAO,EAClB,GAAG,IAAI,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,SAAS,IAAI,IAAI,CAO3B;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAE/C;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,QAKpE;AAED,6BAA6B;AAC7B,wBAAgB,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,MAAM,CAEzC;AAkED
|
|
1
|
+
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../../../packages/core/utils/debug.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,YAExB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG,cAA6F,CAAC;AAE9G;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CACnB,OAAO,EAAE,oBAAoB,EAC7B,SAAS,EAAE,OAAO,EAClB,GAAG,IAAI,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,SAAS,IAAI,IAAI,CAO3B;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAE/C;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,QAKpE;AAED,6BAA6B;AAC7B,wBAAgB,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,MAAM,CAEzC;AAkED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM;;;;;EAgBjC;AAcD;;;;;;;GAOG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAMpC;AAED,+CAA+C;AAC/C,wBAAgB,aAAa,IAAI,MAAM,MAAM,CAc5C;AAED,mFAAmF;AACnF,8BAAsB,SAAS;IAC7B,QAAQ;CAGT;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC;;EAMpC"}
|
|
@@ -108,10 +108,27 @@ function inspectInternal(val, seen) {
|
|
|
108
108
|
v += oneLine ? "}" : "\n}";
|
|
109
109
|
return v;
|
|
110
110
|
}
|
|
111
|
-
/**
|
|
111
|
+
/**
|
|
112
|
+
* Utility function to measure time taken for some operation [ms].
|
|
113
|
+
*
|
|
114
|
+
* To reduce allocations, each timer can only track one entry.
|
|
115
|
+
*
|
|
116
|
+
*/
|
|
112
117
|
export function measure(id) {
|
|
113
|
-
const
|
|
114
|
-
|
|
118
|
+
const response = {
|
|
119
|
+
id,
|
|
120
|
+
start: 0,
|
|
121
|
+
duration() {
|
|
122
|
+
return now() - this.start;
|
|
123
|
+
},
|
|
124
|
+
toString() {
|
|
125
|
+
return `${this.id} took ${(this.duration()).toFixed(2)}ms`;
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
return () => {
|
|
129
|
+
response.start = now();
|
|
130
|
+
return response;
|
|
131
|
+
};
|
|
115
132
|
}
|
|
116
133
|
const BYTES_IN_MB = 1024 * 1024;
|
|
117
134
|
const toMb = (bytes) => (bytes / BYTES_IN_MB).toFixed(1);
|
|
@@ -6,7 +6,7 @@ import type { DisputesErrorCode } from "#@typeberry/disputes/disputes-error-code
|
|
|
6
6
|
import type { SafroleErrorCode, SafroleStateUpdate } from "#@typeberry/safrole/safrole.js";
|
|
7
7
|
import { type SafroleSealError } from "#@typeberry/safrole/safrole-seal.js";
|
|
8
8
|
import type { State, WithStateView } from "#@typeberry/state";
|
|
9
|
-
import { type ErrorResult, Result, type TaggedError } from "#@typeberry/utils";
|
|
9
|
+
import { type ErrorResult, measure, Result, type TaggedError } from "#@typeberry/utils";
|
|
10
10
|
import { type ACCUMULATION_ERROR, type AccumulateOptions, type AccumulateStateUpdate } from "./accumulate/index.js";
|
|
11
11
|
import { type AssurancesError, type AssurancesStateUpdate } from "./assurances.js";
|
|
12
12
|
import { type AuthorizationStateUpdate } from "./authorization.js";
|
|
@@ -59,6 +59,7 @@ export declare class OnChain {
|
|
|
59
59
|
readonly chainSpec: ChainSpec;
|
|
60
60
|
readonly state: State & WithStateView;
|
|
61
61
|
readonly hasher: TransitionHasher;
|
|
62
|
+
readonly measureAccumulate: ReturnType<typeof measure>;
|
|
62
63
|
/** Wire up a full on-chain STF from its dependencies. */
|
|
63
64
|
static assemble(args: {
|
|
64
65
|
chainSpec: ChainSpec;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain-stf.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/transition/chain-stf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAa,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAInF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAY,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAIpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAC1F,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACxF,OAAO,KAAK,EAAkB,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAe,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"chain-stf.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/transition/chain-stf.ts"],"names":[],"mappings":"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"}
|
|
@@ -84,6 +84,7 @@ export class OnChain {
|
|
|
84
84
|
chainSpec;
|
|
85
85
|
state;
|
|
86
86
|
hasher;
|
|
87
|
+
measureAccumulate;
|
|
87
88
|
/** Wire up a full on-chain STF from its dependencies. */
|
|
88
89
|
static assemble(args) {
|
|
89
90
|
return new OnChain(args.chainSpec, args.state, args.hasher, args.options, args.headerChain);
|
|
@@ -104,6 +105,7 @@ export class OnChain {
|
|
|
104
105
|
this.accumulateOutput = new AccumulateOutput();
|
|
105
106
|
this.preimages = new Preimages(state, hasher.blake2b);
|
|
106
107
|
this.authorization = new Authorization(chainSpec, state);
|
|
108
|
+
this.measureAccumulate = measure(`import:accumulate (${PvmBackend[options.pvm]})`);
|
|
107
109
|
}
|
|
108
110
|
/** Pre-populate things worth caching for the next epoch. */
|
|
109
111
|
async prepareForNextEpoch() {
|
|
@@ -205,14 +207,14 @@ export class OnChain {
|
|
|
205
207
|
}
|
|
206
208
|
const { preimages, ...preimagesRest } = preimagesResult.ok;
|
|
207
209
|
assertEmpty(preimagesRest);
|
|
208
|
-
const timerAccumulate =
|
|
210
|
+
const timerAccumulate = this.measureAccumulate();
|
|
209
211
|
// accumulate
|
|
210
212
|
const accumulateResult = await this.accumulate.transition({
|
|
211
213
|
slot: timeSlot,
|
|
212
214
|
reports: availableReports,
|
|
213
215
|
entropy: entropy[0],
|
|
214
216
|
});
|
|
215
|
-
logger.log
|
|
217
|
+
logger.log `#${timeSlot} ${timerAccumulate}`;
|
|
216
218
|
if (accumulateResult.isError) {
|
|
217
219
|
return stfError(StfErrorKind.Accumulate, accumulateResult);
|
|
218
220
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { HeaderHash, TimeSlot } from "#@typeberry/block";
|
|
2
|
+
import type { LeafDb } from "#@typeberry/database";
|
|
3
|
+
import type { Logger } from "#@typeberry/logger";
|
|
4
|
+
import type { SerializedState } from "#@typeberry/state-merkleization";
|
|
5
|
+
/** Events happening during block imports. */
|
|
6
|
+
export interface ImporterEventsListener {
|
|
7
|
+
/**
|
|
8
|
+
* Invoked when we start importing a block.
|
|
9
|
+
*
|
|
10
|
+
* Must return a callback that will be triggered at the end of block import.
|
|
11
|
+
* The callback is expected to return duration between start and end events.
|
|
12
|
+
*/
|
|
13
|
+
onBlockImportingStarted(timeSlot: TimeSlot): (isOk: boolean) => number;
|
|
14
|
+
/** Initial state of the importer. */
|
|
15
|
+
onStart(currentBestHeaderHash: HeaderHash, currentBestState: SerializedState<LeafDb>): void;
|
|
16
|
+
}
|
|
17
|
+
export declare class ImporterStats implements ImporterEventsListener {
|
|
18
|
+
private readonly logger;
|
|
19
|
+
/** How often we are going to print the stats (i.e. every `maxBlocks` blocks) */
|
|
20
|
+
private readonly maxBlocks;
|
|
21
|
+
/** Alternatively print stats when we reach `${maxTimeMs}` of total block execution. */
|
|
22
|
+
private readonly maxTimeMs;
|
|
23
|
+
private readonly memory;
|
|
24
|
+
private totalTimePrev;
|
|
25
|
+
private totalTime;
|
|
26
|
+
private totalBlocksPrev;
|
|
27
|
+
private totalBlocks;
|
|
28
|
+
static new(logger: Logger): ImporterStats;
|
|
29
|
+
private constructor();
|
|
30
|
+
onStart(currentBestHeaderHash: HeaderHash, currentBestState: SerializedState<LeafDb>): void;
|
|
31
|
+
onBlockImportingStarted(timeSlot: TimeSlot): (isOk: boolean) => number;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=events-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-logger.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/importer/events-logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAGtE,6CAA6C;AAC7C,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM,CAAC;IAEvE,qCAAqC;IACrC,OAAO,CAAC,qBAAqB,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CAC7F;AAED,qBAAa,aAAc,YAAW,sBAAsB;IAYxD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,gFAAgF;IAChF,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,uFAAuF;IACvF,OAAO,CAAC,QAAQ,CAAC,SAAS;IAf5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,WAAW,CAAK;IAExB,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM;IAIzB,OAAO;IAQP,OAAO,CAAC,qBAAqB,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,CAAC,MAAM,CAAC;IAIpF,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,IAGhC,MAAM,OAAO;CA0BxB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { memoryTracker, now } from "#@typeberry/utils";
|
|
2
|
+
export class ImporterStats {
|
|
3
|
+
logger;
|
|
4
|
+
maxBlocks;
|
|
5
|
+
maxTimeMs;
|
|
6
|
+
memory = memoryTracker();
|
|
7
|
+
totalTimePrev = 0;
|
|
8
|
+
totalTime = 0;
|
|
9
|
+
totalBlocksPrev = 0;
|
|
10
|
+
totalBlocks = 0;
|
|
11
|
+
static new(logger) {
|
|
12
|
+
return new ImporterStats(logger);
|
|
13
|
+
}
|
|
14
|
+
constructor(logger,
|
|
15
|
+
/** How often we are going to print the stats (i.e. every `maxBlocks` blocks) */
|
|
16
|
+
maxBlocks = 100,
|
|
17
|
+
/** Alternatively print stats when we reach `${maxTimeMs}` of total block execution. */
|
|
18
|
+
maxTimeMs = 5000) {
|
|
19
|
+
this.logger = logger;
|
|
20
|
+
this.maxBlocks = maxBlocks;
|
|
21
|
+
this.maxTimeMs = maxTimeMs;
|
|
22
|
+
}
|
|
23
|
+
onStart(currentBestHeaderHash, currentBestState) {
|
|
24
|
+
this.logger.info `😎 Best time slot: ${currentBestState.timeslot} (header hash: ${currentBestHeaderHash})`;
|
|
25
|
+
}
|
|
26
|
+
onBlockImportingStarted(timeSlot) {
|
|
27
|
+
const start = now();
|
|
28
|
+
return (isOk) => {
|
|
29
|
+
const duration = now() - start;
|
|
30
|
+
const label = isOk ? "import" : "reject";
|
|
31
|
+
this.logger.log `⏱️ ${label} #${timeSlot} took ${duration.toFixed(2)}ms`;
|
|
32
|
+
this.totalTime += duration;
|
|
33
|
+
this.totalBlocks += 1;
|
|
34
|
+
if (this.totalBlocks >= this.maxBlocks || this.totalTime >= this.maxTimeMs) {
|
|
35
|
+
this.logger.info `📊 mem at #${timeSlot}: ${this.memory()}`;
|
|
36
|
+
// compute block statistics (rolling window of last two rounds)
|
|
37
|
+
const importedBlocks = this.totalBlocks + this.totalBlocksPrev;
|
|
38
|
+
const importTime = this.totalTime + this.totalTimePrev;
|
|
39
|
+
const blocksPerSecond = (importedBlocks / importTime) * 1000;
|
|
40
|
+
// carry over current round
|
|
41
|
+
this.totalBlocksPrev = this.totalBlocks;
|
|
42
|
+
this.totalTimePrev = this.totalTime;
|
|
43
|
+
this.totalBlocks = 0;
|
|
44
|
+
this.totalTime = 0;
|
|
45
|
+
this.logger.info `⏱️ time at #${timeSlot}: ${blocksPerSecond.toFixed(2)}bps`;
|
|
46
|
+
}
|
|
47
|
+
return duration;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -8,6 +8,7 @@ import type { TransitionHasher } from "#@typeberry/transition";
|
|
|
8
8
|
import { BlockVerifierError } from "#@typeberry/transition/block-verifier.js";
|
|
9
9
|
import { type StfError } from "#@typeberry/transition/chain-stf.js";
|
|
10
10
|
import { Result, type TaggedError } from "#@typeberry/utils";
|
|
11
|
+
import { type ImporterEventsListener } from "./events-logger.js";
|
|
11
12
|
import type { Finalizer } from "./finality.js";
|
|
12
13
|
export declare enum ImporterErrorKind {
|
|
13
14
|
Verifier = 0,
|
|
@@ -29,6 +30,7 @@ export type ImporterArgs = {
|
|
|
29
30
|
blocks: BlocksDb;
|
|
30
31
|
states: StatesDb<SerializedState<LeafDb>>;
|
|
31
32
|
options?: ImporterOptions;
|
|
33
|
+
events?: ImporterEventsListener;
|
|
32
34
|
};
|
|
33
35
|
export declare class Importer {
|
|
34
36
|
private readonly verifier;
|
|
@@ -36,12 +38,12 @@ export declare class Importer {
|
|
|
36
38
|
private readonly state;
|
|
37
39
|
private currentHash;
|
|
38
40
|
private readonly metrics;
|
|
39
|
-
private readonly memory;
|
|
40
41
|
private readonly hasher;
|
|
41
42
|
private readonly logger;
|
|
42
43
|
private readonly blocks;
|
|
43
44
|
private readonly states;
|
|
44
45
|
private readonly options;
|
|
46
|
+
private readonly events;
|
|
45
47
|
/**
|
|
46
48
|
* Build an {@link Importer} connected to the best state loaded from `states`.
|
|
47
49
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"importer.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/importer/importer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,aAAa,EAAiB,MAAM,kBAAkB,CAAC;AACvH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACxF,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAiB,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,EAA0B,KAAK,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC3F,OAAO,
|
|
1
|
+
{"version":3,"file":"importer.d.ts","sourceRoot":"","sources":["../../../../../packages/workers/importer/importer.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,8 @@ import { tryAsTimeSlot } from "#@typeberry/block";
|
|
|
2
2
|
import { WithHash } from "#@typeberry/hash";
|
|
3
3
|
import { BlockVerifier, BlockVerifierError } from "#@typeberry/transition/block-verifier.js";
|
|
4
4
|
import { DbHeaderChain, OnChain } from "#@typeberry/transition/chain-stf.js";
|
|
5
|
-
import { measure,
|
|
5
|
+
import { measure, Result, resultToString } from "#@typeberry/utils";
|
|
6
|
+
import { ImporterStats } from "./events-logger.js";
|
|
6
7
|
import * as metrics from "./metrics.js";
|
|
7
8
|
export var ImporterErrorKind;
|
|
8
9
|
(function (ImporterErrorKind) {
|
|
@@ -11,6 +12,12 @@ export var ImporterErrorKind;
|
|
|
11
12
|
ImporterErrorKind[ImporterErrorKind["Update"] = 2] = "Update";
|
|
12
13
|
})(ImporterErrorKind || (ImporterErrorKind = {}));
|
|
13
14
|
const importerError = (kind, nested) => Result.taggedError(ImporterErrorKind, kind, nested);
|
|
15
|
+
const MEASURE = {
|
|
16
|
+
importVerify: measure("import:verify"),
|
|
17
|
+
importStf: measure("import:stf"),
|
|
18
|
+
importState: measure("import:state"),
|
|
19
|
+
importDb: measure("import:db"),
|
|
20
|
+
};
|
|
14
21
|
export class Importer {
|
|
15
22
|
verifier;
|
|
16
23
|
stf;
|
|
@@ -19,12 +26,12 @@ export class Importer {
|
|
|
19
26
|
// Hash of the block that we have the posterior state for in `state`.
|
|
20
27
|
currentHash;
|
|
21
28
|
metrics;
|
|
22
|
-
memory = memoryTracker();
|
|
23
29
|
hasher;
|
|
24
30
|
logger;
|
|
25
31
|
blocks;
|
|
26
32
|
states;
|
|
27
33
|
options;
|
|
34
|
+
events;
|
|
28
35
|
/**
|
|
29
36
|
* Build an {@link Importer} connected to the best state loaded from `states`.
|
|
30
37
|
*
|
|
@@ -45,6 +52,7 @@ export class Importer {
|
|
|
45
52
|
this.blocks = args.blocks;
|
|
46
53
|
this.states = args.states;
|
|
47
54
|
this.options = args.options ?? {};
|
|
55
|
+
this.events = args.events ?? ImporterStats.new(args.logger);
|
|
48
56
|
this.metrics = metrics.createMetrics();
|
|
49
57
|
this.verifier = BlockVerifier.new(args.hasher, args.blocks);
|
|
50
58
|
this.stf = OnChain.assemble({
|
|
@@ -57,7 +65,7 @@ export class Importer {
|
|
|
57
65
|
this.state = state;
|
|
58
66
|
this.currentHash = currentBestHeaderHash;
|
|
59
67
|
this.prepareForNextEpoch();
|
|
60
|
-
|
|
68
|
+
this.events.onStart(currentBestHeaderHash, state);
|
|
61
69
|
}
|
|
62
70
|
/** Do some extra work for preparation for the next epoch. */
|
|
63
71
|
async prepareForNextEpoch() {
|
|
@@ -76,42 +84,44 @@ export class Importer {
|
|
|
76
84
|
return res;
|
|
77
85
|
}
|
|
78
86
|
async importBlock(block) {
|
|
79
|
-
const timer = measure("importBlock");
|
|
80
87
|
const timeSlot = extractTimeSlot(block);
|
|
88
|
+
const onEnd = this.events.onBlockImportingStarted(timeSlot);
|
|
81
89
|
this.metrics.recordBlockImportingStarted(timeSlot);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (maybeBestHeader.isOk) {
|
|
86
|
-
if (timeSlot % 100 === 0) {
|
|
87
|
-
this.logger.info `📊 mem #${timeSlot}: ${this.memory()}`;
|
|
88
|
-
}
|
|
89
|
-
const bestHeader = maybeBestHeader.ok;
|
|
90
|
-
this.logger.info `🧊 Best block: #${timeSlot} (${bestHeader.hash})`;
|
|
91
|
-
this.logger.log `${timer()}`;
|
|
92
|
-
this.metrics.recordBlockImportComplete(duration, true);
|
|
90
|
+
let maybeBestHeader = null;
|
|
91
|
+
try {
|
|
92
|
+
maybeBestHeader = await this.importBlockInternal(block);
|
|
93
93
|
return maybeBestHeader;
|
|
94
94
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
finally {
|
|
96
|
+
const isOk = maybeBestHeader?.isOk ?? false;
|
|
97
|
+
const duration = onEnd(isOk);
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
99
|
+
if (maybeBestHeader?.isOk) {
|
|
100
|
+
const bestHeader = maybeBestHeader.ok;
|
|
101
|
+
this.logger.info `🧊 Best block: #${timeSlot} (${bestHeader.hash})`;
|
|
102
|
+
this.metrics.recordBlockImportComplete(duration, true);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
this.logger
|
|
106
|
+
.log `❌ Rejected block #${timeSlot}: ${maybeBestHeader !== null ? resultToString(maybeBestHeader) : "exception"}`;
|
|
107
|
+
this.metrics.recordBlockImportComplete(duration, false);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
99
110
|
}
|
|
100
111
|
async importBlockInternal(block) {
|
|
101
112
|
const logger = this.logger;
|
|
102
113
|
logger.log `🧱 Attempting to import a new block`;
|
|
103
|
-
const timerVerify =
|
|
104
|
-
const verifyStart = now();
|
|
114
|
+
const timerVerify = MEASURE.importVerify();
|
|
105
115
|
const hash = await this.verifier.verifyBlock(block, {
|
|
106
116
|
skipParentAndStateRoot: this.options.initGenesisFromAncestry ?? false,
|
|
107
117
|
});
|
|
108
|
-
const verifyDuration = now() - verifyStart;
|
|
109
|
-
logger.log `${timerVerify()}`;
|
|
110
118
|
if (hash.isError) {
|
|
119
|
+
logger.log `${timerVerify}`;
|
|
111
120
|
this.metrics.recordBlockVerificationFailed(resultToString(hash));
|
|
112
121
|
return importerError(ImporterErrorKind.Verifier, hash);
|
|
113
122
|
}
|
|
114
|
-
|
|
123
|
+
logger.log `${hash.ok} ${timerVerify}`;
|
|
124
|
+
this.metrics.recordBlockVerified(timerVerify.duration());
|
|
115
125
|
// TODO [ToDr] This is incomplete/temporary fork support!
|
|
116
126
|
const parentHash = block.header.view().parentHeaderHash.materialize();
|
|
117
127
|
if (!this.currentHash.isEqualTo(parentHash)) {
|
|
@@ -130,19 +140,17 @@ export class Importer {
|
|
|
130
140
|
const timeSlot = block.header.view().timeSlotIndex.materialize();
|
|
131
141
|
const headerHash = hash.ok;
|
|
132
142
|
logger.log `🧱 Verified block: Got hash ${headerHash} for block at slot ${timeSlot}.`;
|
|
133
|
-
const timerStf =
|
|
134
|
-
const stfStart = now();
|
|
143
|
+
const timerStf = MEASURE.importStf();
|
|
135
144
|
const res = await this.stf.transition(block, headerHash);
|
|
136
|
-
|
|
137
|
-
logger.log `${timerStf()}`;
|
|
145
|
+
logger.log `${headerHash} ${timerStf}`;
|
|
138
146
|
if (res.isError) {
|
|
139
147
|
this.metrics.recordBlockExecutionFailed(resultToString(res));
|
|
140
148
|
return importerError(ImporterErrorKind.Stf, res);
|
|
141
149
|
}
|
|
142
|
-
this.metrics.recordBlockExecuted(
|
|
150
|
+
this.metrics.recordBlockExecuted(timerStf.duration(), 0);
|
|
143
151
|
// modify the state
|
|
144
152
|
const update = res.ok;
|
|
145
|
-
const timerState =
|
|
153
|
+
const timerState = MEASURE.importState();
|
|
146
154
|
const updateResult = await this.states.updateAndSetState(headerHash, this.state, update);
|
|
147
155
|
if (updateResult.isError) {
|
|
148
156
|
logger.error `🧱 Unable to update state: ${resultToString(updateResult)}`;
|
|
@@ -150,9 +158,9 @@ export class Importer {
|
|
|
150
158
|
}
|
|
151
159
|
this.prepareForNextEpoch();
|
|
152
160
|
this.currentHash = headerHash;
|
|
153
|
-
logger.log `${timerState
|
|
161
|
+
logger.log `${timerState}`;
|
|
154
162
|
// insert new state and the block to DB.
|
|
155
|
-
const timerDb =
|
|
163
|
+
const timerDb = MEASURE.importDb();
|
|
156
164
|
const writeBlocks = this.blocks.insertBlock(WithHash.new(headerHash, block));
|
|
157
165
|
// Computation of the state root may happen asynchronously,
|
|
158
166
|
// but we still need to wait for it before next block can be imported
|
|
@@ -160,7 +168,7 @@ export class Importer {
|
|
|
160
168
|
logger.log `🧱 Storing post-state-root for ${headerHash}: ${stateRoot}.`;
|
|
161
169
|
const writeStateRoot = this.blocks.setPostStateRoot(headerHash, stateRoot);
|
|
162
170
|
await Promise.all([writeBlocks, writeStateRoot]);
|
|
163
|
-
logger.log `${timerDb
|
|
171
|
+
logger.log `${headerHash} ${timerDb}`;
|
|
164
172
|
// finally update the best block
|
|
165
173
|
await this.blocks.setBestHeaderHash(headerHash);
|
|
166
174
|
// check for finality and prune old states (and optionally blocks)
|