@lodestar/beacon-node 1.50.0-dev.abf1d462fa → 1.50.0-dev.af3e3a6cff
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/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +6 -1
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +4 -4
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +1 -0
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +7 -3
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts +2 -2
- package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js +5 -7
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/types.d.ts +2 -2
- package/lib/chain/archiveStore/historicalState/types.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/worker.js +1 -1
- package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
- package/lib/chain/archiveStore/interface.d.ts +1 -1
- package/lib/chain/archiveStore/interface.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts +4 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.js +4 -3
- package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +4 -0
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +2 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +1 -1
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts +2 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +5 -4
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
- package/lib/chain/chain.d.ts +5 -4
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +15 -16
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/envelopeReconstructionError.d.ts +5 -0
- package/lib/chain/errors/envelopeReconstructionError.d.ts.map +1 -1
- package/lib/chain/errors/envelopeReconstructionError.js +2 -0
- package/lib/chain/errors/envelopeReconstructionError.js.map +1 -1
- package/lib/chain/errors/gossipValidation.d.ts +3 -1
- package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
- package/lib/chain/errors/gossipValidation.js +2 -0
- package/lib/chain/errors/gossipValidation.js.map +1 -1
- package/lib/chain/initState.d.ts +2 -9
- package/lib/chain/initState.d.ts.map +1 -1
- package/lib/chain/initState.js +5 -38
- package/lib/chain/initState.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/opPools/opPool.d.ts +5 -4
- package/lib/chain/opPools/opPool.d.ts.map +1 -1
- package/lib/chain/opPools/opPool.js +62 -18
- package/lib/chain/opPools/opPool.js.map +1 -1
- package/lib/chain/opPools/utils.d.ts +4 -1
- package/lib/chain/opPools/utils.d.ts.map +1 -1
- package/lib/chain/opPools/utils.js +11 -1
- package/lib/chain/opPools/utils.js.map +1 -1
- package/lib/chain/options.d.ts +1 -1
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +1 -1
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +5 -2
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +6 -2
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/regen.d.ts +2 -0
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +10 -4
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +9 -2
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +23 -13
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts +4 -4
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +3 -0
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.d.ts +3 -3
- package/lib/chain/validation/proposerSlashing.d.ts.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +3 -0
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts +5 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +64 -54
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +2 -0
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/repositories/proposerSlashing.d.ts +1 -0
- package/lib/db/repositories/proposerSlashing.d.ts.map +1 -1
- package/lib/db/repositories/proposerSlashing.js +5 -1
- package/lib/db/repositories/proposerSlashing.js.map +1 -1
- package/lib/execution/engine/disabled.d.ts +0 -2
- package/lib/execution/engine/disabled.d.ts.map +1 -1
- package/lib/execution/engine/disabled.js +0 -6
- package/lib/execution/engine/disabled.js.map +1 -1
- package/lib/execution/engine/http.d.ts +1 -3
- package/lib/execution/engine/http.d.ts.map +1 -1
- package/lib/execution/engine/http.js +2 -17
- package/lib/execution/engine/http.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +2 -4
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/mock.d.ts +0 -2
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +0 -8
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/execution/engine/types.d.ts +0 -8
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/metrics/metrics.d.ts +7 -3
- package/lib/metrics/metrics.d.ts.map +1 -1
- package/lib/metrics/metrics.js +4 -4
- package/lib/metrics/metrics.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +7 -4
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipValidatorFn.d.ts +7 -3
- package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
- package/lib/network/processor/gossipValidatorFn.js +7 -3
- package/lib/network/processor/gossipValidatorFn.js.map +1 -1
- package/lib/network/processor/index.d.ts +9 -0
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +77 -10
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +41 -26
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +25 -3
- package/lib/node/nodejs.js.map +1 -1
- package/lib/sync/range/batch.d.ts +6 -0
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +10 -0
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +50 -18
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +9 -5
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +88 -46
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/execution.d.ts +11 -11
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +6 -2
- package/lib/util/execution.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/blocks/index.ts +7 -4
- package/src/api/impl/beacon/pool/index.ts +4 -4
- package/src/chain/archiveStore/archiveStore.ts +10 -4
- package/src/chain/archiveStore/historicalState/getHistoricalState.ts +5 -7
- package/src/chain/archiveStore/historicalState/historicalStateRegen.ts +1 -1
- package/src/chain/archiveStore/historicalState/types.ts +2 -2
- package/src/chain/archiveStore/historicalState/worker.ts +1 -2
- package/src/chain/archiveStore/interface.ts +1 -1
- package/src/chain/archiveStore/utils/pruneHistory.ts +6 -4
- package/src/chain/blocks/importBlock.ts +4 -0
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +2 -1
- package/src/chain/blocks/verifyBlock.ts +1 -0
- package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +6 -3
- package/src/chain/chain.ts +18 -19
- package/src/chain/errors/envelopeReconstructionError.ts +3 -0
- package/src/chain/errors/gossipValidation.ts +2 -0
- package/src/chain/initState.ts +8 -60
- package/src/chain/interface.ts +2 -2
- package/src/chain/opPools/opPool.ts +91 -18
- package/src/chain/opPools/utils.ts +31 -3
- package/src/chain/options.ts +2 -2
- package/src/chain/prepareNextSlot.ts +6 -3
- package/src/chain/produceBlock/computeNewStateRoot.ts +1 -1
- package/src/chain/produceBlock/produceBlockBody.ts +8 -1
- package/src/chain/regen/regen.ts +12 -4
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +31 -13
- package/src/chain/validation/attesterSlashing.ts +7 -4
- package/src/chain/validation/proposerSlashing.ts +7 -4
- package/src/chain/validatorMonitor.ts +75 -57
- package/src/db/beacon.ts +2 -0
- package/src/db/repositories/proposerSlashing.ts +6 -1
- package/src/execution/engine/disabled.ts +0 -8
- package/src/execution/engine/http.ts +1 -30
- package/src/execution/engine/interface.ts +2 -6
- package/src/execution/engine/mock.ts +1 -19
- package/src/execution/engine/types.ts +0 -10
- package/src/index.ts +1 -1
- package/src/metrics/metrics.ts +21 -6
- package/src/network/processor/gossipHandlers.ts +7 -4
- package/src/network/processor/gossipValidatorFn.ts +13 -3
- package/src/network/processor/index.ts +89 -10
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +42 -28
- package/src/node/nodejs.ts +31 -3
- package/src/sync/range/batch.ts +11 -0
- package/src/sync/range/range.ts +50 -18
- package/src/sync/unknownBlock.ts +99 -50
- package/src/util/execution.ts +17 -9
|
@@ -17,7 +17,7 @@ export async function getNearestState(
|
|
|
17
17
|
slot: number,
|
|
18
18
|
config: BeaconConfig,
|
|
19
19
|
db: IBeaconDb,
|
|
20
|
-
|
|
20
|
+
nativeStateTransition: boolean
|
|
21
21
|
): Promise<IBeaconStateView> {
|
|
22
22
|
const stateBytesArr = await db.stateArchive.binaries({limit: 1, lte: slot, reverse: true});
|
|
23
23
|
if (!stateBytesArr.length) {
|
|
@@ -25,9 +25,7 @@ export async function getNearestState(
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const stateBytes = stateBytesArr[0];
|
|
28
|
-
return
|
|
29
|
-
? createBeaconStateViewForHistoricalRegen({useNative: true, stateBytes})
|
|
30
|
-
: createBeaconStateViewForHistoricalRegen({useNative: false, config, stateBytes});
|
|
28
|
+
return createBeaconStateViewForHistoricalRegen({nativeStateTransition: nativeStateTransition, config, stateBytes});
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
/**
|
|
@@ -37,13 +35,13 @@ export async function getHistoricalState(
|
|
|
37
35
|
slot: number,
|
|
38
36
|
config: BeaconConfig,
|
|
39
37
|
db: IBeaconDb,
|
|
40
|
-
|
|
38
|
+
nativeStateTransition: boolean,
|
|
41
39
|
metrics?: HistoricalStateRegenMetrics
|
|
42
40
|
): Promise<Uint8Array> {
|
|
43
41
|
const regenTimer = metrics?.regenTime.startTimer();
|
|
44
42
|
|
|
45
43
|
const loadStateTimer = metrics?.loadStateTime.startTimer();
|
|
46
|
-
let state = await getNearestState(slot, config, db,
|
|
44
|
+
let state = await getNearestState(slot, config, db, nativeStateTransition).catch((e) => {
|
|
47
45
|
metrics?.regenErrorCount.inc({reason: RegenErrorType.loadState});
|
|
48
46
|
throw e;
|
|
49
47
|
});
|
|
@@ -54,7 +52,7 @@ export async function getHistoricalState(
|
|
|
54
52
|
for await (const block of db.blockArchive.valuesStream({gt: state.slot, lte: slot})) {
|
|
55
53
|
try {
|
|
56
54
|
state = state.stateTransition(
|
|
57
|
-
block,
|
|
55
|
+
{block},
|
|
58
56
|
{
|
|
59
57
|
verifyProposer: false,
|
|
60
58
|
verifySignatures: false,
|
|
@@ -36,7 +36,7 @@ export class HistoricalStateRegen implements HistoricalStateWorkerApi {
|
|
|
36
36
|
dataColumnDir: modules.opts.dataColumnDir,
|
|
37
37
|
metricsEnabled: Boolean(modules.metrics),
|
|
38
38
|
loggerOpts: modules.logger.toOpts(),
|
|
39
|
-
|
|
39
|
+
nativeStateTransition: modules.opts.nativeStateTransition,
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
const worker = new Worker(path.join(WORKER_DIR, "worker.js"), {
|
|
@@ -8,7 +8,7 @@ export type HistoricalStateRegenInitModules = {
|
|
|
8
8
|
genesisTime: number;
|
|
9
9
|
dbLocation: string;
|
|
10
10
|
dataColumnDir: string;
|
|
11
|
-
|
|
11
|
+
nativeStateTransition: boolean;
|
|
12
12
|
};
|
|
13
13
|
config: BeaconConfig;
|
|
14
14
|
logger: LoggerNode;
|
|
@@ -29,7 +29,7 @@ export type HistoricalStateWorkerData = {
|
|
|
29
29
|
dataColumnDir: string;
|
|
30
30
|
metricsEnabled: boolean;
|
|
31
31
|
loggerOpts: LoggerNodeOpts;
|
|
32
|
-
|
|
32
|
+
nativeStateTransition: boolean;
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
export type HistoricalStateWorkerApi = {
|
|
@@ -36,7 +36,6 @@ const abortController = new AbortController();
|
|
|
36
36
|
const metricsRegister = workerData.metricsEnabled ? new RegistryMetricCreator() : null;
|
|
37
37
|
let historicalStateRegenMetrics: HistoricalStateRegenMetrics | undefined;
|
|
38
38
|
let queueMetrics: QueueMetrics | undefined;
|
|
39
|
-
|
|
40
39
|
if (metricsRegister) {
|
|
41
40
|
const closeMetrics = collectNodeJSMetrics(metricsRegister, "lodestar_historical_state_worker_");
|
|
42
41
|
abortController.signal.addEventListener("abort", closeMetrics, {once: true});
|
|
@@ -65,7 +64,7 @@ const api: HistoricalStateWorkerApi = {
|
|
|
65
64
|
historicalStateRegenMetrics?.regenRequestCount.inc();
|
|
66
65
|
|
|
67
66
|
const stateBytes = await queue.push<Uint8Array>(() =>
|
|
68
|
-
getHistoricalState(slot, config, db, workerData.
|
|
67
|
+
getHistoricalState(slot, config, db, workerData.nativeStateTransition, historicalStateRegenMetrics)
|
|
69
68
|
);
|
|
70
69
|
const result = Transfer(stateBytes, [stateBytes.buffer]) as unknown as Uint8Array;
|
|
71
70
|
|
|
@@ -11,8 +11,9 @@ export async function pruneHistory(
|
|
|
11
11
|
logger: Logger,
|
|
12
12
|
metrics: Metrics | null | undefined,
|
|
13
13
|
finalizedEpoch: Epoch,
|
|
14
|
-
currentEpoch: Epoch
|
|
15
|
-
|
|
14
|
+
currentEpoch: Epoch,
|
|
15
|
+
statePruneFromSlot: Slot = 0
|
|
16
|
+
): Promise<{blockCutoffSlot: Slot; stateCutoffSlot: Slot}> {
|
|
16
17
|
const blockCutoffEpoch = Math.min(
|
|
17
18
|
// set by config, with underflow protection
|
|
18
19
|
Math.max(currentEpoch - config.MIN_EPOCHS_FOR_BLOCK_REQUESTS, 0),
|
|
@@ -28,6 +29,7 @@ export async function pruneHistory(
|
|
|
28
29
|
currentEpoch,
|
|
29
30
|
finalizedEpoch,
|
|
30
31
|
blockCutoffEpoch,
|
|
32
|
+
statePruneFromSlot,
|
|
31
33
|
stateCutoffSlot,
|
|
32
34
|
});
|
|
33
35
|
|
|
@@ -35,7 +37,7 @@ export async function pruneHistory(
|
|
|
35
37
|
const [blocks, envelopes, states] = await Promise.all([
|
|
36
38
|
db.blockArchive.keys({gte: 0, lt: blockCutoffSlot}),
|
|
37
39
|
db.executionPayloadEnvelopeArchive.keys({gte: 0, lt: blockCutoffSlot}),
|
|
38
|
-
db.stateArchive.keys({gte:
|
|
40
|
+
stateCutoffSlot > statePruneFromSlot ? db.stateArchive.keys({gte: statePruneFromSlot, lt: stateCutoffSlot}) : [],
|
|
39
41
|
]);
|
|
40
42
|
step0?.();
|
|
41
43
|
|
|
@@ -64,5 +66,5 @@ export async function pruneHistory(
|
|
|
64
66
|
|
|
65
67
|
metrics?.pruneHistory.pruneCount.inc();
|
|
66
68
|
|
|
67
|
-
return blockCutoffSlot;
|
|
69
|
+
return {blockCutoffSlot, stateCutoffSlot};
|
|
68
70
|
}
|
|
@@ -538,6 +538,10 @@ export async function importBlock(
|
|
|
538
538
|
block: blockRootHex,
|
|
539
539
|
slot: blockSlot,
|
|
540
540
|
executionOptimistic: blockSummary != null && isOptimisticBlock(blockSummary),
|
|
541
|
+
...(isGloasBeaconBlock(block.message) && {
|
|
542
|
+
blockHash: toRootHex(block.message.body.signedExecutionPayloadBid.message.blockHash),
|
|
543
|
+
builderIndex: block.message.body.signedExecutionPayloadBid.message.builderIndex,
|
|
544
|
+
}),
|
|
541
545
|
});
|
|
542
546
|
}
|
|
543
547
|
if (this.emitter.listenerCount(routes.events.EventType.voluntaryExit)) {
|
|
@@ -22,8 +22,9 @@ export enum PayloadEnvelopeInputSource {
|
|
|
22
22
|
* - finalized: below the finalized slot
|
|
23
23
|
* - prune: explicit prune by root
|
|
24
24
|
* - cap: insertion-order backstop cap (MAX_PAYLOAD_ENVELOPE_INPUT_CACHE_SIZE)
|
|
25
|
+
* - invalid: the cached envelope failed import with a definitive invalid verdict
|
|
25
26
|
*/
|
|
26
|
-
export type PayloadEnvelopeInputPruneReason = "belowParent" | "finalized" | "remove" | "cap";
|
|
27
|
+
export type PayloadEnvelopeInputPruneReason = "belowParent" | "finalized" | "remove" | "cap" | "invalid";
|
|
27
28
|
|
|
28
29
|
export type SourceMeta = {
|
|
29
30
|
source: PayloadEnvelopeInputSource;
|
|
@@ -188,6 +188,7 @@ export async function verifyBlocksInEpoch(
|
|
|
188
188
|
blockInputs,
|
|
189
189
|
// hack availability for state transition eval as availability is separately determined
|
|
190
190
|
blocks.map(() => DataAvailabilityStatus.Available),
|
|
191
|
+
this.serializedCache,
|
|
191
192
|
this.logger,
|
|
192
193
|
this.metrics,
|
|
193
194
|
this.validatorMonitor,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import {ErrorAborted, Logger, byteArrayEquals} from "@lodestar/utils";
|
|
8
8
|
import {Metrics} from "../../metrics/index.js";
|
|
9
9
|
import {nextEventLoop} from "../../util/eventLoop.js";
|
|
10
|
+
import {SerializedCache} from "../../util/serializedCache.js";
|
|
10
11
|
import {BlockError, BlockErrorCode} from "../errors/index.js";
|
|
11
12
|
import {BlockProcessOpts} from "../options.js";
|
|
12
13
|
import {ValidatorMonitor} from "../validatorMonitor.js";
|
|
@@ -25,6 +26,7 @@ export async function verifyBlocksStateTransitionOnly(
|
|
|
25
26
|
preState0: IBeaconStateView,
|
|
26
27
|
blocks: IBlockInput[],
|
|
27
28
|
dataAvailabilityStatuses: DataAvailabilityStatus[],
|
|
29
|
+
serializedCache: SerializedCache,
|
|
28
30
|
logger: Logger,
|
|
29
31
|
metrics: Metrics | null,
|
|
30
32
|
validatorMonitor: ValidatorMonitor | null,
|
|
@@ -37,7 +39,8 @@ export async function verifyBlocksStateTransitionOnly(
|
|
|
37
39
|
|
|
38
40
|
for (let i = 0; i < blocks.length; i++) {
|
|
39
41
|
const {validProposerSignature, validSignatures} = opts;
|
|
40
|
-
const
|
|
42
|
+
const blockInput = blocks[i];
|
|
43
|
+
const block = blockInput.getBlock();
|
|
41
44
|
const preState = i === 0 ? preState0 : postStates[i - 1];
|
|
42
45
|
const dataAvailabilityStatus = dataAvailabilityStatuses[i];
|
|
43
46
|
|
|
@@ -47,7 +50,7 @@ export async function verifyBlocksStateTransitionOnly(
|
|
|
47
50
|
let postState: IBeaconStateView;
|
|
48
51
|
try {
|
|
49
52
|
postState = preState.stateTransition(
|
|
50
|
-
block,
|
|
53
|
+
{block, ssz: serializedCache.get(block)},
|
|
51
54
|
{
|
|
52
55
|
// NOTE: Assume valid for now while sending payload to execution engine in parallel
|
|
53
56
|
// Latter verifyBlocksInEpoch() will make sure that payload is indeed valid
|
|
@@ -60,7 +63,7 @@ export async function verifyBlocksStateTransitionOnly(
|
|
|
60
63
|
verifySignatures: !useBlsBatchVerify && !validSignatures,
|
|
61
64
|
dontTransferCache: false,
|
|
62
65
|
},
|
|
63
|
-
{metrics, validatorMonitor}
|
|
66
|
+
{metrics: metrics?.stateTransition, validatorMonitor}
|
|
64
67
|
);
|
|
65
68
|
} catch (e) {
|
|
66
69
|
throw new BlockError(block, {
|
package/src/chain/chain.ts
CHANGED
|
@@ -71,7 +71,7 @@ import {BufferPool} from "../util/bufferPool.js";
|
|
|
71
71
|
import {Clock, ClockEvent, IClock} from "../util/clock.js";
|
|
72
72
|
import {CustodyConfig, getValidatorsCustodyRequirement} from "../util/dataColumns.js";
|
|
73
73
|
import {callInNextEventLoop} from "../util/eventLoop.js";
|
|
74
|
-
import {
|
|
74
|
+
import {ReconstructMissPolicy, isRebuildMiss, reconstructExecutionPayloadEnvelopes} from "../util/execution.js";
|
|
75
75
|
import {ensureDir, writeIfNotExist} from "../util/file.js";
|
|
76
76
|
import {isOptimisticBlock} from "../util/forkChoice.js";
|
|
77
77
|
import {JobItemQueue} from "../util/queue/itemQueue.js";
|
|
@@ -432,6 +432,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
432
432
|
blockStateCache,
|
|
433
433
|
checkpointStateCache,
|
|
434
434
|
seenBlockInputCache: this.seenBlockInputCache,
|
|
435
|
+
serializedCache: this.serializedCache,
|
|
435
436
|
db,
|
|
436
437
|
metrics,
|
|
437
438
|
validatorMonitor,
|
|
@@ -611,7 +612,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
611
612
|
/** Populate in-memory caches with persisted data. Call at least once on startup */
|
|
612
613
|
async loadFromDisk(): Promise<void> {
|
|
613
614
|
await this.regen.init();
|
|
614
|
-
await this.opPool.fromPersisted(this.db);
|
|
615
|
+
await this.opPool.fromPersisted(this.db, this.getHeadState(), this.bls, this.clock.currentSlot);
|
|
615
616
|
}
|
|
616
617
|
|
|
617
618
|
/** Persist in-memory data to the DB. Call at least once before stopping the process */
|
|
@@ -934,12 +935,13 @@ export class BeaconChain implements IBeaconChain {
|
|
|
934
935
|
|
|
935
936
|
/**
|
|
936
937
|
* Batch variant: archived header envelopes are rebuilt 32 per EL round-trip. Aligned with `requests`.
|
|
937
|
-
*
|
|
938
|
-
* returns null for that entry, for
|
|
938
|
+
* An archived envelope that cannot be rebuilt (EL-unavailable body or body root mismatch) is not the
|
|
939
|
+
* same as an unknown one: `"throw"` surfaces it, `"omit"` returns null for that entry, for
|
|
940
|
+
* peer-facing paths where the spec allows omission.
|
|
939
941
|
*/
|
|
940
942
|
async getSerializedExecutionPayloadEnvelopes(
|
|
941
943
|
requests: {blockSlot: Slot; blockRootHex: RootHex}[],
|
|
942
|
-
|
|
944
|
+
onMiss: ReconstructMissPolicy = "throw"
|
|
943
945
|
): Promise<(Uint8Array | null)[]> {
|
|
944
946
|
const out: (Uint8Array | null)[] = new Array(requests.length).fill(null);
|
|
945
947
|
const headerEnvelopes: gloas.SignedExecutionPayloadHeaderEnvelope[] = [];
|
|
@@ -978,14 +980,14 @@ export class BeaconChain implements IBeaconChain {
|
|
|
978
980
|
for (let j = 0; j < rebuilt.length; j++) {
|
|
979
981
|
const result = rebuilt[j];
|
|
980
982
|
if (isRebuildMiss(result)) {
|
|
981
|
-
if (
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
"Archived envelope failed body root check against EL bodies"
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
983
|
+
if (onMiss === "throw") throw result.error;
|
|
984
|
+
this.logger.debug(
|
|
985
|
+
result.reason === "mismatch"
|
|
986
|
+
? "Archived envelope failed body root check against EL bodies"
|
|
987
|
+
: "EL cannot serve bodies for archived envelope, omitting",
|
|
988
|
+
{slot: result.slot},
|
|
989
|
+
result.error
|
|
990
|
+
);
|
|
989
991
|
continue;
|
|
990
992
|
}
|
|
991
993
|
out[headerEnvelopeIdxs[j]] = ssz.gloas.SignedExecutionPayloadEnvelope.serialize(result);
|
|
@@ -1016,10 +1018,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1016
1018
|
const [result] = await reconstructExecutionPayloadEnvelopes(this.executionEngine, this.metrics, [
|
|
1017
1019
|
archived.headerEnvelope,
|
|
1018
1020
|
]);
|
|
1019
|
-
if (isRebuildMiss(result))
|
|
1020
|
-
if (result.reason === "mismatch") throw result.error;
|
|
1021
|
-
return null;
|
|
1022
|
-
}
|
|
1021
|
+
if (isRebuildMiss(result)) throw result.error;
|
|
1023
1022
|
return result;
|
|
1024
1023
|
}
|
|
1025
1024
|
|
|
@@ -1329,13 +1328,13 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1329
1328
|
};
|
|
1330
1329
|
|
|
1331
1330
|
try {
|
|
1332
|
-
await validateApiProposerSlashing(this, proposerSlashing);
|
|
1331
|
+
const verifiedDomain = await validateApiProposerSlashing(this, proposerSlashing);
|
|
1332
|
+
this.opPool.insertProposerSlashing(proposerSlashing, verifiedDomain);
|
|
1333
1333
|
} catch (e) {
|
|
1334
1334
|
this.logger.debug("Produced proposer slashing is not valid", {slot: blockSlot, proposerIndex}, e as Error);
|
|
1335
1335
|
return;
|
|
1336
1336
|
}
|
|
1337
1337
|
|
|
1338
|
-
this.opPool.insertProposerSlashing(proposerSlashing);
|
|
1339
1338
|
this.emitter.emit(routes.events.EventType.proposerSlashing, proposerSlashing);
|
|
1340
1339
|
this.emitter.emit(ChainEvent.publishProposerSlashing, proposerSlashing);
|
|
1341
1340
|
this.metrics?.opPool.proposerSlashingsProduced.inc();
|
|
@@ -4,6 +4,8 @@ import {LodestarError} from "@lodestar/utils";
|
|
|
4
4
|
export enum EnvelopeReconstructionErrorCode {
|
|
5
5
|
/** The EL failed to answer engine_getPayloadBodiesByHashV2 (transport / EL down). Transient. */
|
|
6
6
|
ENGINE_UNAVAILABLE = "ENVELOPE_RECONSTRUCTION_ERROR_ENGINE_UNAVAILABLE",
|
|
7
|
+
/** The EL does not have the block or its block access list (pruned, or not yet re-indexed after a restart). May recover. */
|
|
8
|
+
BODY_UNAVAILABLE = "ENVELOPE_RECONSTRUCTION_ERROR_BODY_UNAVAILABLE",
|
|
7
9
|
/** A body returned by the EL does not hash to the root stored in the header envelope. Local DB/EL inconsistency. */
|
|
8
10
|
BODY_ROOT_MISMATCH = "ENVELOPE_RECONSTRUCTION_ERROR_BODY_ROOT_MISMATCH",
|
|
9
11
|
/** A by-range stream stopped short at a slot that cannot be served; the response so far is still valid */
|
|
@@ -12,6 +14,7 @@ export enum EnvelopeReconstructionErrorCode {
|
|
|
12
14
|
|
|
13
15
|
export type EnvelopeReconstructionErrorType =
|
|
14
16
|
| {code: EnvelopeReconstructionErrorCode.ENGINE_UNAVAILABLE}
|
|
17
|
+
| {code: EnvelopeReconstructionErrorCode.BODY_UNAVAILABLE; slot: Slot}
|
|
15
18
|
| {
|
|
16
19
|
code: EnvelopeReconstructionErrorCode.BODY_ROOT_MISMATCH;
|
|
17
20
|
slot: Slot;
|
|
@@ -9,6 +9,8 @@ export enum GossipErrorCode {
|
|
|
9
9
|
INVALID_SERIALIZED_BYTES_ERROR_CODE = "GOSSIP_ERROR_INVALID_SERIALIZED_BYTES",
|
|
10
10
|
PAST_SLOT = "GOSSIP_ERROR_PAST_SLOT",
|
|
11
11
|
FUTURE_SLOT = "GOSSIP_ERROR_FUTURE_SLOT",
|
|
12
|
+
FATAL_PEER = "GOSSIP_ERROR_FATAL_PEER",
|
|
13
|
+
INVALID_SLOT = "GOSSIP_ERROR_INVALID_SLOT",
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export class GossipActionError<T extends {code: string}> extends LodestarError<T> {
|
package/src/chain/initState.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
2
|
import {ForkPostGloas, ForkSeq, ZERO_HASH} from "@lodestar/params";
|
|
3
|
-
import {
|
|
4
|
-
BeaconStateAllForks,
|
|
5
|
-
BeaconStateGloas,
|
|
6
|
-
IBeaconStateView,
|
|
7
|
-
computeEpochAtSlot,
|
|
8
|
-
computeStartSlotAtEpoch,
|
|
9
|
-
} from "@lodestar/state-transition";
|
|
3
|
+
import {BeaconStateAllForks, IBeaconStateView, computeEpochAtSlot, isStatePostGloas} from "@lodestar/state-transition";
|
|
10
4
|
import {SignedBeaconBlock, ssz} from "@lodestar/types";
|
|
11
|
-
import {Logger, byteArrayEquals,
|
|
5
|
+
import {LodestarError, Logger, byteArrayEquals, toRootHex} from "@lodestar/utils";
|
|
12
6
|
import {GENESIS_SLOT} from "../constants/index.js";
|
|
13
7
|
import {IBeaconDb} from "../db/index.js";
|
|
14
8
|
import {Metrics} from "../metrics/index.js";
|
|
@@ -17,7 +11,7 @@ import {getStateTypeFromBytes} from "../util/multifork.js";
|
|
|
17
11
|
export async function persistAnchorState(
|
|
18
12
|
config: ChainForkConfig,
|
|
19
13
|
db: IBeaconDb,
|
|
20
|
-
anchorState:
|
|
14
|
+
anchorState: IBeaconStateView,
|
|
21
15
|
anchorStateBytes: Uint8Array
|
|
22
16
|
): Promise<void> {
|
|
23
17
|
if (anchorState.slot === GENESIS_SLOT) {
|
|
@@ -33,7 +27,8 @@ export async function persistAnchorState(
|
|
|
33
27
|
const latestBlockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(latestBlockHeader);
|
|
34
28
|
|
|
35
29
|
if (!byteArrayEquals(blockRoot, latestBlockRoot)) {
|
|
36
|
-
throw
|
|
30
|
+
throw new LodestarError(
|
|
31
|
+
{code: "GENESIS_BLOCK_ROOT_MISMATCH"},
|
|
37
32
|
`Genesis block root ${toRootHex(blockRoot)} does not match genesis state latest block root ${toRootHex(latestBlockRoot)}`
|
|
38
33
|
);
|
|
39
34
|
}
|
|
@@ -48,16 +43,15 @@ export async function persistAnchorState(
|
|
|
48
43
|
}
|
|
49
44
|
}
|
|
50
45
|
|
|
51
|
-
export function createGenesisBlock(config: ChainForkConfig, genesisState:
|
|
46
|
+
export function createGenesisBlock(config: ChainForkConfig, genesisState: IBeaconStateView): SignedBeaconBlock {
|
|
52
47
|
const types = config.getForkTypes(GENESIS_SLOT);
|
|
53
48
|
const genesisBlock = types.SignedBeaconBlock.defaultValue();
|
|
54
49
|
const stateRoot = genesisState.hashTreeRoot();
|
|
55
50
|
genesisBlock.message.stateRoot = stateRoot;
|
|
56
51
|
|
|
57
|
-
if (config.getForkSeq(GENESIS_SLOT) >= ForkSeq.gloas) {
|
|
52
|
+
if (config.getForkSeq(GENESIS_SLOT) >= ForkSeq.gloas && isStatePostGloas(genesisState)) {
|
|
58
53
|
const gloasBlock = genesisBlock as SignedBeaconBlock<ForkPostGloas>;
|
|
59
|
-
|
|
60
|
-
gloasBlock.message.body.signedExecutionPayloadBid.message = gloasState.latestExecutionPayloadBid.toValue();
|
|
54
|
+
gloasBlock.message.body.signedExecutionPayloadBid.message = genesisState.latestExecutionPayloadBid;
|
|
61
55
|
}
|
|
62
56
|
|
|
63
57
|
return genesisBlock;
|
|
@@ -86,52 +80,6 @@ export async function initStateFromDb(
|
|
|
86
80
|
return state;
|
|
87
81
|
}
|
|
88
82
|
|
|
89
|
-
/**
|
|
90
|
-
* Initialize and persist an anchor state (either weak subjectivity or genesis)
|
|
91
|
-
*/
|
|
92
|
-
export async function checkAndPersistAnchorState(
|
|
93
|
-
config: ChainForkConfig,
|
|
94
|
-
db: IBeaconDb,
|
|
95
|
-
logger: Logger,
|
|
96
|
-
anchorState: BeaconStateAllForks,
|
|
97
|
-
anchorStateBytes: Uint8Array,
|
|
98
|
-
{
|
|
99
|
-
isWithinWeakSubjectivityPeriod,
|
|
100
|
-
isCheckpointState,
|
|
101
|
-
}: {isWithinWeakSubjectivityPeriod: boolean; isCheckpointState: boolean}
|
|
102
|
-
): Promise<void> {
|
|
103
|
-
const expectedFork = config.getForkInfo(computeStartSlotAtEpoch(anchorState.fork.epoch));
|
|
104
|
-
const expectedForkVersion = toHex(expectedFork.version);
|
|
105
|
-
const stateFork = toHex(anchorState.fork.currentVersion);
|
|
106
|
-
if (stateFork !== expectedForkVersion) {
|
|
107
|
-
throw Error(
|
|
108
|
-
`State current fork version ${stateFork} not equal to current config ${expectedForkVersion}. Maybe caused by importing a state from a different network`
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const stateInfo = isCheckpointState ? "checkpoint" : "db";
|
|
113
|
-
if (isWithinWeakSubjectivityPeriod) {
|
|
114
|
-
logger.info(`Initializing beacon from a valid ${stateInfo} state`, {
|
|
115
|
-
slot: anchorState.slot,
|
|
116
|
-
epoch: computeEpochAtSlot(anchorState.slot),
|
|
117
|
-
stateRoot: toRootHex(anchorState.hashTreeRoot()),
|
|
118
|
-
isWithinWeakSubjectivityPeriod,
|
|
119
|
-
});
|
|
120
|
-
} else {
|
|
121
|
-
logger.warn(`Initializing from a stale ${stateInfo} state vulnerable to long range attacks`, {
|
|
122
|
-
slot: anchorState.slot,
|
|
123
|
-
epoch: computeEpochAtSlot(anchorState.slot),
|
|
124
|
-
stateRoot: toRootHex(anchorState.hashTreeRoot()),
|
|
125
|
-
isWithinWeakSubjectivityPeriod,
|
|
126
|
-
});
|
|
127
|
-
logger.warn("Checkpoint sync recommended, please use --help to see checkpoint sync options");
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (isCheckpointState || anchorState.slot === GENESIS_SLOT) {
|
|
131
|
-
await persistAnchorState(config, db, anchorState, anchorStateBytes);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
83
|
export function initBeaconMetrics(metrics: Metrics, state: IBeaconStateView): void {
|
|
136
84
|
metrics.headSlot.set(state.slot);
|
|
137
85
|
metrics.previousJustifiedEpoch.set(state.previousJustifiedCheckpoint.epoch);
|
package/src/chain/interface.ts
CHANGED
|
@@ -30,7 +30,7 @@ import {Metrics} from "../metrics/metrics.js";
|
|
|
30
30
|
import {BufferPool} from "../util/bufferPool.js";
|
|
31
31
|
import {IClock} from "../util/clock.js";
|
|
32
32
|
import {CustodyConfig} from "../util/dataColumns.js";
|
|
33
|
-
import {
|
|
33
|
+
import {ReconstructMissPolicy} from "../util/execution.js";
|
|
34
34
|
import {SerializedCache} from "../util/serializedCache.js";
|
|
35
35
|
import {IArchiveStore} from "./archiveStore/interface.js";
|
|
36
36
|
import {CheckpointBalancesCache} from "./balancesCache.js";
|
|
@@ -239,7 +239,7 @@ export interface IBeaconChain {
|
|
|
239
239
|
getSerializedExecutionPayloadEnvelope(blockSlot: Slot, blockRootHex: string): Promise<Uint8Array | null>;
|
|
240
240
|
getSerializedExecutionPayloadEnvelopes(
|
|
241
241
|
requests: {blockSlot: Slot; blockRootHex: RootHex}[],
|
|
242
|
-
|
|
242
|
+
onMiss?: ReconstructMissPolicy
|
|
243
243
|
): Promise<(Uint8Array | null)[]>;
|
|
244
244
|
getExecutionPayloadEnvelope(
|
|
245
245
|
blockSlot: Slot,
|