@lodestar/beacon-node 1.51.0-dev.bdcac30ee0 → 1.51.0-dev.be91fc5558
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/api.js +1 -1
- package/lib/api/impl/api.js.map +1 -1
- package/lib/api/impl/beacon/blocks/index.d.ts +2 -1
- package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +29 -34
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/index.d.ts +2 -1
- package/lib/api/impl/beacon/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/index.js +2 -2
- package/lib/api/impl/beacon/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 +5 -2
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/validator/index.d.ts +6 -0
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +42 -26
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/api/options.d.ts +2 -0
- package/lib/api/options.d.ts.map +1 -1
- package/lib/api/options.js +1 -0
- package/lib/api/options.js.map +1 -1
- package/lib/chain/GetBlobsTracker.d.ts +11 -0
- package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
- package/lib/chain/GetBlobsTracker.js +85 -27
- package/lib/chain/GetBlobsTracker.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +1 -0
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +4 -0
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +61 -97
- package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +6 -5
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +6 -11
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +8 -15
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.js +2 -2
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +12 -9
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.js +24 -19
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +4 -1
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +18 -7
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksDataAvailability.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksDataAvailability.js +8 -1
- package/lib/chain/blocks/verifyBlocksDataAvailability.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.js +7 -5
- package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
- package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +3 -3
- package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js +11 -6
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
- package/lib/chain/bls/interface.d.ts +2 -0
- package/lib/chain/bls/interface.d.ts.map +1 -1
- package/lib/chain/bls/multithread/index.d.ts.map +1 -1
- package/lib/chain/bls/multithread/index.js +13 -11
- package/lib/chain/bls/multithread/index.js.map +1 -1
- package/lib/chain/bls/multithread/types.d.ts +1 -1
- package/lib/chain/bls/multithread/types.d.ts.map +1 -1
- package/lib/chain/bls/multithread/worker.js +1 -1
- package/lib/chain/bls/multithread/worker.js.map +1 -1
- package/lib/chain/bls/singleThread.js +1 -1
- package/lib/chain/bls/singleThread.js.map +1 -1
- package/lib/chain/bls/utils.js +1 -1
- package/lib/chain/bls/utils.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 +4 -4
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +1 -1
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +1 -1
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +7 -0
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
- package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -3
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +23 -10
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/opPools/attestationPool.d.ts +1 -1
- package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/attestationPool.js +15 -4
- package/lib/chain/opPools/attestationPool.js.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.js +17 -7
- package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
- package/lib/chain/opPools/syncCommitteeMessagePool.d.ts.map +1 -1
- package/lib/chain/opPools/syncCommitteeMessagePool.js +9 -3
- package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
- package/lib/chain/opPools/syncContributionAndProofPool.d.ts.map +1 -1
- package/lib/chain/opPools/syncContributionAndProofPool.js +11 -3
- package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
- package/lib/chain/opPools/utils.d.ts +1 -1
- package/lib/chain/opPools/utils.d.ts.map +1 -1
- package/lib/chain/opPools/utils.js +1 -1
- package/lib/chain/opPools/utils.js.map +1 -1
- package/lib/chain/options.d.ts +0 -1
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +0 -1
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +0 -1
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +0 -1
- package/lib/chain/regen/interface.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts +0 -15
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +13 -166
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.d.ts +6 -0
- package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +53 -0
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/db/beacon.d.ts +7 -0
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +34 -0
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/dataColumnStore.d.ts +1 -1
- package/lib/db/dataColumnStore.d.ts.map +1 -1
- package/lib/db/dataColumnStore.js +1 -4
- package/lib/db/dataColumnStore.js.map +1 -1
- package/lib/db/flatFileStore/flatFileStore.js +5 -5
- package/lib/db/flatFileStore/flatFileStore.js.map +1 -1
- package/lib/db/flatFileStore/slotIndex.d.ts.map +1 -1
- package/lib/db/flatFileStore/slotIndex.js +2 -2
- package/lib/db/flatFileStore/slotIndex.js.map +1 -1
- package/lib/db/interface.d.ts +1 -0
- package/lib/db/interface.d.ts.map +1 -1
- package/lib/db/repositories/dataColumnSidecarArchive.d.ts +6 -0
- package/lib/db/repositories/dataColumnSidecarArchive.d.ts.map +1 -1
- package/lib/db/repositories/dataColumnSidecarArchive.js +19 -0
- package/lib/db/repositories/dataColumnSidecarArchive.js.map +1 -1
- package/lib/execution/builder/apiClient.d.ts +14 -8
- package/lib/execution/builder/apiClient.d.ts.map +1 -1
- package/lib/execution/builder/apiClient.js +12 -10
- package/lib/execution/builder/apiClient.js.map +1 -1
- package/lib/execution/builder/http.d.ts +2 -0
- package/lib/execution/builder/http.d.ts.map +1 -1
- package/lib/execution/builder/http.js +2 -0
- package/lib/execution/builder/http.js.map +1 -1
- package/lib/execution/engine/index.d.ts +1 -1
- package/lib/execution/engine/index.d.ts.map +1 -1
- package/lib/execution/engine/index.js +1 -1
- package/lib/execution/engine/index.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +1 -1
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/interface.js.map +1 -1
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js +2 -2
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/execution/engine/utils.d.ts.map +1 -1
- package/lib/execution/engine/utils.js +3 -2
- package/lib/execution/engine/utils.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +7 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +15 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/metrics/server/http.js +5 -5
- package/lib/metrics/server/http.js.map +1 -1
- package/lib/monitoring/service.js +1 -1
- package/lib/monitoring/service.js.map +1 -1
- package/lib/network/core/networkCore.d.ts +2 -0
- package/lib/network/core/networkCore.d.ts.map +1 -1
- package/lib/network/core/networkCore.js +3 -0
- package/lib/network/core/networkCore.js.map +1 -1
- package/lib/network/core/networkCoreWorker.js +1 -0
- package/lib/network/core/networkCoreWorker.js.map +1 -1
- package/lib/network/core/networkCoreWorkerHandler.d.ts +2 -0
- package/lib/network/core/networkCoreWorkerHandler.d.ts.map +1 -1
- package/lib/network/core/networkCoreWorkerHandler.js +3 -0
- package/lib/network/core/networkCoreWorkerHandler.js.map +1 -1
- package/lib/network/core/types.d.ts +2 -0
- package/lib/network/core/types.d.ts.map +1 -1
- package/lib/network/interface.d.ts +2 -0
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/libp2p/index.d.ts.map +1 -1
- package/lib/network/libp2p/index.js +5 -1
- package/lib/network/libp2p/index.js.map +1 -1
- package/lib/network/network.d.ts +2 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +6 -1
- package/lib/network/network.js.map +1 -1
- package/lib/network/options.d.ts +2 -0
- package/lib/network/options.d.ts.map +1 -1
- package/lib/network/options.js.map +1 -1
- package/lib/network/peers/peerManager.d.ts +2 -1
- package/lib/network/peers/peerManager.d.ts.map +1 -1
- package/lib/network/peers/peerManager.js.map +1 -1
- package/lib/network/peers/utils/assertPeerRelevance.d.ts +9 -1
- package/lib/network/peers/utils/assertPeerRelevance.d.ts.map +1 -1
- package/lib/network/peers/utils/assertPeerRelevance.js +32 -21
- package/lib/network/peers/utils/assertPeerRelevance.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +57 -37
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/node/nodejs.d.ts +3 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +47 -21
- package/lib/node/nodejs.js.map +1 -1
- package/lib/node/options.d.ts +3 -1
- package/lib/node/options.d.ts.map +1 -1
- package/lib/node/options.js +4 -2
- package/lib/node/options.js.map +1 -1
- package/lib/sync/interface.d.ts.map +1 -1
- package/lib/sync/interface.js.map +1 -1
- package/lib/sync/sync.d.ts +7 -0
- package/lib/sync/sync.d.ts.map +1 -1
- package/lib/sync/sync.js +61 -3
- package/lib/sync/sync.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +42 -18
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/file.d.ts.map +1 -1
- package/lib/util/file.js +8 -9
- package/lib/util/file.js.map +1 -1
- package/lib/util/queue/itemQueue.js +1 -1
- package/lib/util/queue/itemQueue.js.map +1 -1
- package/lib/util/sszBytes.d.ts +5 -0
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +35 -2
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +16 -17
- package/src/api/impl/api.ts +1 -1
- package/src/api/impl/beacon/blocks/index.ts +57 -62
- package/src/api/impl/beacon/index.ts +3 -1
- package/src/api/impl/beacon/pool/index.ts +5 -1
- package/src/api/impl/beacon/state/utils.ts +1 -1
- package/src/api/impl/validator/index.ts +47 -30
- package/src/api/options.ts +3 -0
- package/src/chain/GetBlobsTracker.ts +97 -38
- package/src/chain/archiveStore/archiveStore.ts +1 -0
- package/src/chain/archiveStore/utils/archiveBlocks.ts +76 -130
- package/src/chain/blocks/importBlock.ts +8 -7
- package/src/chain/blocks/importExecutionPayload.ts +13 -21
- package/src/chain/blocks/index.ts +6 -2
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +35 -24
- package/src/chain/blocks/types.ts +4 -1
- package/src/chain/blocks/verifyBlock.ts +31 -16
- package/src/chain/blocks/verifyBlocksDataAvailability.ts +10 -1
- package/src/chain/blocks/verifyBlocksSignatures.ts +7 -5
- package/src/chain/blocks/verifyPayloadsDataAvailability.ts +14 -6
- package/src/chain/bls/interface.ts +2 -0
- package/src/chain/bls/multithread/index.ts +14 -10
- package/src/chain/bls/multithread/types.ts +1 -1
- package/src/chain/bls/multithread/worker.ts +1 -5
- package/src/chain/bls/singleThread.ts +1 -1
- package/src/chain/bls/utils.ts +1 -1
- package/src/chain/chain.ts +5 -5
- package/src/chain/errors/blockError.ts +1 -1
- package/src/chain/errors/executionPayloadEnvelope.ts +8 -0
- package/src/chain/interface.ts +2 -3
- package/src/chain/opPools/aggregatedAttestationPool.ts +25 -9
- package/src/chain/opPools/attestationPool.ts +16 -4
- package/src/chain/opPools/payloadAttestationPool.ts +18 -7
- package/src/chain/opPools/syncCommitteeMessagePool.ts +10 -3
- package/src/chain/opPools/syncContributionAndProofPool.ts +13 -3
- package/src/chain/opPools/utils.ts +1 -1
- package/src/chain/options.ts +0 -2
- package/src/chain/regen/interface.ts +0 -1
- package/src/chain/validation/executionPayloadBid.ts +14 -193
- package/src/chain/validation/executionPayloadEnvelope.ts +68 -1
- package/src/db/beacon.ts +44 -0
- package/src/db/dataColumnStore.ts +2 -4
- package/src/db/flatFileStore/flatFileStore.ts +7 -7
- package/src/db/flatFileStore/slotIndex.ts +4 -3
- package/src/db/interface.ts +2 -0
- package/src/db/repositories/dataColumnSidecarArchive.ts +20 -0
- package/src/execution/builder/apiClient.ts +16 -13
- package/src/execution/builder/http.ts +4 -0
- package/src/execution/engine/index.ts +1 -1
- package/src/execution/engine/interface.ts +1 -1
- package/src/execution/engine/types.ts +3 -1
- package/src/execution/engine/utils.ts +4 -2
- package/src/index.ts +2 -0
- package/src/metrics/metrics/lodestar.ts +15 -0
- package/src/metrics/server/http.ts +5 -5
- package/src/monitoring/service.ts +1 -1
- package/src/network/core/networkCore.ts +5 -0
- package/src/network/core/networkCoreWorker.ts +1 -0
- package/src/network/core/networkCoreWorkerHandler.ts +4 -0
- package/src/network/core/types.ts +2 -0
- package/src/network/interface.ts +2 -0
- package/src/network/libp2p/index.ts +5 -1
- package/src/network/network.ts +8 -1
- package/src/network/options.ts +2 -0
- package/src/network/peers/peerManager.ts +1 -1
- package/src/network/peers/utils/assertPeerRelevance.ts +39 -23
- package/src/network/processor/gossipHandlers.ts +69 -40
- package/src/node/nodejs.ts +58 -22
- package/src/node/options.ts +9 -6
- package/src/sync/interface.ts +1 -0
- package/src/sync/sync.ts +65 -4
- package/src/sync/unknownBlock.ts +47 -28
- package/src/util/file.ts +8 -9
- package/src/util/queue/itemQueue.ts +1 -1
- package/src/util/sszBytes.ts +42 -2
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
deneb,
|
|
25
25
|
fulu,
|
|
26
26
|
gloas,
|
|
27
|
+
isGloasBeaconBlock,
|
|
27
28
|
isGloasDataColumnSidecar,
|
|
28
29
|
ssz,
|
|
29
30
|
sszTypesFor,
|
|
@@ -65,7 +66,10 @@ import {
|
|
|
65
66
|
validateGossipGloasDataColumnSidecar,
|
|
66
67
|
} from "../../chain/validation/dataColumnSidecar.js";
|
|
67
68
|
import {validateGossipExecutionPayloadBid} from "../../chain/validation/executionPayloadBid.js";
|
|
68
|
-
import {
|
|
69
|
+
import {
|
|
70
|
+
validateGossipExecutionPayloadEnvelope,
|
|
71
|
+
validateGossipExecutionPayloadEnvelopeSerialized,
|
|
72
|
+
} from "../../chain/validation/executionPayloadEnvelope.js";
|
|
69
73
|
import {InclusionListValidationResult, validateGossipInclusionList} from "../../chain/validation/inclusionList.js";
|
|
70
74
|
import {
|
|
71
75
|
AggregateAndProofValidationResult,
|
|
@@ -150,6 +154,31 @@ export function getGossipHandlers(modules: ValidatorFnsModules, options: GossipH
|
|
|
150
154
|
*/
|
|
151
155
|
function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHandlerOpts): SequentialGossipHandlers {
|
|
152
156
|
const {chain, config, metrics, logger, core} = modules;
|
|
157
|
+
const incompletePayloadWaits = new WeakSet<PayloadEnvelopeInput>();
|
|
158
|
+
|
|
159
|
+
function scheduleIncompletePayloadEnvelope(payloadInput: PayloadEnvelopeInput, peer: string): void {
|
|
160
|
+
if (payloadInput.isComplete() || incompletePayloadWaits.has(payloadInput)) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
incompletePayloadWaits.add(payloadInput);
|
|
164
|
+
|
|
165
|
+
const fork = config.getForkName(payloadInput.slot);
|
|
166
|
+
const cutoffTimeMs = getCutoffTimeMs(chain, payloadInput.slot, config.getPayloadDueMs(fork));
|
|
167
|
+
payloadInput.waitForEnvelopeAndAllData(cutoffTimeMs).catch(() => {
|
|
168
|
+
if (
|
|
169
|
+
payloadInput.isComplete() ||
|
|
170
|
+
chain.seenPayloadEnvelopeInputCache.get(payloadInput.blockRootHex) !== payloadInput
|
|
171
|
+
) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
chain.logger.debug("Payload envelope incomplete at payload deadline", payloadInput.getLogMeta());
|
|
175
|
+
chain.emitter.emit(ChainEvent.incompletePayloadEnvelope, {
|
|
176
|
+
payloadInput,
|
|
177
|
+
peer,
|
|
178
|
+
source: BlockInputSource.gossip,
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
}
|
|
153
182
|
|
|
154
183
|
/**
|
|
155
184
|
* Add a gossip block to the seen caches. The proposer signature of the block MUST be verified.
|
|
@@ -679,10 +708,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
679
708
|
|
|
680
709
|
// Immediately attempt fetch of data columns from execution engine as the bid contains kzg commitments
|
|
681
710
|
// which is all the information we need so there is no reason to delay until execution payload arrives
|
|
682
|
-
//
|
|
683
|
-
//
|
|
684
|
-
// Columns fetched here feed payloadInput.addColumn, which resolves waitForAllData for any
|
|
685
|
-
// in-flight importExecutionPayload. No processExecutionPayload trigger needed from this path.
|
|
711
|
+
// Columns fetched here feed payloadInput.addColumn, which resolves the waitForAllData of a
|
|
712
|
+
// pending payload import. No processExecutionPayload trigger needed from this path.
|
|
686
713
|
chain.getBlobsTracker.triggerGetBlobs(payloadInput);
|
|
687
714
|
}
|
|
688
715
|
})
|
|
@@ -692,11 +719,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
692
719
|
|
|
693
720
|
if (e instanceof BlockError) {
|
|
694
721
|
switch (e.type.code) {
|
|
695
|
-
case BlockErrorCode.DATA_UNAVAILABLE:
|
|
696
|
-
//
|
|
722
|
+
case BlockErrorCode.DATA_UNAVAILABLE:
|
|
723
|
+
// Data did not arrive in time, BlockInputSync keeps pulling it and retries the import
|
|
697
724
|
logLevel = LogLevel.debug;
|
|
698
725
|
break;
|
|
699
|
-
}
|
|
700
726
|
// ALREADY_KNOWN should not happen with ignoreIfKnown=true above
|
|
701
727
|
// PARENT_BLOCK_UNKNOWN should not happen, we handled this in validateBeaconBlock() function above
|
|
702
728
|
case BlockErrorCode.ALREADY_KNOWN:
|
|
@@ -764,7 +790,12 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
764
790
|
// roots per proposer and slot, which bounds full imports over gossip to one alternate
|
|
765
791
|
chain.seenBlockProposers.hasBlockRoot(signedBlock.message.slot, e.type.proposerIndex, e.type.root) &&
|
|
766
792
|
// A sibling with an unknown parent cannot be imported, sync fetches it if its branch becomes relevant
|
|
767
|
-
chain.forkChoice.getBlockHexDefaultStatus(toRootHex(signedBlock.message.parentRoot)) !== null
|
|
793
|
+
chain.forkChoice.getBlockHexDefaultStatus(toRootHex(signedBlock.message.parentRoot)) !== null &&
|
|
794
|
+
(!isGloasBeaconBlock(signedBlock.message) ||
|
|
795
|
+
chain.forkChoice.getBlockHexAndBlockHash(
|
|
796
|
+
toRootHex(signedBlock.message.parentRoot),
|
|
797
|
+
toRootHex(signedBlock.message.body.signedExecutionPayloadBid.message.parentBlockHash)
|
|
798
|
+
) !== null)
|
|
768
799
|
) {
|
|
769
800
|
const blockInput = cacheSignatureVerifiedBlock(
|
|
770
801
|
signedBlock,
|
|
@@ -899,28 +930,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
899
930
|
}
|
|
900
931
|
|
|
901
932
|
// NOTE: we do NOT call chain.processExecutionPayload here. That is triggered only by
|
|
902
|
-
// envelope arrival (gossip or API).
|
|
933
|
+
// envelope arrival (gossip or API). A pending payload import is awaiting
|
|
903
934
|
// payloadInput.waitForAllData(); addColumn above will resolve it once hasAllData flips.
|
|
904
935
|
|
|
905
|
-
|
|
906
|
-
const cutoffTimeMs = getCutoffTimeMs(chain, dataColumnSlot, BLOCK_AVAILABILITY_CUTOFF_MS);
|
|
907
|
-
// do not await here to not delay gossip validation
|
|
908
|
-
payloadInput.waitForEnvelopeAndAllData(cutoffTimeMs).catch((_e) => {
|
|
909
|
-
chain.logger.debug(
|
|
910
|
-
"Waited for envelope and data after receiving gossip column. Cut-off reached so emitting incompletePayloadEnvelope",
|
|
911
|
-
{
|
|
912
|
-
dataColumnIndex: index,
|
|
913
|
-
...payloadInputMeta,
|
|
914
|
-
}
|
|
915
|
-
);
|
|
916
|
-
// TODO GLOAS: UnknownBlockSync to handle this event
|
|
917
|
-
chain.emitter.emit(ChainEvent.incompletePayloadEnvelope, {
|
|
918
|
-
payloadInput,
|
|
919
|
-
peer: peerIdStr,
|
|
920
|
-
source: BlockInputSource.gossip,
|
|
921
|
-
});
|
|
922
|
-
});
|
|
923
|
-
}
|
|
936
|
+
scheduleIncompletePayloadEnvelope(payloadInput, peerIdStr);
|
|
924
937
|
} catch (e) {
|
|
925
938
|
logger.debug(
|
|
926
939
|
"Error handling gossip data column",
|
|
@@ -1266,6 +1279,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1266
1279
|
seenTimestampSec,
|
|
1267
1280
|
}: GossipHandlerParamGeneric<GossipType.execution_payload>) => {
|
|
1268
1281
|
const {serializedData} = gossipData;
|
|
1282
|
+
validateGossipExecutionPayloadEnvelopeSerialized(chain, serializedData);
|
|
1269
1283
|
const signedEnvelope = sszDeserialize(topic, serializedData);
|
|
1270
1284
|
const envelope = signedEnvelope.message;
|
|
1271
1285
|
|
|
@@ -1318,17 +1332,23 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1318
1332
|
});
|
|
1319
1333
|
}
|
|
1320
1334
|
|
|
1335
|
+
// Add the envelope in the same tick as validation, otherwise a by-root download that completes
|
|
1336
|
+
// before the next event loop sees no envelope, validates it again and adds it first
|
|
1337
|
+
if (!payloadInput.hasPayloadEnvelope()) {
|
|
1338
|
+
chain.serializedCache.set(signedEnvelope, serializedData);
|
|
1339
|
+
|
|
1340
|
+
payloadInput.addPayloadEnvelope({
|
|
1341
|
+
envelope: signedEnvelope,
|
|
1342
|
+
source: PayloadEnvelopeInputSource.gossip,
|
|
1343
|
+
seenTimestampSec,
|
|
1344
|
+
peerIdStr,
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1321
1348
|
// Handler - deferred to next event loop so the validation result propagates first
|
|
1322
1349
|
callInNextEventLoop(() => {
|
|
1323
1350
|
try {
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
payloadInput.addPayloadEnvelope({
|
|
1327
|
-
envelope: signedEnvelope,
|
|
1328
|
-
source: PayloadEnvelopeInputSource.gossip,
|
|
1329
|
-
seenTimestampSec,
|
|
1330
|
-
peerIdStr,
|
|
1331
|
-
});
|
|
1351
|
+
scheduleIncompletePayloadEnvelope(payloadInput, peerIdStr);
|
|
1332
1352
|
|
|
1333
1353
|
chain.emitter.emit(routes.events.EventType.executionPayloadGossip, {
|
|
1334
1354
|
slot,
|
|
@@ -1337,12 +1357,18 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1337
1357
|
blockRoot: blockRootHex,
|
|
1338
1358
|
});
|
|
1339
1359
|
|
|
1340
|
-
|
|
1360
|
+
// Signature is verified above only for this envelope, one added by another source is verified at import
|
|
1361
|
+
const validSignature = payloadInput.getPayloadEnvelope() === signedEnvelope;
|
|
1362
|
+
chain.processExecutionPayload(payloadInput, {validSignature}).catch((e) => {
|
|
1341
1363
|
// Adjust verbosity based on error type
|
|
1342
1364
|
let logLevel: LogLevel;
|
|
1343
1365
|
|
|
1344
1366
|
if (e instanceof PayloadError) {
|
|
1345
1367
|
switch (e.type.code) {
|
|
1368
|
+
case PayloadErrorCode.DATA_UNAVAILABLE:
|
|
1369
|
+
// Columns did not arrive in time, BlockInputSync keeps pulling them and retries the import
|
|
1370
|
+
logLevel = LogLevel.debug;
|
|
1371
|
+
break;
|
|
1346
1372
|
// BLOCK_NOT_IN_FORK_CHOICE should not happen, validateGossipExecutionPayloadEnvelope above
|
|
1347
1373
|
// already verified the block is in fork choice
|
|
1348
1374
|
case PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE:
|
|
@@ -1351,11 +1377,14 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1351
1377
|
// Errors might indicate an issue with our node or the connected EL client
|
|
1352
1378
|
logLevel = LogLevel.error;
|
|
1353
1379
|
break;
|
|
1354
|
-
// INVALID_SIGNATURE
|
|
1380
|
+
// INVALID_SIGNATURE only happens for an envelope added by another source
|
|
1355
1381
|
case PayloadErrorCode.INVALID_SIGNATURE:
|
|
1356
1382
|
case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
|
|
1357
1383
|
case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
|
|
1358
|
-
|
|
1384
|
+
// Penalize only when the stored envelope is the one this peer sent, not one added by another source
|
|
1385
|
+
if (validSignature) {
|
|
1386
|
+
core.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadGossipPayload");
|
|
1387
|
+
}
|
|
1359
1388
|
// The builder may have signed another envelope that is valid, keeping this one would make
|
|
1360
1389
|
// by-root and range sync reuse it and never import the payload
|
|
1361
1390
|
chain.seenPayloadEnvelopeInputCache.removeInvalid(payloadInput);
|
package/src/node/nodejs.ts
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
import {setMaxListeners} from "node:events";
|
|
2
2
|
import {PrivateKey} from "@libp2p/interface";
|
|
3
3
|
import {Registry} from "prom-client";
|
|
4
|
+
import {hasher} from "@chainsafe/persistent-merkle-tree";
|
|
5
|
+
import {BeaconApiMethods} from "@lodestar/api/beacon/server";
|
|
6
|
+
import {BeaconConfig} from "@lodestar/config";
|
|
7
|
+
import type {LoggerNode} from "@lodestar/logger/node";
|
|
4
8
|
import {
|
|
5
9
|
init as initNativeMetrics,
|
|
6
10
|
registerLocalValidator as registerNativeLocalValidator,
|
|
7
11
|
scrapeMetrics as scrapeNativeMetrics,
|
|
8
12
|
unregisterLocalValidator as unregisterNativeLocalValidator,
|
|
9
|
-
} from "@
|
|
10
|
-
import {type PubkeyCache} from "@
|
|
11
|
-
import {hasher} from "@chainsafe/persistent-merkle-tree";
|
|
12
|
-
import {BeaconApiMethods} from "@lodestar/api/beacon/server";
|
|
13
|
-
import {BeaconConfig} from "@lodestar/config";
|
|
14
|
-
import type {LoggerNode} from "@lodestar/logger/node";
|
|
13
|
+
} from "@lodestar/native/metrics";
|
|
14
|
+
import {type PubkeyCache} from "@lodestar/native/pubkeys";
|
|
15
15
|
import {ZERO_HASH_HEX} from "@lodestar/params";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
IBeaconStateView,
|
|
18
|
+
computeStartSlotAtEpoch,
|
|
19
|
+
isStatePostBellatrix,
|
|
20
|
+
isStatePostGloas,
|
|
21
|
+
} from "@lodestar/state-transition";
|
|
17
22
|
import {Slot} from "@lodestar/types";
|
|
18
|
-
import {sleep, toRootHex} from "@lodestar/utils";
|
|
23
|
+
import {defer, sleep, toRootHex} from "@lodestar/utils";
|
|
19
24
|
import {ProcessShutdownCallback} from "@lodestar/validator";
|
|
20
25
|
import {BeaconRestApiServer, getApi} from "../api/index.js";
|
|
26
|
+
import {getDataColumnSidecarsMinEpoch} from "../chain/archiveStore/utils/archiveBlocks.js";
|
|
21
27
|
import {BeaconChain, IBeaconChain, initBeaconMetrics} from "../chain/index.js";
|
|
22
28
|
import {ValidatorMonitor, createValidatorMonitor} from "../chain/validatorMonitor.js";
|
|
23
29
|
import {IBeaconDb} from "../db/index.js";
|
|
@@ -111,6 +117,7 @@ export class BeaconNode {
|
|
|
111
117
|
|
|
112
118
|
status: BeaconNodeStatus;
|
|
113
119
|
private controller?: AbortController;
|
|
120
|
+
private closePromise: Promise<void> | undefined;
|
|
114
121
|
|
|
115
122
|
constructor({
|
|
116
123
|
opts,
|
|
@@ -212,6 +219,17 @@ export class BeaconNode {
|
|
|
212
219
|
|
|
213
220
|
const clock = new Clock({config, genesisTime: anchorState.genesisTime, signal});
|
|
214
221
|
|
|
222
|
+
// Before any lookup into the legacy column buckets, which can be slow until compacted
|
|
223
|
+
const columnsMinEpoch =
|
|
224
|
+
opts.chain.archiveDataEpochs === Infinity
|
|
225
|
+
? null
|
|
226
|
+
: getDataColumnSidecarsMinEpoch(config, clock.currentEpoch, opts.chain.archiveDataEpochs);
|
|
227
|
+
await db.compactLegacyDataColumns(
|
|
228
|
+
columnsMinEpoch !== null && columnsMinEpoch >= config.FULU_FORK_EPOCH
|
|
229
|
+
? computeStartSlotAtEpoch(columnsMinEpoch)
|
|
230
|
+
: 0
|
|
231
|
+
);
|
|
232
|
+
|
|
215
233
|
await db.init();
|
|
216
234
|
|
|
217
235
|
// Prune hot db repos
|
|
@@ -280,6 +298,7 @@ export class BeaconNode {
|
|
|
280
298
|
: undefined,
|
|
281
299
|
builderApiClientOpts: {
|
|
282
300
|
timeout: opts.executionBuilder.timeout,
|
|
301
|
+
bidDeadline: opts.executionBuilder.bidDeadline,
|
|
283
302
|
// Sent with all builder api requests, unless the node runs in private mode
|
|
284
303
|
userAgent: opts.executionBuilder.userAgent,
|
|
285
304
|
},
|
|
@@ -375,23 +394,40 @@ export class BeaconNode {
|
|
|
375
394
|
/**
|
|
376
395
|
* Stop beacon node and its sub-components.
|
|
377
396
|
*/
|
|
378
|
-
|
|
379
|
-
if (this.
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
397
|
+
close(): Promise<void> {
|
|
398
|
+
if (this.closePromise !== undefined) return this.closePromise;
|
|
399
|
+
const completion = defer<void>();
|
|
400
|
+
this.closePromise = completion.promise;
|
|
401
|
+
this.status = BeaconNodeStatus.closing;
|
|
402
|
+
void this.closeInternal().then(completion.resolve, completion.reject);
|
|
403
|
+
return this.closePromise;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
private async closeInternal(): Promise<void> {
|
|
407
|
+
const errors: unknown[] = [];
|
|
408
|
+
for (const cleanup of [
|
|
409
|
+
() => this.sync.close(),
|
|
410
|
+
() => this.restApi?.close(),
|
|
411
|
+
() => this.network.close(),
|
|
412
|
+
() => this.metricsServer?.close(),
|
|
413
|
+
() => this.monitoring?.close(),
|
|
414
|
+
() => this.chain.persistToDisk(),
|
|
415
|
+
() => this.chain.close(),
|
|
388
416
|
// Abort signal last: close() calls above clear intervals/timeouts so no new
|
|
389
417
|
// operations get scheduled. If we aborted first, a still-pending interval could
|
|
390
418
|
// fire and schedule a new operation after abort, leaving it stuck and delaying shutdown.
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
419
|
+
() => this.controller?.abort(),
|
|
420
|
+
() => sleep(DELAY_BEFORE_CLOSING_DB_MS),
|
|
421
|
+
() => this.db.close(),
|
|
422
|
+
]) {
|
|
423
|
+
try {
|
|
424
|
+
await cleanup();
|
|
425
|
+
} catch (error) {
|
|
426
|
+
errors.push(error);
|
|
427
|
+
}
|
|
395
428
|
}
|
|
429
|
+
this.status = BeaconNodeStatus.closed;
|
|
430
|
+
if (errors.length === 1) throw errors[0];
|
|
431
|
+
if (errors.length > 1) throw new AggregateError(errors, "Beacon node cleanup failed");
|
|
396
432
|
}
|
|
397
433
|
}
|
package/src/node/options.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import {BLOCK_PRODUCTION_RACE_CUTOFF_GLOAS_BPS} from "../api/impl/validator/index.js";
|
|
1
2
|
import {ApiOptions, defaultApiOptions} from "../api/options.js";
|
|
2
3
|
import {ArchiveMode, DEFAULT_ARCHIVE_MODE, IChainOptions, defaultChainOptions} from "../chain/options.js";
|
|
3
4
|
import {ValidatorMonitorOpts, defaultValidatorMonitorOpts} from "../chain/validatorMonitor.js";
|
|
4
5
|
import {DatabaseOptions, defaultDbOptions} from "../db/options.js";
|
|
6
|
+
import {BUILDER_BID_LAG_BUFFER_MS} from "../execution/builder/apiClient.js";
|
|
5
7
|
import {
|
|
6
8
|
EngineApiMode,
|
|
7
9
|
ExecutionBuilderOpts,
|
|
@@ -19,16 +21,17 @@ import {SyncOptions, defaultSyncOptions} from "../sync/options.js";
|
|
|
19
21
|
|
|
20
22
|
// Re-export so the CLI doesn't need to depend on lodestar-api
|
|
21
23
|
export {allNamespaces} from "../api/rest/index.js";
|
|
22
|
-
|
|
23
|
-
// Re-export to use as default values in CLI args
|
|
24
|
+
export type {EngineApiMode};
|
|
25
|
+
// Re-export to use as default values and for validation in CLI args
|
|
24
26
|
export {
|
|
25
|
-
defaultExecutionEngineHttpOpts,
|
|
26
|
-
defaultExecutionBuilderHttpOpts,
|
|
27
|
-
engineApiModes,
|
|
28
27
|
ArchiveMode,
|
|
28
|
+
BLOCK_PRODUCTION_RACE_CUTOFF_GLOAS_BPS,
|
|
29
|
+
BUILDER_BID_LAG_BUFFER_MS,
|
|
29
30
|
DEFAULT_ARCHIVE_MODE,
|
|
31
|
+
defaultExecutionBuilderHttpOpts,
|
|
32
|
+
defaultExecutionEngineHttpOpts,
|
|
33
|
+
engineApiModes,
|
|
30
34
|
};
|
|
31
|
-
export type {EngineApiMode};
|
|
32
35
|
|
|
33
36
|
export interface IBeaconNodeOptions {
|
|
34
37
|
api: ApiOptions;
|
package/src/sync/interface.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {IBeaconDb} from "../db/index.js";
|
|
|
7
7
|
import {Metrics} from "../metrics/index.js";
|
|
8
8
|
import {INetwork} from "../network/index.js";
|
|
9
9
|
import {SyncChainDebugState} from "./range/chain.js";
|
|
10
|
+
|
|
10
11
|
export type {SyncChainDebugState};
|
|
11
12
|
|
|
12
13
|
export type SyncingStatus = routes.node.SyncingStatus;
|
package/src/sync/sync.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
-
import {
|
|
2
|
+
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
3
|
+
import {Slot, Status} from "@lodestar/types";
|
|
3
4
|
import {Logger, toRootHex} from "@lodestar/utils";
|
|
4
5
|
import {IBeaconChain} from "../chain/index.js";
|
|
5
|
-
import {GENESIS_SLOT} from "../constants/constants.js";
|
|
6
|
+
import {GENESIS_EPOCH, GENESIS_SLOT} from "../constants/constants.js";
|
|
7
|
+
import {GoodByeReasonCode} from "../constants/index.js";
|
|
8
|
+
import {IBeaconDb} from "../db/index.js";
|
|
6
9
|
import {ExecutionEngineState} from "../execution/index.js";
|
|
7
10
|
import {Metrics} from "../metrics/index.js";
|
|
8
|
-
import {INetwork, NetworkEvent, NetworkEventData} from "../network/index.js";
|
|
11
|
+
import {INetwork, NetworkEvent, NetworkEventData, PeerAction} from "../network/index.js";
|
|
9
12
|
import {ClockEvent} from "../util/clock.js";
|
|
10
13
|
import {isOptimisticBlock} from "../util/forkChoice.js";
|
|
14
|
+
import {PeerIdStr} from "../util/peerId.js";
|
|
11
15
|
import {MIN_EPOCH_TO_START_GOSSIP} from "./constants.js";
|
|
12
16
|
import {IBeaconSync, SyncChainDebugState, SyncModules, SyncState, SyncingStatus, syncStateMetric} from "./interface.js";
|
|
13
17
|
import {SyncOptions} from "./options.js";
|
|
@@ -19,6 +23,7 @@ export class BeaconSync implements IBeaconSync {
|
|
|
19
23
|
private readonly logger: Logger;
|
|
20
24
|
private readonly network: INetwork;
|
|
21
25
|
private readonly chain: IBeaconChain;
|
|
26
|
+
private readonly db: IBeaconDb;
|
|
22
27
|
private readonly metrics: Metrics | null;
|
|
23
28
|
private readonly opts: SyncOptions;
|
|
24
29
|
|
|
@@ -30,10 +35,11 @@ export class BeaconSync implements IBeaconSync {
|
|
|
30
35
|
private readonly slotImportTolerance: Slot;
|
|
31
36
|
|
|
32
37
|
constructor(opts: SyncOptions, modules: SyncModules) {
|
|
33
|
-
const {config, chain, metrics, network, logger} = modules;
|
|
38
|
+
const {config, chain, db, metrics, network, logger} = modules;
|
|
34
39
|
this.opts = opts;
|
|
35
40
|
this.network = network;
|
|
36
41
|
this.chain = chain;
|
|
42
|
+
this.db = db;
|
|
37
43
|
this.metrics = metrics;
|
|
38
44
|
this.logger = logger;
|
|
39
45
|
this.rangeSync = new RangeSync(modules, opts);
|
|
@@ -192,6 +198,11 @@ export class BeaconSync implements IBeaconSync {
|
|
|
192
198
|
*/
|
|
193
199
|
private addPeer = (data: NetworkEventData[NetworkEvent.peerConnected]): void => {
|
|
194
200
|
const localStatus = this.chain.getStatus();
|
|
201
|
+
// Genesis and equal finalized epochs are already checked by assertPeerRelevance in the network worker
|
|
202
|
+
if (data.status.finalizedEpoch > GENESIS_EPOCH && data.status.finalizedEpoch < localStatus.finalizedEpoch) {
|
|
203
|
+
void this.verifyPastFinalizedCheckpoint(data.peer, data.status);
|
|
204
|
+
}
|
|
205
|
+
|
|
195
206
|
const syncType = getPeerSyncType(localStatus, data.status, this.chain.forkChoice, this.slotImportTolerance);
|
|
196
207
|
this.logger.verbose("Peer sync type classified", {
|
|
197
208
|
peer: data.peer,
|
|
@@ -216,6 +227,56 @@ export class BeaconSync implements IBeaconSync {
|
|
|
216
227
|
this.updateSyncState();
|
|
217
228
|
};
|
|
218
229
|
|
|
230
|
+
/**
|
|
231
|
+
* A behind peer's finalized checkpoint must be the canonical block in effect at the start slot of its epoch
|
|
232
|
+
*/
|
|
233
|
+
async verifyPastFinalizedCheckpoint(peer: PeerIdStr, remote: Status): Promise<void> {
|
|
234
|
+
const startSlot = computeStartSlotAtEpoch(remote.finalizedEpoch);
|
|
235
|
+
const root = toRootHex(remote.finalizedRoot);
|
|
236
|
+
try {
|
|
237
|
+
let reason: string | null = null;
|
|
238
|
+
// After a finality jump, finalized blocks stay in fork choice until the archiver migrates them.
|
|
239
|
+
// Fork choice is pruned only after archiving, so a miss here means the db already has this range.
|
|
240
|
+
const canonicalBlock = this.chain.forkChoice.getCanonicalBlockClosestLteSlot(startSlot);
|
|
241
|
+
if (canonicalBlock !== null) {
|
|
242
|
+
if (canonicalBlock.blockRoot === root) return;
|
|
243
|
+
reason = "finalized_root_not_canonical";
|
|
244
|
+
} else {
|
|
245
|
+
const slot = await this.db.blockArchive.getSlotByRoot(remote.finalizedRoot);
|
|
246
|
+
if (slot !== null && slot > startSlot) {
|
|
247
|
+
reason = "finalized_root_after_epoch_start";
|
|
248
|
+
} else if (slot !== startSlot) {
|
|
249
|
+
const childSlot = await this.db.blockArchive.getSlotByParentRoot(remote.finalizedRoot);
|
|
250
|
+
if (childSlot !== null) {
|
|
251
|
+
if (childSlot <= startSlot) reason = "finalized_root_not_in_effect_at_epoch_start";
|
|
252
|
+
} else if (slot === null && startSlot > this.chain.earliestAvailableSlot) {
|
|
253
|
+
// childSlot == null too, neither the root nor a child is canonical
|
|
254
|
+
// or they are canonical and both pruned but peer's finalized epoch starts after earliestAvailableSlot
|
|
255
|
+
reason = "unknown_finalized_root";
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (reason !== null) {
|
|
261
|
+
this.logger.debug("Peer finalized checkpoint not in our chain", {
|
|
262
|
+
peer,
|
|
263
|
+
finalizedEpoch: remote.finalizedEpoch,
|
|
264
|
+
root,
|
|
265
|
+
reason,
|
|
266
|
+
});
|
|
267
|
+
this.metrics?.syncPeerFinalizedCheckpointMismatch.inc({reason});
|
|
268
|
+
this.network.reportPeer(peer, PeerAction.Fatal, "PeerFinalizedCheckpointMismatch");
|
|
269
|
+
await this.network.goodbyeAndDisconnect(peer, GoodByeReasonCode.IRRELEVANT_NETWORK);
|
|
270
|
+
}
|
|
271
|
+
} catch (e) {
|
|
272
|
+
this.logger.debug(
|
|
273
|
+
"Error verifying peer finalized checkpoint",
|
|
274
|
+
{peer, finalizedEpoch: remote.finalizedEpoch, root},
|
|
275
|
+
e as Error
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
219
280
|
/**
|
|
220
281
|
* Must be called by libp2p when a peer is removed from the peer manager
|
|
221
282
|
*/
|
package/src/sync/unknownBlock.ts
CHANGED
|
@@ -300,10 +300,19 @@ export class BlockInputSync {
|
|
|
300
300
|
|
|
301
301
|
private onIncompletePayloadEnvelope = (data: ChainEventData[ChainEvent.incompletePayloadEnvelope]): void => {
|
|
302
302
|
try {
|
|
303
|
-
this.addByPayloadInput(data.payloadInput, data.peer);
|
|
304
|
-
this.
|
|
305
|
-
|
|
306
|
-
|
|
303
|
+
const isNewRoot = this.addByPayloadInput(data.payloadInput, data.peer);
|
|
304
|
+
const pendingPayload = this.pendingPayloads.get(data.payloadInput.blockRootHex);
|
|
305
|
+
if (
|
|
306
|
+
pendingPayload &&
|
|
307
|
+
pendingPayload.status !== PendingPayloadInputStatus.fetching &&
|
|
308
|
+
pendingPayload.status !== PendingPayloadInputStatus.processing
|
|
309
|
+
) {
|
|
310
|
+
this.triggerUnknownBlockSearch();
|
|
311
|
+
}
|
|
312
|
+
if (isNewRoot) {
|
|
313
|
+
this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.INCOMPLETE_PAYLOAD_ENVELOPE});
|
|
314
|
+
this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
|
|
315
|
+
}
|
|
307
316
|
} catch (e) {
|
|
308
317
|
this.logger.debug("Error handling incompletePayloadEnvelope event", {}, e as Error);
|
|
309
318
|
}
|
|
@@ -599,43 +608,44 @@ export class BlockInputSync {
|
|
|
599
608
|
return this.chain.seenPayloadEnvelopeInputCache.get(rootHex)?.slot;
|
|
600
609
|
}
|
|
601
610
|
|
|
602
|
-
private addByPayloadInput = (
|
|
603
|
-
payloadInput: PayloadEnvelopeInput,
|
|
604
|
-
peerIdStr?: PeerIdStr,
|
|
605
|
-
envelope?: gloas.SignedExecutionPayloadEnvelope
|
|
606
|
-
): void => {
|
|
611
|
+
private addByPayloadInput = (payloadInput: PayloadEnvelopeInput, peerIdStr?: PeerIdStr): boolean => {
|
|
607
612
|
if (this.knownBadBlocks.has(payloadInput.blockRootHex)) {
|
|
608
613
|
this.logger.debug("Ignoring payload input for known bad block root", {
|
|
609
614
|
slot: payloadInput.slot,
|
|
610
615
|
root: payloadInput.blockRootHex,
|
|
611
616
|
peerIdStr,
|
|
612
617
|
});
|
|
613
|
-
return;
|
|
618
|
+
return false;
|
|
614
619
|
}
|
|
615
620
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
+
let pendingPayload = this.pendingPayloads.get(payloadInput.blockRootHex);
|
|
622
|
+
const isNewRoot = pendingPayload === undefined;
|
|
623
|
+
// Envelope-only entries must go through reconciliation to validate their speculative envelope.
|
|
624
|
+
if (
|
|
625
|
+
!pendingPayload ||
|
|
626
|
+
pendingPayload.status === PendingPayloadInputStatus.pending ||
|
|
627
|
+
pendingPayload.status === PendingPayloadInputStatus.downloaded
|
|
628
|
+
) {
|
|
629
|
+
pendingPayload = this.toPendingPayloadInput(payloadInput, pendingPayload);
|
|
630
|
+
this.pendingPayloads.set(payloadInput.blockRootHex, pendingPayload);
|
|
631
|
+
|
|
632
|
+
this.logger.verbose("Added payloadInput to BlockInputSync.pendingPayloads", {
|
|
633
|
+
slot: payloadInput.slot,
|
|
634
|
+
root: payloadInput.blockRootHex,
|
|
635
|
+
delaySec: this.chain.clock.secFromSlot(payloadInput.slot),
|
|
636
|
+
});
|
|
637
|
+
}
|
|
621
638
|
|
|
622
639
|
if (peerIdStr && pendingPayload.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
|
|
623
640
|
pendingPayload.peerIdStrings.add(peerIdStr);
|
|
624
641
|
}
|
|
625
642
|
|
|
626
|
-
this.pendingPayloads.set(payloadInput.blockRootHex, pendingPayload);
|
|
627
|
-
|
|
628
|
-
this.logger.verbose("Added payloadInput to BlockInputSync.pendingPayloads", {
|
|
629
|
-
slot: payloadInput.slot,
|
|
630
|
-
root: payloadInput.blockRootHex,
|
|
631
|
-
delaySec: this.chain.clock.secFromSlot(payloadInput.slot),
|
|
632
|
-
});
|
|
633
|
-
|
|
634
643
|
const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
|
|
635
644
|
if (prunedItemCount > 0) {
|
|
636
645
|
this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
|
|
637
646
|
this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
|
|
638
647
|
}
|
|
648
|
+
return isNewRoot;
|
|
639
649
|
};
|
|
640
650
|
|
|
641
651
|
private onPeerConnected = (data: NetworkEventData[NetworkEvent.peerConnected]): void => {
|
|
@@ -1267,6 +1277,9 @@ export class BlockInputSync {
|
|
|
1267
1277
|
}
|
|
1268
1278
|
|
|
1269
1279
|
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
1280
|
+
if (this.pendingPayloads.get(rootHex) !== pendingPayload) {
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1270
1283
|
if (!payloadInput) {
|
|
1271
1284
|
this.logger.debug("PayloadEnvelopeInput not yet reloadable for imported block, will retry", {
|
|
1272
1285
|
root: rootHex,
|
|
@@ -1278,6 +1291,9 @@ export class BlockInputSync {
|
|
|
1278
1291
|
const validationResult = await wrapError(
|
|
1279
1292
|
validateGossipExecutionPayloadEnvelope(this.chain, pendingPayload.envelope)
|
|
1280
1293
|
);
|
|
1294
|
+
if (this.pendingPayloads.get(rootHex) !== pendingPayload) {
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1281
1297
|
if (validationResult.err) {
|
|
1282
1298
|
this.logger.debug(
|
|
1283
1299
|
"Pending payload envelope failed validation after block import, refetching by root",
|
|
@@ -1345,14 +1361,13 @@ export class BlockInputSync {
|
|
|
1345
1361
|
payload.status = PendingPayloadInputStatus.fetching;
|
|
1346
1362
|
|
|
1347
1363
|
const res = await wrapError(this.fetchPayloadInput(payload));
|
|
1364
|
+
if (this.pendingPayloads.get(rootHex) !== payload) {
|
|
1365
|
+
this.logger.verbose("Dropping downloaded payload, entry changed during fetch", logCtx);
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1348
1368
|
if (!res.err) {
|
|
1349
1369
|
const pendingPayload = res.result;
|
|
1350
1370
|
const resultRootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
|
|
1351
|
-
// finalization may have deleted this entry while we were awaiting the network, do not resurrect it via the set below
|
|
1352
|
-
if (!this.pendingPayloads.has(resultRootHex)) {
|
|
1353
|
-
this.logger.verbose("Dropping downloaded payload, entry pruned during fetch", logCtx);
|
|
1354
|
-
return;
|
|
1355
|
-
}
|
|
1356
1371
|
this.pendingPayloads.set(resultRootHex, pendingPayload);
|
|
1357
1372
|
const result = isPendingPayloadEnvelope(pendingPayload)
|
|
1358
1373
|
? DownloadResult.WaitingForBlock
|
|
@@ -1423,12 +1438,16 @@ export class BlockInputSync {
|
|
|
1423
1438
|
this.logger.debug("Processing downloaded payload", logCtx);
|
|
1424
1439
|
|
|
1425
1440
|
const res = await wrapError(this.chain.processExecutionPayload(pendingPayload.payloadInput));
|
|
1441
|
+
// The executionPayload event emitted during import usually removes the entry before this point
|
|
1426
1442
|
if (!res.err) {
|
|
1427
1443
|
this.logger.debug("Processed payload from unknown sync", logCtx);
|
|
1428
1444
|
this.pendingPayloads.delete(rootHex);
|
|
1429
1445
|
this.triggerUnknownBlockSearch();
|
|
1430
1446
|
return;
|
|
1431
1447
|
}
|
|
1448
|
+
if (this.pendingPayloads.get(rootHex) !== pendingPayload) {
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1432
1451
|
|
|
1433
1452
|
if (res.err instanceof PayloadError) {
|
|
1434
1453
|
switch (res.err.type.code) {
|