@lodestar/beacon-node 1.44.0-dev.552cdce8d0 → 1.44.0-dev.5a822af737
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 +50 -29
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +1 -26
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/config/constants.d.ts +1 -0
- package/lib/api/impl/config/constants.d.ts.map +1 -1
- package/lib/api/impl/config/constants.js +2 -1
- package/lib/api/impl/config/constants.js.map +1 -1
- package/lib/api/impl/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +69 -12
- package/lib/api/impl/debug/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.d.ts.map +1 -1
- package/lib/api/impl/lodestar/index.js +28 -0
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +121 -69
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +0 -1
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +0 -4
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +5 -2
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +5 -3
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
- package/lib/chain/chain.d.ts +1 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +10 -2
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +2 -1
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +0 -7
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +0 -3
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +17 -1
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +3 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/errors/payloadAttestation.d.ts +6 -0
- package/lib/chain/errors/payloadAttestation.d.ts.map +1 -1
- package/lib/chain/errors/payloadAttestation.js +1 -0
- package/lib/chain/errors/payloadAttestation.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts +4 -4
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +24 -11
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.d.ts +4 -4
- package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.js +6 -4
- package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +1 -0
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +2 -1
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +7 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +108 -19
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +2 -1
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +2 -0
- package/lib/chain/regen/interface.js.map +1 -1
- package/lib/chain/regen/queued.d.ts +0 -1
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +0 -4
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts +0 -5
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.js +0 -5
- package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +1 -4
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +5 -2
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +0 -2
- package/lib/chain/stateCache/types.d.ts.map +1 -1
- package/lib/chain/stateCache/types.js.map +1 -1
- package/lib/chain/validation/block.d.ts +5 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +4 -14
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts +7 -3
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +70 -16
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +0 -2
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +24 -4
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts +1 -0
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +16 -0
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/execution/builder/index.d.ts +1 -2
- package/lib/execution/builder/index.d.ts.map +1 -1
- package/lib/execution/builder/index.js +0 -1
- package/lib/execution/builder/index.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +1 -0
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/types.d.ts +2 -0
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js +2 -0
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +5 -1
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +14 -3
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +2 -2
- package/lib/network/interface.d.ts +1 -0
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +1 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +5 -0
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +21 -6
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/index.d.ts +2 -2
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +25 -23
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +9 -5
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +13 -3
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts +2 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +16 -6
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts +2 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +15 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/index.js +4 -4
- package/lib/network/reqresp/handlers/index.js.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js +22 -3
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
- package/lib/sync/types.d.ts +9 -1
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js +9 -2
- package/lib/sync/types.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +64 -30
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/dataColumns.d.ts.map +1 -1
- package/lib/util/dataColumns.js +16 -11
- package/lib/util/dataColumns.js.map +1 -1
- package/lib/util/sszBytes.js +1 -1
- package/package.json +15 -17
- package/src/api/impl/beacon/blocks/index.ts +60 -38
- package/src/api/impl/beacon/pool/index.ts +4 -42
- package/src/api/impl/config/constants.ts +2 -0
- package/src/api/impl/debug/index.ts +73 -12
- package/src/api/impl/lodestar/index.ts +30 -0
- package/src/api/impl/validator/index.ts +141 -82
- package/src/chain/archiveStore/archiveStore.ts +0 -5
- package/src/chain/blocks/importBlock.ts +10 -2
- package/src/chain/blocks/importExecutionPayload.ts +8 -2
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +2 -4
- package/src/chain/chain.ts +12 -1
- package/src/chain/emitter.ts +3 -2
- package/src/chain/errors/blockError.ts +0 -4
- package/src/chain/errors/executionPayloadBid.ts +13 -1
- package/src/chain/errors/payloadAttestation.ts +2 -0
- package/src/chain/forkChoice/index.ts +27 -4
- package/src/chain/opPools/executionPayloadBidPool.ts +10 -9
- package/src/chain/options.ts +1 -0
- package/src/chain/prepareNextSlot.ts +2 -1
- package/src/chain/produceBlock/produceBlockBody.ts +159 -26
- package/src/chain/regen/interface.ts +2 -1
- package/src/chain/regen/queued.ts +0 -5
- package/src/chain/stateCache/fifoBlockStateCache.ts +0 -6
- package/src/chain/stateCache/persistentCheckpointsCache.ts +6 -2
- package/src/chain/stateCache/types.ts +0 -2
- package/src/chain/validation/block.ts +12 -16
- package/src/chain/validation/executionPayloadBid.ts +78 -19
- package/src/chain/validation/executionPayloadEnvelope.ts +0 -2
- package/src/chain/validation/payloadAttestationMessage.ts +26 -4
- package/src/chain/validatorMonitor.ts +18 -0
- package/src/execution/builder/index.ts +1 -4
- package/src/execution/engine/interface.ts +1 -0
- package/src/execution/engine/types.ts +4 -0
- package/src/metrics/metrics/lodestar.ts +15 -3
- package/src/network/interface.ts +1 -0
- package/src/network/network.ts +11 -0
- package/src/network/processor/gossipHandlers.ts +26 -6
- package/src/network/processor/index.ts +27 -27
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +12 -5
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -3
- package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +1 -1
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +22 -6
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +20 -1
- package/src/network/reqresp/handlers/index.ts +4 -4
- package/src/network/reqresp/utils/dataColumnResponseValidation.ts +21 -3
- package/src/sync/types.ts +11 -2
- package/src/sync/unknownBlock.ts +70 -31
- package/src/util/dataColumns.ts +17 -12
- package/src/util/sszBytes.ts +1 -1
- package/lib/execution/builder/utils.d.ts +0 -5
- package/lib/execution/builder/utils.d.ts.map +0 -1
- package/lib/execution/builder/utils.js +0 -17
- package/lib/execution/builder/utils.js.map +0 -1
- package/src/execution/builder/utils.ts +0 -19
|
@@ -914,20 +914,38 @@ export function getValidatorApi(
|
|
|
914
914
|
notWhileSyncing();
|
|
915
915
|
await waitForSlot(slot);
|
|
916
916
|
|
|
917
|
-
// TODO GLOAS: support producing blocks from builder bids
|
|
918
|
-
const source = ProducedBlockSource.engine;
|
|
919
|
-
|
|
920
|
-
// TODO GLOAS: needs to be updated after fork choice changes are merged
|
|
921
917
|
const parentBlock = chain.getProposerHead(slot);
|
|
922
918
|
const {blockRoot: parentBlockRootHex, slot: parentSlot} = parentBlock;
|
|
923
919
|
const parentBlockRoot = fromHex(parentBlockRootHex);
|
|
924
920
|
notOnOutOfRangeData(parentBlockRoot);
|
|
925
921
|
metrics?.blockProductionSlotDelta.set(slot - parentSlot);
|
|
926
|
-
metrics?.blockProductionRequests.inc({source});
|
|
927
922
|
|
|
928
923
|
const graffitiBytes = toGraffitiBytes(
|
|
929
924
|
graffiti ?? getDefaultGraffiti(getLodestarClientVersion(opts), chain.executionEngine.clientVersion, opts)
|
|
930
925
|
);
|
|
926
|
+
|
|
927
|
+
// TODO GLOAS: respect builderSelection (MaxProfit, BuilderAlways, ExecutionAlways, etc.) to let
|
|
928
|
+
// the user control bid source preferences and value comparison. Also add external builder api
|
|
929
|
+
// support when it is implemented.
|
|
930
|
+
const isBuildingOnFull = chain.forkChoice.shouldBuildOnFull(parentBlock, slot);
|
|
931
|
+
const bidParentBlockHash = isBuildingOnFull ? parentBlock.executionPayloadBlockHash : parentBlock.parentBlockHash;
|
|
932
|
+
const builderBid = chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex);
|
|
933
|
+
|
|
934
|
+
const logCtx = {
|
|
935
|
+
slot,
|
|
936
|
+
parentSlot,
|
|
937
|
+
parentBlockRoot: parentBlockRootHex,
|
|
938
|
+
parentBlockHash: parentBlock.executionPayloadBlockHash,
|
|
939
|
+
fork,
|
|
940
|
+
...(builderBid !== null
|
|
941
|
+
? {
|
|
942
|
+
bidValue: builderBid.message.value,
|
|
943
|
+
builderIndex: builderBid.message.builderIndex,
|
|
944
|
+
bidBlockHash: toRootHex(builderBid.message.blockHash),
|
|
945
|
+
}
|
|
946
|
+
: {}),
|
|
947
|
+
};
|
|
948
|
+
|
|
931
949
|
const commonBlockBodyPromise = chain.produceCommonBlockBody({
|
|
932
950
|
slot,
|
|
933
951
|
parentBlock,
|
|
@@ -935,44 +953,76 @@ export function getValidatorApi(
|
|
|
935
953
|
graffiti: graffitiBytes,
|
|
936
954
|
});
|
|
937
955
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
feeRecipient,
|
|
947
|
-
commonBlockBodyPromise,
|
|
948
|
-
});
|
|
956
|
+
const baseAttrs = {
|
|
957
|
+
slot,
|
|
958
|
+
parentBlock,
|
|
959
|
+
randaoReveal,
|
|
960
|
+
graffiti: graffitiBytes,
|
|
961
|
+
feeRecipient,
|
|
962
|
+
commonBlockBodyPromise,
|
|
963
|
+
};
|
|
949
964
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
metrics?.
|
|
953
|
-
|
|
965
|
+
metrics?.blockProductionRequests.inc({source: ProducedBlockSource.engine});
|
|
966
|
+
if (builderBid !== null) {
|
|
967
|
+
metrics?.blockProductionRequests.inc({source: ProducedBlockSource.builder});
|
|
968
|
+
}
|
|
954
969
|
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
970
|
+
const timed = <T>(source: ProducedBlockSource, fn: () => Promise<T>): Promise<T> => {
|
|
971
|
+
const t = metrics?.blockProductionTime.startTimer();
|
|
972
|
+
return fn().finally(() => t?.({source}));
|
|
973
|
+
};
|
|
974
|
+
|
|
975
|
+
// Always build local block. If builder bid available, also build with it in parallel and prefer it.
|
|
976
|
+
const [engineResult, bidResult] = await Promise.allSettled([
|
|
977
|
+
timed(ProducedBlockSource.engine, () => chain.produceBlock(baseAttrs)),
|
|
978
|
+
builderBid !== null
|
|
979
|
+
? timed(ProducedBlockSource.builder, () => chain.produceBlock({...baseAttrs, builderBid}))
|
|
980
|
+
: Promise.reject(),
|
|
981
|
+
]);
|
|
982
|
+
|
|
983
|
+
let bestResult: typeof engineResult | null = null;
|
|
984
|
+
let source: ProducedBlockSource = ProducedBlockSource.engine;
|
|
985
|
+
if (builderBid !== null && bidResult.status === "fulfilled") {
|
|
986
|
+
source = ProducedBlockSource.builder;
|
|
987
|
+
bestResult = bidResult;
|
|
988
|
+
logger.info("Selected builder bid block", logCtx);
|
|
989
|
+
} else if (engineResult.status === "fulfilled") {
|
|
990
|
+
source = ProducedBlockSource.engine;
|
|
991
|
+
bestResult = engineResult;
|
|
992
|
+
if (builderBid !== null) {
|
|
993
|
+
logger.warn("Builder bid block production failed, using local block", logCtx);
|
|
964
994
|
}
|
|
995
|
+
}
|
|
965
996
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
}
|
|
974
|
-
|
|
997
|
+
if (bestResult === null || bestResult.status !== "fulfilled") {
|
|
998
|
+
const engineReason = engineResult.status === "rejected" ? engineResult.reason : undefined;
|
|
999
|
+
const bidReason = builderBid !== null && bidResult.status === "rejected" ? bidResult.reason : undefined;
|
|
1000
|
+
logger.error("Block production failed", {...logCtx, engineReason, bidReason});
|
|
1001
|
+
throw Error(`Block production failed: engine=${engineReason ?? "n/a"} builder=${bidReason ?? "n/a"}`);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
const {block, executionPayloadValue, consensusBlockValue} = bestResult.value;
|
|
1005
|
+
|
|
1006
|
+
metrics?.blockProductionSuccess.inc({source});
|
|
1007
|
+
metrics?.blockProductionNumAggregated.observe({source}, block.body.attestations.length);
|
|
1008
|
+
metrics?.blockProductionConsensusBlockValue.observe({source}, Number(formatWeiToEth(consensusBlockValue)));
|
|
1009
|
+
metrics?.blockProductionExecutionPayloadValue.observe({source}, Number(formatWeiToEth(executionPayloadValue)));
|
|
1010
|
+
|
|
1011
|
+
const blockRoot = toRootHex(config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block));
|
|
1012
|
+
logger.verbose("Produced block", {
|
|
1013
|
+
...logCtx,
|
|
1014
|
+
executionPayloadValue,
|
|
1015
|
+
consensusBlockValue,
|
|
1016
|
+
root: blockRoot,
|
|
1017
|
+
});
|
|
1018
|
+
if (chain.opts.persistProducedBlocks) {
|
|
1019
|
+
void chain.persistBlock(block, "produced_engine_block");
|
|
975
1020
|
}
|
|
1021
|
+
|
|
1022
|
+
return {
|
|
1023
|
+
data: block as gloas.BeaconBlock,
|
|
1024
|
+
meta: {version: fork, consensusBlockValue},
|
|
1025
|
+
};
|
|
976
1026
|
},
|
|
977
1027
|
|
|
978
1028
|
async produceAttestationData({committeeIndex, slot}) {
|
|
@@ -1060,15 +1110,34 @@ export function getValidatorApi(
|
|
|
1060
1110
|
notWhileSyncing();
|
|
1061
1111
|
await waitForSlot(slot);
|
|
1062
1112
|
|
|
1063
|
-
const block = chain.forkChoice.
|
|
1113
|
+
const block = chain.forkChoice.getCanonicalBlockAtSlot(slot);
|
|
1064
1114
|
if (!block) {
|
|
1065
|
-
|
|
1115
|
+
// No block is seen at slot. Return 404 so vc can skip casting payload attestation.
|
|
1116
|
+
throw new ApiError(404, `No canonical block found at slot=${slot}`);
|
|
1066
1117
|
}
|
|
1067
1118
|
|
|
1068
|
-
const blockIsForSlot = block.slot === slot;
|
|
1069
1119
|
const payloadInput = chain.seenPayloadEnvelopeInputCache.get(block.blockRoot);
|
|
1070
|
-
|
|
1071
|
-
|
|
1120
|
+
// Spec: set payload_present only if the envelope was seen before get_payload_due_ms()
|
|
1121
|
+
// into the slot. Use the envelope's own arrival time (getPayloadEnvelopeSource), not
|
|
1122
|
+
// the input's creation time.
|
|
1123
|
+
const payloadDueSec = config.getPayloadDueMs() / 1000;
|
|
1124
|
+
const payloadSeenSec =
|
|
1125
|
+
payloadInput?.hasPayloadEnvelope() === true
|
|
1126
|
+
? chain.clock.secFromSlot(slot, payloadInput.getPayloadEnvelopeSource().seenTimestampSec)
|
|
1127
|
+
: null;
|
|
1128
|
+
const payloadPresent = payloadSeenSec !== null && payloadSeenSec < payloadDueSec;
|
|
1129
|
+
const blobDataAvailable = payloadInput?.hasAllData() === true;
|
|
1130
|
+
|
|
1131
|
+
logger.debug("Produced payload attestation data", {
|
|
1132
|
+
slot,
|
|
1133
|
+
blockRoot: block.blockRoot,
|
|
1134
|
+
blockSlot: block.slot,
|
|
1135
|
+
payloadPresent,
|
|
1136
|
+
blobDataAvailable,
|
|
1137
|
+
hasPayloadInput: payloadInput !== undefined,
|
|
1138
|
+
payloadSeenSec,
|
|
1139
|
+
payloadDueSec,
|
|
1140
|
+
});
|
|
1072
1141
|
|
|
1073
1142
|
return {
|
|
1074
1143
|
data: {
|
|
@@ -1138,7 +1207,10 @@ export function getValidatorApi(
|
|
|
1138
1207
|
const isPostFulu = isForkPostFulu(config.getForkName(startSlot));
|
|
1139
1208
|
const maxFutureEpoch = isPostFulu && nearNextEpoch && opts?.v2 ? nextEpoch + 1 : nextEpoch;
|
|
1140
1209
|
if (currentEpoch >= 0 && epoch > maxFutureEpoch) {
|
|
1141
|
-
throw new ApiError(
|
|
1210
|
+
throw new ApiError(
|
|
1211
|
+
400,
|
|
1212
|
+
`Requested epoch ${epoch} must not be more than ${maxFutureEpoch}, currentEpoch=${currentEpoch}, v2=${opts?.v2 ?? false}`
|
|
1213
|
+
);
|
|
1142
1214
|
}
|
|
1143
1215
|
|
|
1144
1216
|
const head = chain.forkChoice.getHead();
|
|
@@ -1222,17 +1294,35 @@ export function getValidatorApi(
|
|
|
1222
1294
|
duties.push({slot: startSlot + i, validatorIndex: indexes[i], pubkey: pubkeys[i]});
|
|
1223
1295
|
}
|
|
1224
1296
|
|
|
1225
|
-
//
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1297
|
+
// In v2 the dependent root is different after fulu due to deterministic proposer lookahead
|
|
1298
|
+
let dependentRoot = proposerShufflingDecisionRoot(
|
|
1299
|
+
opts?.v2 ? config.getForkName(startSlot) : ForkName.phase0,
|
|
1300
|
+
state,
|
|
1301
|
+
epoch
|
|
1302
|
+
);
|
|
1303
|
+
const logCtx = {
|
|
1304
|
+
epoch,
|
|
1305
|
+
stateSlot: state.slot,
|
|
1306
|
+
stateEpoch: state.epoch,
|
|
1307
|
+
v2: opts?.v2 ?? false,
|
|
1308
|
+
};
|
|
1309
|
+
if (dependentRoot === null) {
|
|
1310
|
+
// fallback to get_proposer_duties() v1, also in lodestar v1.43
|
|
1311
|
+
logger.verbose("Proposer duties decision root not in state, falling back to state epoch", logCtx);
|
|
1312
|
+
dependentRoot = proposerShufflingDecisionRoot(ForkName.phase0, state, state.epoch);
|
|
1313
|
+
}
|
|
1314
|
+
if (dependentRoot === null) {
|
|
1315
|
+
logger.verbose("Proposer duties decision root not in state, falling back to genesis block root", logCtx);
|
|
1316
|
+
dependentRoot = await getGenesisBlockRoot(state);
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
const dependentRootHex = toRootHex(dependentRoot);
|
|
1320
|
+
logger.verbose("Computed proposer duties decision root", {...logCtx, dependentRoot: dependentRootHex});
|
|
1231
1321
|
|
|
1232
1322
|
return {
|
|
1233
1323
|
data: duties,
|
|
1234
1324
|
meta: {
|
|
1235
|
-
dependentRoot:
|
|
1325
|
+
dependentRoot: dependentRootHex,
|
|
1236
1326
|
executionOptimistic: isOptimisticBlock(head),
|
|
1237
1327
|
},
|
|
1238
1328
|
};
|
|
@@ -1411,33 +1501,6 @@ export function getValidatorApi(
|
|
|
1411
1501
|
};
|
|
1412
1502
|
},
|
|
1413
1503
|
|
|
1414
|
-
async getAggregatedAttestation({attestationDataRoot, slot}) {
|
|
1415
|
-
notWhileSyncing();
|
|
1416
|
-
|
|
1417
|
-
await waitForSlot(slot); // Must never request for a future slot > currentSlot
|
|
1418
|
-
|
|
1419
|
-
const dataRootHex = toRootHex(attestationDataRoot);
|
|
1420
|
-
const aggregate = chain.attestationPool.getAggregate(slot, dataRootHex, null);
|
|
1421
|
-
const fork = chain.config.getForkName(slot);
|
|
1422
|
-
|
|
1423
|
-
if (isForkPostElectra(fork)) {
|
|
1424
|
-
throw new ApiError(
|
|
1425
|
-
400,
|
|
1426
|
-
`Use getAggregatedAttestationV2 to retrieve aggregated attestations for post-electra fork=${fork}`
|
|
1427
|
-
);
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
if (!aggregate) {
|
|
1431
|
-
throw new ApiError(404, `No aggregated attestation for slot=${slot}, dataRoot=${dataRootHex}`);
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
metrics?.production.producedAggregateParticipants.observe(aggregate.aggregationBits.getTrueBitIndexes().length);
|
|
1435
|
-
|
|
1436
|
-
return {
|
|
1437
|
-
data: aggregate,
|
|
1438
|
-
};
|
|
1439
|
-
},
|
|
1440
|
-
|
|
1441
1504
|
async getAggregatedAttestationV2({attestationDataRoot, slot, committeeIndex}) {
|
|
1442
1505
|
notWhileSyncing();
|
|
1443
1506
|
|
|
@@ -1461,10 +1524,6 @@ export function getValidatorApi(
|
|
|
1461
1524
|
};
|
|
1462
1525
|
},
|
|
1463
1526
|
|
|
1464
|
-
async publishAggregateAndProofs({signedAggregateAndProofs}) {
|
|
1465
|
-
await this.publishAggregateAndProofsV2({signedAggregateAndProofs});
|
|
1466
|
-
},
|
|
1467
|
-
|
|
1468
1527
|
async publishAggregateAndProofsV2({signedAggregateAndProofs}) {
|
|
1469
1528
|
notWhileSyncing();
|
|
1470
1529
|
|
|
@@ -30,7 +30,6 @@ export enum ArchiveStoreTask {
|
|
|
30
30
|
PruneHistory = "prune_history",
|
|
31
31
|
OnFinalizedCheckpoint = "on_finalized_checkpoint",
|
|
32
32
|
MaybeArchiveState = "maybe_archive_state",
|
|
33
|
-
RegenPruneOnFinalized = "regen_prune_on_finalized",
|
|
34
33
|
ForkchoicePrune = "forkchoice_prune",
|
|
35
34
|
UpdateBackfillRange = "update_backfill_range",
|
|
36
35
|
}
|
|
@@ -229,10 +228,6 @@ export class ArchiveStore {
|
|
|
229
228
|
await this.statesArchiverStrategy.maybeArchiveState(finalized, this.metrics);
|
|
230
229
|
timer?.({source: ArchiveStoreTask.MaybeArchiveState});
|
|
231
230
|
|
|
232
|
-
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
233
|
-
this.chain.regen.pruneOnFinalized(finalizedEpoch);
|
|
234
|
-
timer?.({source: ArchiveStoreTask.RegenPruneOnFinalized});
|
|
235
|
-
|
|
236
231
|
// tasks rely on extended fork choice
|
|
237
232
|
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
238
233
|
const prunedBlocks = this.chain.forkChoice.prune(finalized.rootHex);
|
|
@@ -116,13 +116,19 @@ export async function importBlock(
|
|
|
116
116
|
}
|
|
117
117
|
executionStatus = parentBlock.executionStatus;
|
|
118
118
|
}
|
|
119
|
+
|
|
120
|
+
// getBeaconProposerOrNull will return null if head state is more than one epoch away
|
|
121
|
+
// from block slot. We skip proposer boost canonical check as we cannot determine the canonical proposer
|
|
122
|
+
const expectedProposerIndex: number | null = this.getHeadState().getBeaconProposerOrNull(blockSlot);
|
|
123
|
+
|
|
119
124
|
const blockSummary = this.forkChoice.onBlock(
|
|
120
125
|
block.message,
|
|
121
126
|
postState,
|
|
122
127
|
blockDelaySec,
|
|
123
128
|
currentSlot,
|
|
124
129
|
executionStatus,
|
|
125
|
-
dataAvailabilityStatus
|
|
130
|
+
dataAvailabilityStatus,
|
|
131
|
+
expectedProposerIndex
|
|
126
132
|
);
|
|
127
133
|
|
|
128
134
|
// This adds the state necessary to process the next block
|
|
@@ -257,8 +263,10 @@ export async function importBlock(
|
|
|
257
263
|
if (ptcIndices.length > 0) {
|
|
258
264
|
this.forkChoice.notifyPtcMessages(
|
|
259
265
|
toRootHex(payloadAttestation.data.beaconBlockRoot),
|
|
266
|
+
payloadAttestation.data.slot,
|
|
260
267
|
ptcIndices,
|
|
261
|
-
payloadAttestation.data.payloadPresent
|
|
268
|
+
payloadAttestation.data.payloadPresent,
|
|
269
|
+
payloadAttestation.data.blobDataAvailable
|
|
262
270
|
);
|
|
263
271
|
}
|
|
264
272
|
} catch (e) {
|
|
@@ -129,7 +129,7 @@ export async function importExecutionPayload(
|
|
|
129
129
|
|
|
130
130
|
// 3. Regenerate state for envelope verification
|
|
131
131
|
const blockState = await this.regen
|
|
132
|
-
.getBlockSlotState(protoBlock, protoBlock.slot, {dontTransferCache: true}, RegenCaller.
|
|
132
|
+
.getBlockSlotState(protoBlock, protoBlock.slot, {dontTransferCache: true}, RegenCaller.importExecutionPayload)
|
|
133
133
|
.catch(() =>
|
|
134
134
|
// only happen at the 1st batch of skipped slot checkpoint sync
|
|
135
135
|
this.regen.getClosestHeadState(protoBlock)
|
|
@@ -237,6 +237,7 @@ export async function importExecutionPayload(
|
|
|
237
237
|
blockRootHex,
|
|
238
238
|
blockHashHex,
|
|
239
239
|
envelope.payload.blockNumber,
|
|
240
|
+
envelope.payload.gasLimit,
|
|
240
241
|
execStatus,
|
|
241
242
|
dataAvailabilityStatus
|
|
242
243
|
);
|
|
@@ -254,7 +255,11 @@ export async function importExecutionPayload(
|
|
|
254
255
|
}
|
|
255
256
|
|
|
256
257
|
// 8. Record metrics for payload envelope and column sources
|
|
257
|
-
this.
|
|
258
|
+
const delaySec = this.clock.secFromSlot(slot);
|
|
259
|
+
this.metrics?.importPayload.elapsedTimeTillImported.observe(
|
|
260
|
+
{source: payloadInput.getPayloadEnvelopeSource().source},
|
|
261
|
+
delaySec
|
|
262
|
+
);
|
|
258
263
|
for (const {source} of payloadInput.getSampledColumnsWithSource()) {
|
|
259
264
|
this.metrics?.importPayload.columnsBySource.inc({source});
|
|
260
265
|
}
|
|
@@ -275,6 +280,7 @@ export async function importExecutionPayload(
|
|
|
275
280
|
builderIndex: envelope.builderIndex,
|
|
276
281
|
blockRoot: blockRootHex,
|
|
277
282
|
blockHash: blockHashHex,
|
|
283
|
+
delaySec,
|
|
278
284
|
});
|
|
279
285
|
}
|
|
280
286
|
|
|
@@ -61,10 +61,8 @@ export function verifyExecutionPayloadEnvelope(
|
|
|
61
61
|
`Prev randao mismatch between bid and payload bid=${toHex(bid.prevRandao)} payload=${toHex(payload.prevRandao)}`
|
|
62
62
|
);
|
|
63
63
|
}
|
|
64
|
-
if (
|
|
65
|
-
throw new Error(
|
|
66
|
-
`Gas limit mismatch between payload and bid payload=${payload.gasLimit} bid=${Number(bid.gasLimit)}`
|
|
67
|
-
);
|
|
64
|
+
if (bid.gasLimit !== payload.gasLimit) {
|
|
65
|
+
throw new Error(`Gas limit mismatch between payload and bid payload=${payload.gasLimit} bid=${bid.gasLimit}`);
|
|
68
66
|
}
|
|
69
67
|
if (!byteArrayEquals(bid.blockHash, payload.blockHash)) {
|
|
70
68
|
throw new Error(
|
package/src/chain/chain.ts
CHANGED
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import {PrivateKey} from "@libp2p/interface";
|
|
3
3
|
import {Type} from "@chainsafe/ssz";
|
|
4
4
|
import {BeaconConfig} from "@lodestar/config";
|
|
5
|
-
import {CheckpointWithHex, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice";
|
|
5
|
+
import {CheckpointWithHex, ForkChoiceStateGetter, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice";
|
|
6
6
|
import {LoggerNode} from "@lodestar/logger/node";
|
|
7
7
|
import {
|
|
8
8
|
EFFECTIVE_BALANCE_INCREMENT,
|
|
@@ -382,6 +382,14 @@ export class BeaconChain implements IBeaconChain {
|
|
|
382
382
|
blockStateCache.setHeadState(anchorState);
|
|
383
383
|
checkpointStateCache.add(checkpoint, anchorState);
|
|
384
384
|
|
|
385
|
+
const forkChoiceStateGetter: ForkChoiceStateGetter = ({stateRoot, checkpoint}) => {
|
|
386
|
+
if (stateRoot) return blockStateCache.get(stateRoot);
|
|
387
|
+
|
|
388
|
+
if (checkpoint) return checkpointStateCache.get({epoch: checkpoint.epoch, rootHex: checkpoint.rootHex});
|
|
389
|
+
|
|
390
|
+
return null;
|
|
391
|
+
};
|
|
392
|
+
|
|
385
393
|
const forkChoice = initializeForkChoice(
|
|
386
394
|
config,
|
|
387
395
|
emitter,
|
|
@@ -390,6 +398,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
390
398
|
isAnchorStateFinalized,
|
|
391
399
|
opts,
|
|
392
400
|
this.justifiedBalancesGetter.bind(this),
|
|
401
|
+
forkChoiceStateGetter,
|
|
393
402
|
metrics,
|
|
394
403
|
logger
|
|
395
404
|
);
|
|
@@ -1049,6 +1058,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1049
1058
|
feeRecipient,
|
|
1050
1059
|
commonBlockBodyPromise,
|
|
1051
1060
|
parentBlock,
|
|
1061
|
+
builderBid,
|
|
1052
1062
|
}: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}
|
|
1053
1063
|
): Promise<{
|
|
1054
1064
|
block: AssembledBlockType<T>;
|
|
@@ -1078,6 +1088,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1078
1088
|
proposerIndex,
|
|
1079
1089
|
proposerPubKey,
|
|
1080
1090
|
commonBlockBodyPromise,
|
|
1091
|
+
builderBid,
|
|
1081
1092
|
}
|
|
1082
1093
|
);
|
|
1083
1094
|
|
package/src/chain/emitter.ts
CHANGED
|
@@ -3,7 +3,7 @@ import {StrictEventEmitter} from "strict-event-emitter-types";
|
|
|
3
3
|
import {routes} from "@lodestar/api";
|
|
4
4
|
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
5
5
|
import {IBeaconStateView} from "@lodestar/state-transition";
|
|
6
|
-
import {DataColumnSidecar, RootHex, deneb, phase0} from "@lodestar/types";
|
|
6
|
+
import {DataColumnSidecar, RootHex, Slot, deneb, phase0} from "@lodestar/types";
|
|
7
7
|
import {PeerIdStr} from "../util/peerId.js";
|
|
8
8
|
import {BlockInputSource, IBlockInput} from "./blocks/blockInput/types.js";
|
|
9
9
|
import {PayloadEnvelopeInput} from "./blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
@@ -94,7 +94,8 @@ export type ChainEventData = {
|
|
|
94
94
|
peer: PeerIdStr;
|
|
95
95
|
source: BlockInputSource;
|
|
96
96
|
};
|
|
97
|
-
|
|
97
|
+
// slot is the message slot, not necessarily the envelope's slot, but useful as a logging/prune hint
|
|
98
|
+
[ChainEvent.unknownEnvelopeBlockRoot]: {rootHex: RootHex; slot: Slot; peer?: PeerIdStr; source: BlockInputSource};
|
|
98
99
|
};
|
|
99
100
|
|
|
100
101
|
export type IChainEvents = ApiEvents & {
|
|
@@ -61,9 +61,6 @@ export enum BlockErrorCode {
|
|
|
61
61
|
TRANSACTIONS_TOO_BIG = "BLOCK_ERROR_TRANSACTIONS_TOO_BIG",
|
|
62
62
|
/** Execution engine is unavailable, syncing, or api call errored. Peers must not be downscored on this code */
|
|
63
63
|
EXECUTION_ENGINE_ERROR = "BLOCK_ERROR_EXECUTION_ERROR",
|
|
64
|
-
/** The attestation head block is too far behind the attestation slot, causing many skip slots.
|
|
65
|
-
This is deemed a DoS risk */
|
|
66
|
-
TOO_MANY_SKIPPED_SLOTS = "TOO_MANY_SKIPPED_SLOTS",
|
|
67
64
|
/** The blobs are unavailable */
|
|
68
65
|
DATA_UNAVAILABLE = "BLOCK_ERROR_DATA_UNAVAILABLE",
|
|
69
66
|
/** Block contains too many kzg commitments */
|
|
@@ -89,7 +86,6 @@ export type BlockErrorType =
|
|
|
89
86
|
| {code: BlockErrorCode.FUTURE_SLOT; blockSlot: Slot; currentSlot: Slot}
|
|
90
87
|
| {code: BlockErrorCode.STATE_ROOT_MISMATCH}
|
|
91
88
|
| {code: BlockErrorCode.GENESIS_BLOCK}
|
|
92
|
-
| {code: BlockErrorCode.TOO_MANY_SKIPPED_SLOTS; parentSlot: Slot; blockSlot: Slot}
|
|
93
89
|
| {code: BlockErrorCode.WOULD_REVERT_FINALIZED_SLOT; blockSlot: Slot; finalizedSlot: Slot}
|
|
94
90
|
| {code: BlockErrorCode.ALREADY_KNOWN; root: RootHex}
|
|
95
91
|
| {code: BlockErrorCode.REPEAT_PROPOSAL; proposerIndex: ValidatorIndex}
|
|
@@ -9,7 +9,10 @@ export enum ExecutionPayloadBidErrorCode {
|
|
|
9
9
|
BID_TOO_HIGH = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_HIGH",
|
|
10
10
|
TOO_MANY_KZG_COMMITMENTS = "EXECUTION_PAYLOAD_BID_ERROR_TOO_MANY_KZG_COMMITMENTS",
|
|
11
11
|
UNKNOWN_BLOCK_ROOT = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_BLOCK_ROOT",
|
|
12
|
+
UNKNOWN_PARENT_BLOCK_HASH = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_PARENT_BLOCK_HASH",
|
|
12
13
|
INVALID_SLOT = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SLOT",
|
|
14
|
+
NOT_LATER_THAN_PARENT = "EXECUTION_PAYLOAD_BID_ERROR_NOT_LATER_THAN_PARENT",
|
|
15
|
+
INVALID_PREV_RANDAO = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_PREV_RANDAO",
|
|
13
16
|
INVALID_SIGNATURE = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SIGNATURE",
|
|
14
17
|
NO_MATCHING_PROPOSER_PREFERENCES = "EXECUTION_PAYLOAD_BID_ERROR_NO_MATCHING_PROPOSER_PREFERENCES",
|
|
15
18
|
PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH = "EXECUTION_PAYLOAD_BID_ERROR_PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH",
|
|
@@ -38,7 +41,15 @@ export type ExecutionPayloadBidErrorType =
|
|
|
38
41
|
commitmentLimit: number;
|
|
39
42
|
}
|
|
40
43
|
| {code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT; parentBlockRoot: RootHex}
|
|
44
|
+
| {code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH; parentBlockHash: RootHex}
|
|
41
45
|
| {code: ExecutionPayloadBidErrorCode.INVALID_SLOT; builderIndex: BuilderIndex; slot: Slot}
|
|
46
|
+
| {code: ExecutionPayloadBidErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot}
|
|
47
|
+
| {
|
|
48
|
+
code: ExecutionPayloadBidErrorCode.INVALID_PREV_RANDAO;
|
|
49
|
+
builderIndex: BuilderIndex;
|
|
50
|
+
bidPrevRandao: string;
|
|
51
|
+
expectedPrevRandao: string;
|
|
52
|
+
}
|
|
42
53
|
| {code: ExecutionPayloadBidErrorCode.INVALID_SIGNATURE; builderIndex: BuilderIndex; slot: Slot}
|
|
43
54
|
| {
|
|
44
55
|
code: ExecutionPayloadBidErrorCode.NO_MATCHING_PROPOSER_PREFERENCES;
|
|
@@ -56,7 +67,8 @@ export type ExecutionPayloadBidErrorType =
|
|
|
56
67
|
code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_GAS_LIMIT_MISMATCH;
|
|
57
68
|
builderIndex: BuilderIndex;
|
|
58
69
|
bidGasLimit: number;
|
|
59
|
-
|
|
70
|
+
parentGasLimit: number;
|
|
71
|
+
targetGasLimit: number;
|
|
60
72
|
};
|
|
61
73
|
|
|
62
74
|
export class ExecutionPayloadBidError extends GossipActionError<ExecutionPayloadBidErrorType> {}
|
|
@@ -5,6 +5,7 @@ export enum PayloadAttestationErrorCode {
|
|
|
5
5
|
NOT_CURRENT_SLOT = "PAYLOAD_ATTESTATION_ERROR_NOT_CURRENT_SLOT",
|
|
6
6
|
PAYLOAD_ATTESTATION_ALREADY_KNOWN = "PAYLOAD_ATTESTATION_ERROR_PAYLOAD_ATTESTATION_ALREADY_KNOWN",
|
|
7
7
|
UNKNOWN_BLOCK_ROOT = "PAYLOAD_ATTESTATION_ERROR_UNKNOWN_BLOCK_ROOT",
|
|
8
|
+
INVALID_BLOCK_SLOT = "PAYLOAD_ATTESTATION_ERROR_INVALID_BLOCK_SLOT",
|
|
8
9
|
INVALID_BLOCK = "PAYLOAD_ATTESTATION_ERROR_INVALID_BLOCK",
|
|
9
10
|
INVALID_ATTESTER = "PAYLOAD_ATTESTATION_ERROR_INVALID_ATTESTER",
|
|
10
11
|
INVALID_SIGNATURE = "PAYLOAD_ATTESTATION_ERROR_INVALID_SIGNATURE",
|
|
@@ -18,6 +19,7 @@ export type PayloadAttestationErrorType =
|
|
|
18
19
|
blockRoot: RootHex;
|
|
19
20
|
}
|
|
20
21
|
| {code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT; blockRoot: RootHex}
|
|
22
|
+
| {code: PayloadAttestationErrorCode.INVALID_BLOCK_SLOT; blockRoot: RootHex; blockSlot: Slot; slot: Slot}
|
|
21
23
|
| {code: PayloadAttestationErrorCode.INVALID_BLOCK; blockRoot: RootHex}
|
|
22
24
|
| {code: PayloadAttestationErrorCode.INVALID_ATTESTER; attesterIndex: ValidatorIndex}
|
|
23
25
|
| {code: PayloadAttestationErrorCode.INVALID_SIGNATURE};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import {routes} from "@lodestar/api";
|
|
1
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
3
|
import {
|
|
3
4
|
ExecutionStatus,
|
|
4
5
|
ForkChoice,
|
|
6
|
+
ForkChoiceStateGetter,
|
|
5
7
|
ForkChoiceStore,
|
|
6
8
|
JustifiedBalancesGetter,
|
|
7
9
|
PayloadStatus,
|
|
@@ -45,6 +47,7 @@ export function initializeForkChoice(
|
|
|
45
47
|
isFinalizedState: boolean,
|
|
46
48
|
opts: ForkChoiceOpts,
|
|
47
49
|
justifiedBalancesGetter: JustifiedBalancesGetter,
|
|
50
|
+
stateGetter: ForkChoiceStateGetter,
|
|
48
51
|
metrics: Metrics | null,
|
|
49
52
|
logger?: Logger
|
|
50
53
|
): ForkChoice {
|
|
@@ -56,6 +59,7 @@ export function initializeForkChoice(
|
|
|
56
59
|
state,
|
|
57
60
|
opts,
|
|
58
61
|
justifiedBalancesGetter,
|
|
62
|
+
stateGetter,
|
|
59
63
|
metrics,
|
|
60
64
|
logger
|
|
61
65
|
)
|
|
@@ -66,6 +70,7 @@ export function initializeForkChoice(
|
|
|
66
70
|
state,
|
|
67
71
|
opts,
|
|
68
72
|
justifiedBalancesGetter,
|
|
73
|
+
stateGetter,
|
|
69
74
|
metrics,
|
|
70
75
|
logger
|
|
71
76
|
);
|
|
@@ -81,6 +86,7 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
81
86
|
state: IBeaconStateView,
|
|
82
87
|
opts: ForkChoiceOpts,
|
|
83
88
|
justifiedBalancesGetter: JustifiedBalancesGetter,
|
|
89
|
+
stateGetter: ForkChoiceStateGetter,
|
|
84
90
|
metrics: Metrics | null,
|
|
85
91
|
logger?: Logger
|
|
86
92
|
): ForkChoice {
|
|
@@ -112,9 +118,12 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
112
118
|
finalizedCheckpoint,
|
|
113
119
|
justifiedBalances,
|
|
114
120
|
justifiedBalancesGetter,
|
|
121
|
+
stateGetter,
|
|
115
122
|
{
|
|
116
123
|
onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
|
|
117
124
|
onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
|
|
125
|
+
onFastConfirmation: ({block, slot, currentSlot}) =>
|
|
126
|
+
emitter.emit(routes.events.EventType.fastConfirmation, {block, slot, currentSlot}),
|
|
118
127
|
}
|
|
119
128
|
),
|
|
120
129
|
|
|
@@ -140,9 +149,11 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
140
149
|
executionPayloadBlockHash: isStatePostGloas(state)
|
|
141
150
|
? toRootHex(state.latestBlockHash)
|
|
142
151
|
: toRootHex(state.latestExecutionPayloadHeader.blockHash),
|
|
143
|
-
// TODO GLOAS: executionPayloadNumber
|
|
144
|
-
// latestExecutionPayloadHeader). Using 0 as unavailable fallback
|
|
152
|
+
// TODO GLOAS: executionPayloadNumber/GasLimit are not tracked in BeaconState post-gloas
|
|
153
|
+
// (EIP-7732 removed latestExecutionPayloadHeader). Using 0 as unavailable fallback —
|
|
154
|
+
// see initializeForkChoiceFromUnfinalizedState for the same caveat on validation.
|
|
145
155
|
executionPayloadNumber: isStatePostGloas(state) ? 0 : state.payloadBlockNumber,
|
|
156
|
+
executionPayloadGasLimit: isStatePostGloas(state) ? 0 : state.latestExecutionPayloadHeader.gasLimit,
|
|
146
157
|
executionStatus: blockHeader.slot === GENESIS_SLOT ? ExecutionStatus.Valid : ExecutionStatus.Syncing,
|
|
147
158
|
}
|
|
148
159
|
: {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
|
|
@@ -170,6 +181,7 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
170
181
|
unfinalizedState: IBeaconStateView,
|
|
171
182
|
opts: ForkChoiceOpts,
|
|
172
183
|
justifiedBalancesGetter: JustifiedBalancesGetter,
|
|
184
|
+
stateGetter: ForkChoiceStateGetter,
|
|
173
185
|
metrics: Metrics | null,
|
|
174
186
|
logger?: Logger
|
|
175
187
|
): ForkChoice {
|
|
@@ -201,9 +213,12 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
201
213
|
finalizedCheckpoint,
|
|
202
214
|
justifiedBalances,
|
|
203
215
|
justifiedBalancesGetter,
|
|
216
|
+
stateGetter,
|
|
204
217
|
{
|
|
205
218
|
onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
|
|
206
219
|
onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
|
|
220
|
+
onFastConfirmation: ({block, slot, currentSlot}) =>
|
|
221
|
+
emitter.emit(routes.events.EventType.fastConfirmation, {block, slot, currentSlot}),
|
|
207
222
|
}
|
|
208
223
|
);
|
|
209
224
|
|
|
@@ -232,9 +247,17 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
232
247
|
executionPayloadBlockHash: isStatePostGloas(unfinalizedState)
|
|
233
248
|
? toRootHex(unfinalizedState.latestBlockHash)
|
|
234
249
|
: toRootHex(unfinalizedState.latestExecutionPayloadHeader.blockHash),
|
|
235
|
-
// TODO GLOAS: executionPayloadNumber
|
|
236
|
-
// latestExecutionPayloadHeader). Using 0 as unavailable fallback until
|
|
250
|
+
// TODO GLOAS: executionPayloadNumber/GasLimit are not tracked in BeaconState post-gloas
|
|
251
|
+
// (EIP-7732 removed latestExecutionPayloadHeader). Using 0 as unavailable fallback until
|
|
252
|
+
// a solution is found. The 0 doesn't gate validation in practice: at boot the head's
|
|
253
|
+
// PENDING variant's `executionPayloadBlockHash` is the *parent's* payload hash (per the
|
|
254
|
+
// PENDING/EMPTY convention), so gossip bids that reference the head's *own* payload
|
|
255
|
+
// hash won't match this variant anyway and will IGNORE until `onExecutionPayload`
|
|
256
|
+
// upgrades the head to FULL with real values.
|
|
237
257
|
executionPayloadNumber: isStatePostGloas(unfinalizedState) ? 0 : unfinalizedState.payloadBlockNumber,
|
|
258
|
+
executionPayloadGasLimit: isStatePostGloas(unfinalizedState)
|
|
259
|
+
? 0
|
|
260
|
+
: unfinalizedState.latestExecutionPayloadHeader.gasLimit,
|
|
238
261
|
executionStatus: blockHeader.slot === GENESIS_SLOT ? ExecutionStatus.Valid : ExecutionStatus.Syncing,
|
|
239
262
|
}
|
|
240
263
|
: {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
|