@lodestar/beacon-node 1.50.0-dev.cddd01a6c6 → 1.50.0-dev.ce0e732118
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/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/index.js +13 -0
- package/lib/api/impl/beacon/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts +1 -0
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +17 -1
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +1 -1
- 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/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 +1 -0
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +29 -0
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +7 -1
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js +5 -0
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +2 -0
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts +4 -4
- package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.js +14 -11
- package/lib/chain/opPools/proposerPreferencesPool.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/produceBlock/computeNewStateRoot.js +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.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/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/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/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/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +5 -1
- package/lib/sync/range/chain.js.map +1 -1
- package/package.json +16 -16
- package/src/api/impl/beacon/index.ts +15 -0
- package/src/api/impl/validator/index.ts +16 -2
- package/src/chain/archiveStore/archiveStore.ts +1 -1
- 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/blocks/verifyBlock.ts +1 -0
- package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +6 -3
- package/src/chain/chain.ts +33 -0
- package/src/chain/emitter.ts +7 -1
- package/src/chain/forkChoice/index.ts +2 -0
- package/src/chain/opPools/proposerPreferencesPool.ts +14 -10
- package/src/chain/options.ts +2 -2
- package/src/chain/produceBlock/computeNewStateRoot.ts +1 -1
- package/src/chain/regen/regen.ts +12 -4
- package/src/chain/validatorMonitor.ts +75 -57
- package/src/metrics/metrics.ts +21 -6
- package/src/node/nodejs.ts +31 -3
- package/src/sync/range/chain.ts +6 -1
|
@@ -189,6 +189,7 @@ export enum EngineBlockSelectionReason {
|
|
|
189
189
|
BuilderTimeout = "builder_timeout",
|
|
190
190
|
BuilderPending = "builder_pending",
|
|
191
191
|
BuilderNoBid = "builder_no_bid",
|
|
192
|
+
BuilderCircuitBreaker = "builder_circuit_breaker",
|
|
192
193
|
BuilderCensorship = "builder_censorship",
|
|
193
194
|
BlockValue = "block_value",
|
|
194
195
|
EnginePreferred = "engine_preferred",
|
|
@@ -1160,8 +1161,21 @@ export function getValidatorApi(
|
|
|
1160
1161
|
: {}),
|
|
1161
1162
|
};
|
|
1162
1163
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1164
|
+
if (circuitBreakerActive && engineResult.status === "fulfilled") {
|
|
1165
|
+
source = ProducedBlockSource.engine;
|
|
1166
|
+
bestResult = engineResult;
|
|
1167
|
+
metrics?.blockProductionSelectionResults.inc({
|
|
1168
|
+
source: ProducedBlockSource.engine,
|
|
1169
|
+
reason: EngineBlockSelectionReason.BuilderCircuitBreaker,
|
|
1170
|
+
});
|
|
1171
|
+
logger.info("Selected local block: builder circuit breaker is active", {
|
|
1172
|
+
reason: EngineBlockSelectionReason.BuilderCircuitBreaker,
|
|
1173
|
+
...logCtx,
|
|
1174
|
+
durationMs: engineResult.durationMs,
|
|
1175
|
+
...getBlockValueLogInfo(engineResult.value),
|
|
1176
|
+
});
|
|
1177
|
+
} else if (
|
|
1178
|
+
// handle shouldOverrideBuilder separately
|
|
1165
1179
|
engineResult.status === "fulfilled" &&
|
|
1166
1180
|
engineResult.value.shouldOverrideBuilder &&
|
|
1167
1181
|
(builderBidExpected || bidBlockResult.status === "fulfilled")
|
|
@@ -148,7 +148,7 @@ export class ArchiveStore {
|
|
|
148
148
|
genesisTime: this.chain.clock.genesisTime,
|
|
149
149
|
dbLocation: this.opts.dbName,
|
|
150
150
|
dataColumnDir: this.opts.dataColumnDir,
|
|
151
|
-
|
|
151
|
+
nativeStateTransition: this.opts.nativeStateTransition ?? false,
|
|
152
152
|
},
|
|
153
153
|
config: this.chain.config,
|
|
154
154
|
metrics: this.metrics,
|
|
@@ -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
|
|
|
@@ -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
|
@@ -244,6 +244,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
244
244
|
protected readonly blockProcessor: BlockProcessor;
|
|
245
245
|
protected readonly payloadEnvelopeProcessor: PayloadEnvelopeProcessor;
|
|
246
246
|
protected readonly db: IBeaconDb;
|
|
247
|
+
private genesisStateRoot?: RootHex | null;
|
|
247
248
|
// this is only available if nHistoricalStates is enabled
|
|
248
249
|
private readonly cpStateDatastore?: CPStateDatastore;
|
|
249
250
|
private abortController = new AbortController();
|
|
@@ -432,6 +433,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
432
433
|
blockStateCache,
|
|
433
434
|
checkpointStateCache,
|
|
434
435
|
seenBlockInputCache: this.seenBlockInputCache,
|
|
436
|
+
serializedCache: this.serializedCache,
|
|
435
437
|
db,
|
|
436
438
|
metrics,
|
|
437
439
|
validatorMonitor,
|
|
@@ -702,6 +704,37 @@ export class BeaconChain implements IBeaconChain {
|
|
|
702
704
|
stateRoot: RootHex,
|
|
703
705
|
opts?: StateGetOpts
|
|
704
706
|
): Promise<{state: IBeaconStateView | Uint8Array; executionOptimistic: boolean; finalized: boolean} | null> {
|
|
707
|
+
const finalizedBlock = this.forkChoice.getFinalizedBlock();
|
|
708
|
+
const finalizedCheckpoint = this.forkChoice.getFinalizedCheckpoint();
|
|
709
|
+
// Checkpoint state only equals the block post-state if the block is at the epoch start slot
|
|
710
|
+
if (
|
|
711
|
+
finalizedBlock.stateRoot === stateRoot &&
|
|
712
|
+
finalizedBlock.slot === computeStartSlotAtEpoch(finalizedCheckpoint.epoch)
|
|
713
|
+
) {
|
|
714
|
+
const state = this.regen.getCheckpointStateSync({
|
|
715
|
+
epoch: finalizedCheckpoint.epoch,
|
|
716
|
+
rootHex: finalizedCheckpoint.rootHex,
|
|
717
|
+
});
|
|
718
|
+
if (state) {
|
|
719
|
+
return {
|
|
720
|
+
state,
|
|
721
|
+
executionOptimistic: isOptimisticBlock(finalizedBlock),
|
|
722
|
+
finalized: finalizedCheckpoint.epoch !== GENESIS_EPOCH,
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
if (this.genesisStateRoot === undefined) {
|
|
728
|
+
const genesisBlock = await this.db.blockArchive.get(GENESIS_SLOT);
|
|
729
|
+
this.genesisStateRoot = genesisBlock ? toRootHex(genesisBlock.message.stateRoot) : null;
|
|
730
|
+
}
|
|
731
|
+
if (this.genesisStateRoot === stateRoot) {
|
|
732
|
+
const state = await this.db.stateArchive.getBinary(GENESIS_SLOT);
|
|
733
|
+
if (state) {
|
|
734
|
+
return {state, executionOptimistic: false, finalized: finalizedCheckpoint.epoch !== GENESIS_EPOCH};
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
705
738
|
if (opts?.allowRegen) {
|
|
706
739
|
const state = await this.regen.getState(stateRoot, RegenCaller.restApi);
|
|
707
740
|
const block = this.forkChoice.getBlockDefaultStatus(
|
package/src/chain/emitter.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {EventEmitter} from "node:events";
|
|
2
2
|
import {StrictEventEmitter} from "strict-event-emitter-types";
|
|
3
3
|
import {routes} from "@lodestar/api";
|
|
4
|
-
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
4
|
+
import {CheckpointWithHex, PtcQuorumEvent} from "@lodestar/fork-choice";
|
|
5
5
|
import {IBeaconStateView} from "@lodestar/state-transition";
|
|
6
6
|
import {DataColumnSidecar, RootHex, Slot, deneb, phase0} from "@lodestar/types";
|
|
7
7
|
import {PeerIdStr} from "../util/peerId.js";
|
|
@@ -36,6 +36,11 @@ export enum ChainEvent {
|
|
|
36
36
|
* This event is guaranteed to be triggered whenever the fork choice finalized checkpoint is updated. This is either in response to a newly processed block or a new clock tick.
|
|
37
37
|
*/
|
|
38
38
|
forkChoiceFinalized = "forkChoice:finalized",
|
|
39
|
+
/**
|
|
40
|
+
* This event signals that the PTC verdict on a block was decided: a majority against payload presence or blob data
|
|
41
|
+
* availability, or a majority for both.
|
|
42
|
+
*/
|
|
43
|
+
forkChoicePtcQuorum = "forkChoice:ptcQuorum",
|
|
39
44
|
/**
|
|
40
45
|
* This event signals that dependent services (e.g. custody sampling) should update to account for the new target group count.
|
|
41
46
|
*/
|
|
@@ -112,6 +117,7 @@ export type IChainEvents = ApiEvents & {
|
|
|
112
117
|
|
|
113
118
|
[ChainEvent.forkChoiceJustified]: (checkpoint: CheckpointWithHex) => void;
|
|
114
119
|
[ChainEvent.forkChoiceFinalized]: (checkpoint: CheckpointWithHex) => void;
|
|
120
|
+
[ChainEvent.forkChoicePtcQuorum]: (data: PtcQuorumEvent) => void;
|
|
115
121
|
|
|
116
122
|
[ChainEvent.updateTargetCustodyGroupCount]: (targetGroupCount: number) => void;
|
|
117
123
|
|
|
@@ -124,6 +124,7 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
124
124
|
onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
|
|
125
125
|
onFastConfirmation: ({block, slot, currentSlot}) =>
|
|
126
126
|
emitter.emit(routes.events.EventType.fastConfirmation, {block, slot, currentSlot}),
|
|
127
|
+
onPtcQuorum: (data) => emitter.emit(ChainEvent.forkChoicePtcQuorum, data),
|
|
127
128
|
}
|
|
128
129
|
),
|
|
129
130
|
|
|
@@ -222,6 +223,7 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
222
223
|
onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
|
|
223
224
|
onFastConfirmation: ({block, slot, currentSlot}) =>
|
|
224
225
|
emitter.emit(routes.events.EventType.fastConfirmation, {block, slot, currentSlot}),
|
|
226
|
+
onPtcQuorum: (data) => emitter.emit(ChainEvent.forkChoicePtcQuorum, data),
|
|
225
227
|
}
|
|
226
228
|
);
|
|
227
229
|
|
|
@@ -6,8 +6,8 @@ import {toRootHex} from "@lodestar/utils";
|
|
|
6
6
|
*
|
|
7
7
|
* The primary consumer is `validateExecutionPayloadBid`, which looks up the matching
|
|
8
8
|
* preferences via `get(bid.slot, dependent_root)` to enforce the IGNORE-existence and
|
|
9
|
-
* REJECT-equality rules from the gloas spec. The beacon API
|
|
10
|
-
*
|
|
9
|
+
* REJECT-equality rules from the gloas spec. The beacon API `getProposerPreferences`
|
|
10
|
+
* endpoint reads from the same pool via `getAll`.
|
|
11
11
|
*
|
|
12
12
|
* `validator_index` is intentionally not part of the key: gossip validation enforces
|
|
13
13
|
* `proposers[proposalSlot % SLOTS_PER_EPOCH] === validatorIndex` against the shuffling
|
|
@@ -37,15 +37,19 @@ export class ProposerPreferencesPool {
|
|
|
37
37
|
byRoot.set(rootHex, signed);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
/** API read-out: flatten across branches, optionally filtered by slot. */
|
|
41
|
-
getAll(slot?: Slot): gloas.SignedProposerPreferences[] {
|
|
42
|
-
if (slot !== undefined) {
|
|
43
|
-
const byRoot = this.bySlot.get(slot);
|
|
44
|
-
return byRoot ? Array.from(byRoot.values()) : [];
|
|
45
|
-
}
|
|
40
|
+
/** API read-out: flatten across branches, optionally filtered by slot and dependent root. */
|
|
41
|
+
getAll(slot?: Slot, dependentRootHex?: RootHex): gloas.SignedProposerPreferences[] {
|
|
46
42
|
const out: gloas.SignedProposerPreferences[] = [];
|
|
47
|
-
for (const byRoot of this.bySlot
|
|
48
|
-
|
|
43
|
+
for (const [s, byRoot] of this.bySlot) {
|
|
44
|
+
if (slot !== undefined && s !== slot) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
for (const [root, signed] of byRoot) {
|
|
48
|
+
if (dependentRootHex !== undefined && root !== dependentRootHex) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
out.push(signed);
|
|
52
|
+
}
|
|
49
53
|
}
|
|
50
54
|
return out;
|
|
51
55
|
}
|
package/src/chain/options.ts
CHANGED
|
@@ -52,7 +52,7 @@ export type IChainOptions = BlockProcessOpts &
|
|
|
52
52
|
minSameMessageSignatureSetsToBatch: number;
|
|
53
53
|
archiveDateEpochs?: number;
|
|
54
54
|
nHistoricalStatesFileDataStore?: boolean;
|
|
55
|
-
|
|
55
|
+
nativeStateTransition?: boolean;
|
|
56
56
|
/** Builder circuit breaker fault inspection window in slots */
|
|
57
57
|
faultInspectionWindow?: number;
|
|
58
58
|
/** Canonical EMPTY blocks allowed per `faultInspectionWindow` observed blocks */
|
|
@@ -131,7 +131,7 @@ export const defaultChainOptions: IChainOptions = {
|
|
|
131
131
|
// - users can prune the persisted checkpoint state files manually to save disc space
|
|
132
132
|
// - it helps debug easier when network is unfinalized
|
|
133
133
|
nHistoricalStatesFileDataStore: true,
|
|
134
|
-
|
|
134
|
+
nativeStateTransition: false,
|
|
135
135
|
maxBlockStates: DEFAULT_MAX_BLOCK_STATES,
|
|
136
136
|
maxCPStateEpochsInMemory: DEFAULT_MAX_CP_STATE_EPOCHS_IN_MEMORY,
|
|
137
137
|
maxCPStateEpochsOnDisk: DEFAULT_MAX_CP_STATE_ON_DISK,
|
|
@@ -16,7 +16,7 @@ export function computeNewStateRoot(
|
|
|
16
16
|
const signedBlock = {message: block, signature: EMPTY_SIGNATURE};
|
|
17
17
|
const {newStateRoot, proposerReward, postState, hashTreeRootTime} = state.computeNewStateRoot(
|
|
18
18
|
{block: signedBlock},
|
|
19
|
-
{metrics}
|
|
19
|
+
{metrics: metrics?.stateTransition}
|
|
20
20
|
);
|
|
21
21
|
|
|
22
22
|
metrics?.stateHashTreeRootTime.observe({source: StateHashTreeRootSource.computeNewStateRoot}, hashTreeRootTime);
|
package/src/chain/regen/regen.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {Logger, fromHex, toRootHex} from "@lodestar/utils";
|
|
|
14
14
|
import {IBeaconDb} from "../../db/index.js";
|
|
15
15
|
import {Metrics} from "../../metrics/index.js";
|
|
16
16
|
import {nextEventLoop} from "../../util/eventLoop.js";
|
|
17
|
+
import {SerializedCache} from "../../util/serializedCache.js";
|
|
17
18
|
import {getCheckpointFromState} from "../blocks/utils/checkpoint.js";
|
|
18
19
|
import {ChainEvent, ChainEventEmitter} from "../emitter.js";
|
|
19
20
|
import {SeenBlockInput} from "../seenCache/seenGossipBlockInput.js";
|
|
@@ -28,6 +29,7 @@ export type RegenModules = {
|
|
|
28
29
|
blockStateCache: BlockStateCache;
|
|
29
30
|
checkpointStateCache: CheckpointStateCache;
|
|
30
31
|
seenBlockInputCache: SeenBlockInput;
|
|
32
|
+
serializedCache: SerializedCache;
|
|
31
33
|
config: ChainForkConfig;
|
|
32
34
|
emitter: ChainEventEmitter;
|
|
33
35
|
logger: Logger;
|
|
@@ -235,7 +237,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
235
237
|
// We are only running the state transition to get a specific state's data.
|
|
236
238
|
// stateTransition() does the clone() inside, transfer cache to make the regen faster
|
|
237
239
|
state = state.stateTransition(
|
|
238
|
-
block,
|
|
240
|
+
{block, ssz: this.modules.serializedCache.get(block)},
|
|
239
241
|
{
|
|
240
242
|
// Replay previously imported blocks, assume valid and available
|
|
241
243
|
executionPayloadStatus: ExecutionPayloadStatus.valid,
|
|
@@ -245,7 +247,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
|
|
|
245
247
|
verifySignatures: false,
|
|
246
248
|
dontTransferCache: false,
|
|
247
249
|
},
|
|
248
|
-
this.modules
|
|
250
|
+
{metrics: this.modules.metrics?.stateTransition, validatorMonitor: this.modules.validatorMonitor}
|
|
249
251
|
);
|
|
250
252
|
|
|
251
253
|
const hashTreeRootTimer = this.modules.metrics?.stateHashTreeRootTime.startTimer({
|
|
@@ -316,7 +318,10 @@ async function processSlotsByCheckpoint(
|
|
|
316
318
|
): Promise<IBeaconStateView> {
|
|
317
319
|
let postState = await processSlotsToNearestCheckpoint(modules, preState, slot, regenCaller, opts);
|
|
318
320
|
if (postState.slot < slot) {
|
|
319
|
-
postState = postState.processSlots(slot, opts,
|
|
321
|
+
postState = postState.processSlots(slot, opts, {
|
|
322
|
+
metrics: modules.metrics?.stateTransition,
|
|
323
|
+
validatorMonitor: modules.validatorMonitor,
|
|
324
|
+
});
|
|
320
325
|
}
|
|
321
326
|
return postState;
|
|
322
327
|
}
|
|
@@ -361,7 +366,10 @@ export async function processSlotsToNearestCheckpoint(
|
|
|
361
366
|
caller: regenCaller,
|
|
362
367
|
});
|
|
363
368
|
// processSlots calls .clone() before mutating
|
|
364
|
-
postState = postState.processSlots(nextEpochSlot, opts,
|
|
369
|
+
postState = postState.processSlots(nextEpochSlot, opts, {
|
|
370
|
+
metrics: metrics?.stateTransition,
|
|
371
|
+
validatorMonitor: modules.validatorMonitor,
|
|
372
|
+
});
|
|
365
373
|
metrics?.epochTransitionByCaller.inc({caller: regenCaller});
|
|
366
374
|
|
|
367
375
|
// this is usually added when we prepare for next slot or validate gossip block
|