@lodestar/beacon-node 1.50.0-dev.f2d839a25c → 1.50.0-dev.fc618d94e9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +6 -1
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/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/beacon/pool/index.js +4 -4
- package/lib/api/impl/beacon/pool/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.d.ts +1 -0
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +7 -3
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts +2 -2
- package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js +5 -7
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/types.d.ts +2 -2
- package/lib/chain/archiveStore/historicalState/types.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/worker.js +1 -1
- package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
- package/lib/chain/archiveStore/interface.d.ts +1 -1
- package/lib/chain/archiveStore/interface.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts +4 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.js +4 -3
- package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +4 -0
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +2 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +1 -1
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts +2 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +5 -4
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
- package/lib/chain/chain.d.ts +6 -4
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +43 -16
- 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/errors/envelopeReconstructionError.d.ts +5 -0
- package/lib/chain/errors/envelopeReconstructionError.d.ts.map +1 -1
- package/lib/chain/errors/envelopeReconstructionError.js +2 -0
- package/lib/chain/errors/envelopeReconstructionError.js.map +1 -1
- package/lib/chain/errors/gossipValidation.d.ts +3 -1
- package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
- package/lib/chain/errors/gossipValidation.js +2 -0
- package/lib/chain/errors/gossipValidation.js.map +1 -1
- package/lib/chain/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/initState.d.ts +2 -9
- package/lib/chain/initState.d.ts.map +1 -1
- package/lib/chain/initState.js +5 -38
- package/lib/chain/initState.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/opPools/opPool.d.ts +5 -4
- package/lib/chain/opPools/opPool.d.ts.map +1 -1
- package/lib/chain/opPools/opPool.js +62 -18
- package/lib/chain/opPools/opPool.js.map +1 -1
- package/lib/chain/opPools/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/opPools/utils.d.ts +4 -1
- package/lib/chain/opPools/utils.d.ts.map +1 -1
- package/lib/chain/opPools/utils.js +11 -1
- package/lib/chain/opPools/utils.js.map +1 -1
- package/lib/chain/options.d.ts +1 -1
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +1 -1
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +5 -2
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +6 -2
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/regen.d.ts +2 -0
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +10 -4
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +9 -2
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +23 -13
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts +4 -4
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +3 -0
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.d.ts +3 -3
- package/lib/chain/validation/proposerSlashing.d.ts.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +3 -0
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts +5 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +64 -54
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +2 -0
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/repositories/proposerSlashing.d.ts +1 -0
- package/lib/db/repositories/proposerSlashing.d.ts.map +1 -1
- package/lib/db/repositories/proposerSlashing.js +5 -1
- package/lib/db/repositories/proposerSlashing.js.map +1 -1
- package/lib/execution/engine/disabled.d.ts +0 -2
- package/lib/execution/engine/disabled.d.ts.map +1 -1
- package/lib/execution/engine/disabled.js +0 -6
- package/lib/execution/engine/disabled.js.map +1 -1
- package/lib/execution/engine/http.d.ts +1 -3
- package/lib/execution/engine/http.d.ts.map +1 -1
- package/lib/execution/engine/http.js +2 -17
- package/lib/execution/engine/http.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +2 -4
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/mock.d.ts +0 -2
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +0 -8
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/execution/engine/types.d.ts +0 -8
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/metrics/metrics.d.ts +7 -3
- package/lib/metrics/metrics.d.ts.map +1 -1
- package/lib/metrics/metrics.js +4 -4
- package/lib/metrics/metrics.js.map +1 -1
- package/lib/network/metadata.d.ts +1 -1
- package/lib/network/metadata.d.ts.map +1 -1
- package/lib/network/metadata.js +17 -17
- package/lib/network/metadata.js.map +1 -1
- package/lib/network/peers/datastore.d.ts +9 -9
- package/lib/network/peers/datastore.d.ts.map +1 -1
- package/lib/network/peers/datastore.js +36 -36
- package/lib/network/peers/datastore.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +7 -4
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipValidatorFn.d.ts +7 -3
- package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
- package/lib/network/processor/gossipValidatorFn.js +7 -3
- package/lib/network/processor/gossipValidatorFn.js.map +1 -1
- package/lib/network/processor/index.d.ts +9 -0
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +77 -10
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +41 -26
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +25 -3
- package/lib/node/nodejs.js.map +1 -1
- package/lib/sync/range/batch.d.ts +6 -0
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +10 -0
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +5 -1
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +50 -18
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +9 -5
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +88 -46
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/execution.d.ts +11 -11
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +6 -2
- package/lib/util/execution.js.map +1 -1
- package/package.json +16 -16
- package/src/api/impl/beacon/blocks/index.ts +7 -4
- package/src/api/impl/beacon/index.ts +15 -0
- package/src/api/impl/beacon/pool/index.ts +4 -4
- package/src/api/impl/validator/index.ts +16 -2
- package/src/chain/archiveStore/archiveStore.ts +10 -4
- package/src/chain/archiveStore/historicalState/getHistoricalState.ts +5 -7
- package/src/chain/archiveStore/historicalState/historicalStateRegen.ts +1 -1
- package/src/chain/archiveStore/historicalState/types.ts +2 -2
- package/src/chain/archiveStore/historicalState/worker.ts +1 -2
- package/src/chain/archiveStore/interface.ts +1 -1
- package/src/chain/archiveStore/utils/pruneHistory.ts +6 -4
- package/src/chain/blocks/importBlock.ts +4 -0
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +2 -1
- package/src/chain/blocks/verifyBlock.ts +1 -0
- package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +6 -3
- package/src/chain/chain.ts +50 -19
- package/src/chain/emitter.ts +7 -1
- package/src/chain/errors/envelopeReconstructionError.ts +3 -0
- package/src/chain/errors/gossipValidation.ts +2 -0
- package/src/chain/forkChoice/index.ts +2 -0
- package/src/chain/initState.ts +8 -60
- package/src/chain/interface.ts +2 -2
- package/src/chain/opPools/opPool.ts +91 -18
- package/src/chain/opPools/proposerPreferencesPool.ts +14 -10
- package/src/chain/opPools/utils.ts +31 -3
- package/src/chain/options.ts +2 -2
- package/src/chain/prepareNextSlot.ts +6 -3
- package/src/chain/produceBlock/computeNewStateRoot.ts +1 -1
- package/src/chain/produceBlock/produceBlockBody.ts +8 -1
- package/src/chain/regen/regen.ts +12 -4
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +31 -13
- package/src/chain/validation/attesterSlashing.ts +7 -4
- package/src/chain/validation/proposerSlashing.ts +7 -4
- package/src/chain/validatorMonitor.ts +75 -57
- package/src/db/beacon.ts +2 -0
- package/src/db/repositories/proposerSlashing.ts +6 -1
- package/src/execution/engine/disabled.ts +0 -8
- package/src/execution/engine/http.ts +1 -30
- package/src/execution/engine/interface.ts +2 -6
- package/src/execution/engine/mock.ts +1 -19
- package/src/execution/engine/types.ts +0 -10
- package/src/index.ts +1 -1
- package/src/metrics/metrics.ts +21 -6
- package/src/network/metadata.ts +17 -17
- package/src/network/peers/datastore.ts +36 -36
- package/src/network/processor/gossipHandlers.ts +7 -4
- package/src/network/processor/gossipValidatorFn.ts +13 -3
- package/src/network/processor/index.ts +89 -10
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +42 -28
- package/src/node/nodejs.ts +31 -3
- package/src/sync/range/batch.ts +11 -0
- package/src/sync/range/chain.ts +6 -1
- package/src/sync/range/range.ts +50 -18
- package/src/sync/unknownBlock.ts +99 -50
- package/src/util/execution.ts +17 -9
package/src/sync/range/range.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {IBeaconStateViewGloas, computeStartSlotAtEpoch, isStatePostGloas} from "
|
|
|
5
5
|
import {Epoch, Status, fulu} from "@lodestar/types";
|
|
6
6
|
import {Logger, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
7
7
|
import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
|
|
8
|
+
import {PayloadError, PayloadErrorCode} from "../../chain/blocks/importExecutionPayload.js";
|
|
8
9
|
import {AttestationImportOpt, ImportBlockOpts} from "../../chain/blocks/index.js";
|
|
9
10
|
import {assertLinearChainSegment} from "../../chain/blocks/utils/chainSegment.js";
|
|
10
11
|
import {BlockError} from "../../chain/errors/index.js";
|
|
@@ -207,22 +208,50 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
207
208
|
blsVerifyOnMainThread: false,
|
|
208
209
|
};
|
|
209
210
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
211
|
+
try {
|
|
212
|
+
if (this.opts?.disableProcessAsChainSegment) {
|
|
213
|
+
// Should only be used for debugging or testing
|
|
214
|
+
for (const block of blocks) {
|
|
215
|
+
await this.chain.processBlock(block, flags);
|
|
216
|
+
const payloadEnvelope = payloadEnvelopes?.get(block.slot);
|
|
217
|
+
if (payloadEnvelope?.hasPayloadEnvelope()) {
|
|
218
|
+
await this.chain.processExecutionPayload(payloadEnvelope);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
const {orphaned, skipped} = await this.chain.processChainSegment(blocks, payloadEnvelopes, flags);
|
|
223
|
+
// We log orphaned payloads to work with different clients
|
|
224
|
+
// in the future, consider applying penalties in certain conditions
|
|
225
|
+
// make sure the payload source was from range sync in that case
|
|
226
|
+
for (const {slot, payloadEnvelopeInput} of orphaned) {
|
|
227
|
+
const {peerIdStr, source} = payloadEnvelopeInput.getPayloadEnvelopeSource();
|
|
228
|
+
let client = "unknown";
|
|
229
|
+
if (peerIdStr !== undefined) {
|
|
230
|
+
try {
|
|
231
|
+
client = this.getConnectedPeerSyncMeta(peerIdStr).client;
|
|
232
|
+
} catch {
|
|
233
|
+
// peer disconnected since serving the envelope, keep "unknown"
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
this.logger.debug("Orphaned payload envelope in range sync batch", {
|
|
237
|
+
slot,
|
|
238
|
+
root: payloadEnvelopeInput.blockRootHex,
|
|
239
|
+
peer: peerIdStr ?? "unknown",
|
|
240
|
+
source,
|
|
241
|
+
client,
|
|
242
|
+
skipped,
|
|
243
|
+
});
|
|
217
244
|
}
|
|
218
245
|
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
246
|
+
} catch (e) {
|
|
247
|
+
if (
|
|
248
|
+
e instanceof PayloadError &&
|
|
249
|
+
(e.type.code === PayloadErrorCode.INVALID_SIGNATURE ||
|
|
250
|
+
e.type.code === PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR ||
|
|
251
|
+
e.type.code === PayloadErrorCode.EXECUTION_ENGINE_INVALID)
|
|
252
|
+
) {
|
|
253
|
+
const {payloadInput} = e;
|
|
254
|
+
const {peerIdStr, source} = payloadInput.getPayloadEnvelopeSource();
|
|
226
255
|
let client = "unknown";
|
|
227
256
|
if (peerIdStr !== undefined) {
|
|
228
257
|
try {
|
|
@@ -231,15 +260,18 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
231
260
|
// peer disconnected since serving the envelope, keep "unknown"
|
|
232
261
|
}
|
|
233
262
|
}
|
|
234
|
-
this.logger.debug("
|
|
235
|
-
slot,
|
|
236
|
-
root:
|
|
263
|
+
this.logger.debug("Removing invalid payload envelope in range sync batch", {
|
|
264
|
+
slot: payloadInput.slot,
|
|
265
|
+
root: payloadInput.blockRootHex,
|
|
237
266
|
peer: peerIdStr ?? "unknown",
|
|
238
267
|
source,
|
|
239
268
|
client,
|
|
240
|
-
|
|
269
|
+
code: e.type.code,
|
|
241
270
|
});
|
|
271
|
+
// The batch is downloaded again, it would otherwise reuse the cached envelope and fail the same way
|
|
272
|
+
this.chain.seenPayloadEnvelopeInputCache.removeInvalid(payloadInput);
|
|
242
273
|
}
|
|
274
|
+
throw e;
|
|
243
275
|
}
|
|
244
276
|
};
|
|
245
277
|
|
package/src/sync/unknownBlock.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {ChainEvent, ChainEventData, IBeaconChain} from "../chain/index.js";
|
|
|
15
15
|
import {validateGloasBlockDataColumnSidecars} from "../chain/validation/dataColumnSidecar.js";
|
|
16
16
|
import {validateGossipExecutionPayloadEnvelope} from "../chain/validation/executionPayloadEnvelope.js";
|
|
17
17
|
import {Metrics} from "../metrics/index.js";
|
|
18
|
-
import {INetwork, NetworkEvent, NetworkEventData, prettyPrintPeerIdStr} from "../network/index.js";
|
|
18
|
+
import {INetwork, NetworkEvent, NetworkEventData, PeerAction, prettyPrintPeerIdStr} from "../network/index.js";
|
|
19
19
|
import {PeerSyncMeta} from "../network/peers/peersData.js";
|
|
20
20
|
import {MAX_PEERS_PER_ROOT} from "../network/processor/constants.js";
|
|
21
21
|
import {ClockEvent} from "../util/clock.js";
|
|
@@ -442,6 +442,11 @@ export class BlockInputSync {
|
|
|
442
442
|
};
|
|
443
443
|
|
|
444
444
|
private addByRootHex = (rootHex: RootHex, peerIdStr?: PeerIdStr): boolean => {
|
|
445
|
+
if (this.knownBadBlocks.has(rootHex)) {
|
|
446
|
+
this.logger.debug("Ignoring known bad block root", {root: rootHex, peerIdStr: peerIdStr ?? "unknown peer"});
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
|
|
445
450
|
let pendingBlock = this.pendingBlocks.get(rootHex);
|
|
446
451
|
let added = false;
|
|
447
452
|
if (!pendingBlock) {
|
|
@@ -477,6 +482,11 @@ export class BlockInputSync {
|
|
|
477
482
|
};
|
|
478
483
|
|
|
479
484
|
private addByBlockInput = (blockInput: IBlockInput, peerIdStr?: string): void => {
|
|
485
|
+
if (this.knownBadBlocks.has(blockInput.blockRootHex)) {
|
|
486
|
+
this.logger.debug("Ignoring known bad block", {slot: blockInput.slot, root: blockInput.blockRootHex, peerIdStr});
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
480
490
|
let pendingBlock = this.pendingBlocks.get(blockInput.blockRootHex);
|
|
481
491
|
// if entry is missing or was added via rootHex and now we have more complete information overwrite
|
|
482
492
|
// the existing information with the more complete cache entry
|
|
@@ -513,6 +523,15 @@ export class BlockInputSync {
|
|
|
513
523
|
};
|
|
514
524
|
|
|
515
525
|
private addByPayloadRootHex = (rootHex: RootHex, peerIdStr?: PeerIdStr, slot?: Slot): boolean => {
|
|
526
|
+
if (this.knownBadBlocks.has(rootHex)) {
|
|
527
|
+
this.logger.debug("Ignoring payload for known bad block root", {
|
|
528
|
+
slot: slot ?? "unknown",
|
|
529
|
+
root: rootHex,
|
|
530
|
+
peerIdStr,
|
|
531
|
+
});
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
|
|
516
535
|
let pendingPayload = this.pendingPayloads.get(rootHex);
|
|
517
536
|
let added = false;
|
|
518
537
|
if (!pendingPayload) {
|
|
@@ -581,6 +600,15 @@ export class BlockInputSync {
|
|
|
581
600
|
peerIdStr?: PeerIdStr,
|
|
582
601
|
envelope?: gloas.SignedExecutionPayloadEnvelope
|
|
583
602
|
): void => {
|
|
603
|
+
if (this.knownBadBlocks.has(payloadInput.blockRootHex)) {
|
|
604
|
+
this.logger.debug("Ignoring payload input for known bad block root", {
|
|
605
|
+
slot: payloadInput.slot,
|
|
606
|
+
root: payloadInput.blockRootHex,
|
|
607
|
+
peerIdStr,
|
|
608
|
+
});
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
|
|
584
612
|
const pendingPayload = this.toPendingPayloadInput(
|
|
585
613
|
payloadInput,
|
|
586
614
|
this.pendingPayloads.get(payloadInput.blockRootHex),
|
|
@@ -654,6 +682,7 @@ export class BlockInputSync {
|
|
|
654
682
|
return {kind: "ready"};
|
|
655
683
|
}
|
|
656
684
|
|
|
685
|
+
// The parent's payload is known but does not match `parentBlockHashHex`
|
|
657
686
|
if (this.chain.forkChoice.hasPayloadHexUnsafe(parentRootHex)) {
|
|
658
687
|
return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
|
|
659
688
|
}
|
|
@@ -1032,7 +1061,8 @@ export class BlockInputSync {
|
|
|
1032
1061
|
}
|
|
1033
1062
|
} else if (blockSlot <= finalizedSlot) {
|
|
1034
1063
|
// the common ancestor of the downloading chain and canonical chain should be at least the finalized slot and
|
|
1035
|
-
// we should found it through forkchoice. If not,
|
|
1064
|
+
// we should found it through forkchoice. If not, drop the chain without penalizing peers because pending entries are
|
|
1065
|
+
// block retained on failed download, so finalization can pass the block while it is still pending
|
|
1036
1066
|
// 0 - 1 - ... - n - finalizedSlot
|
|
1037
1067
|
// \
|
|
1038
1068
|
// parent 1 - parent 2 - ... - unknownParent block
|
|
@@ -1040,7 +1070,7 @@ export class BlockInputSync {
|
|
|
1040
1070
|
...logCtx2,
|
|
1041
1071
|
finalizedSlot,
|
|
1042
1072
|
});
|
|
1043
|
-
this.
|
|
1073
|
+
this.removeAllDescendants(block, DroppedItemReason.belowFinalized);
|
|
1044
1074
|
} else {
|
|
1045
1075
|
this.onUnknownBlockRoot({rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot});
|
|
1046
1076
|
}
|
|
@@ -1172,15 +1202,18 @@ export class BlockInputSync {
|
|
|
1172
1202
|
break;
|
|
1173
1203
|
|
|
1174
1204
|
case BlockErrorCode.EXECUTION_ENGINE_INVALID:
|
|
1175
|
-
//
|
|
1205
|
+
// Ban but do not downscore: optimistic-sync peers may forward and serve blocks whose payload is later
|
|
1206
|
+
// rejected by the execution engine. Per the spec, an INVALID execution payload SHOULD NOT cause a peer
|
|
1207
|
+
// to be down-scored or disconnected, only consensus-layer invalidity MAY.
|
|
1208
|
+
// https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
|
|
1176
1209
|
this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
|
|
1177
|
-
this.
|
|
1210
|
+
this.removeAndBanAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
|
|
1178
1211
|
break;
|
|
1179
1212
|
|
|
1180
1213
|
default:
|
|
1181
1214
|
// Block is not correct with respect to our chain. Log error loudly
|
|
1182
1215
|
this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
|
|
1183
|
-
this.
|
|
1216
|
+
this.removeAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
|
|
1184
1217
|
}
|
|
1185
1218
|
}
|
|
1186
1219
|
|
|
@@ -1393,20 +1426,23 @@ export class BlockInputSync {
|
|
|
1393
1426
|
pendingPayload.status = PendingPayloadInputStatus.downloaded;
|
|
1394
1427
|
break;
|
|
1395
1428
|
|
|
1429
|
+
// The invalid envelope is evicted from the seen cache in the cases below, otherwise the next
|
|
1430
|
+
// attempt would reuse it instead of fetching another envelope from peers
|
|
1396
1431
|
case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
|
|
1397
1432
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1433
|
+
this.chain.seenPayloadEnvelopeInputCache.removeInvalid(pendingPayload.payloadInput);
|
|
1398
1434
|
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.elInvalid);
|
|
1399
1435
|
break;
|
|
1400
1436
|
|
|
1401
1437
|
case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
|
|
1402
1438
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1439
|
+
this.chain.seenPayloadEnvelopeInputCache.removeInvalid(pendingPayload.payloadInput);
|
|
1403
1440
|
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidEnvelope);
|
|
1404
1441
|
break;
|
|
1405
1442
|
|
|
1406
1443
|
case PayloadErrorCode.INVALID_SIGNATURE:
|
|
1407
|
-
// TODO GLOAS: Decide how invalid payload inputs should eventually leave memory without
|
|
1408
|
-
// reintroducing envelope replacement / recreation flows.
|
|
1409
1444
|
this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
|
|
1445
|
+
this.chain.seenPayloadEnvelopeInputCache.removeInvalid(pendingPayload.payloadInput);
|
|
1410
1446
|
this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidSignature);
|
|
1411
1447
|
break;
|
|
1412
1448
|
|
|
@@ -1478,11 +1514,11 @@ export class BlockInputSync {
|
|
|
1478
1514
|
}
|
|
1479
1515
|
|
|
1480
1516
|
const {peerId, client: peerClient} = peerMeta;
|
|
1481
|
-
cacheItem.peerIdStrings.add(peerId);
|
|
1482
1517
|
|
|
1483
1518
|
try {
|
|
1484
1519
|
if (!envelope) {
|
|
1485
1520
|
envelope = await this.fetchExecutionPayloadEnvelope(peerId, blockRoot, rootHex);
|
|
1521
|
+
cacheItem.peerIdStrings.add(peerId);
|
|
1486
1522
|
const slotWasUnknown = typeof slot !== "number";
|
|
1487
1523
|
slot = envelope.message.payload.slotNumber;
|
|
1488
1524
|
if (slotWasUnknown) {
|
|
@@ -1524,6 +1560,8 @@ export class BlockInputSync {
|
|
|
1524
1560
|
const missing = pendingPayload.payloadInput.getMissingSampledColumnMeta().missing;
|
|
1525
1561
|
if (missing.length > 0) {
|
|
1526
1562
|
const columnSidecars = await this.fetchPayloadColumns(peerMeta, pendingPayload.payloadInput, missing);
|
|
1563
|
+
// toPendingPayloadInput copied cacheItem's set, so add to the object that is carried forward
|
|
1564
|
+
pendingPayload.peerIdStrings.add(peerId);
|
|
1527
1565
|
const seenTimestampSec = Date.now() / 1000;
|
|
1528
1566
|
for (const columnSidecar of columnSidecars) {
|
|
1529
1567
|
if (pendingPayload.payloadInput.hasColumn(columnSidecar.index)) {
|
|
@@ -1716,8 +1754,6 @@ export class BlockInputSync {
|
|
|
1716
1754
|
}
|
|
1717
1755
|
const {peerId, client: peerClient} = peerMeta;
|
|
1718
1756
|
|
|
1719
|
-
cacheItem.peerIdStrings.add(peerId);
|
|
1720
|
-
|
|
1721
1757
|
try {
|
|
1722
1758
|
const downloadResult = await downloadByRoot({
|
|
1723
1759
|
config: this.config,
|
|
@@ -1728,6 +1764,7 @@ export class BlockInputSync {
|
|
|
1728
1764
|
cacheItem,
|
|
1729
1765
|
});
|
|
1730
1766
|
cacheItem = downloadResult.result;
|
|
1767
|
+
cacheItem.peerIdStrings.add(peerId);
|
|
1731
1768
|
if (slot === undefined) {
|
|
1732
1769
|
slot = cacheItem.blockInput.slot;
|
|
1733
1770
|
// we were not able to observe the time into slot when starting the fetch, do it now
|
|
@@ -1843,44 +1880,8 @@ export class BlockInputSync {
|
|
|
1843
1880
|
throw Error(message);
|
|
1844
1881
|
}
|
|
1845
1882
|
|
|
1846
|
-
/**
|
|
1847
|
-
* Gets all descendant blocks of `block` recursively from `pendingBlocks`.
|
|
1848
|
-
* Assumes that if a parent block does not exist or is not processable, all descendant blocks are bad too.
|
|
1849
|
-
* Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
|
|
1850
|
-
* referenced more than one bad block.
|
|
1851
|
-
*/
|
|
1852
|
-
private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
|
|
1853
|
-
// Get all blocks that are a descendant of this one
|
|
1854
|
-
const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
|
|
1855
|
-
// just console log and do not penalize on pending/bad blocks for debugging
|
|
1856
|
-
// console.log("removeAndDownscoreAllDescendants", {block});
|
|
1857
|
-
|
|
1858
|
-
for (const block of badPendingBlocks) {
|
|
1859
|
-
//
|
|
1860
|
-
// TODO(fulu): why is this commented out here?
|
|
1861
|
-
//
|
|
1862
|
-
// this.knownBadBlocks.add(block.blockRootHex);
|
|
1863
|
-
// for (const peerIdStr of block.peerIdStrings) {
|
|
1864
|
-
// // TODO: Refactor peerRpcScores to work with peerIdStr only
|
|
1865
|
-
// this.network.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadBlockByRoot");
|
|
1866
|
-
// }
|
|
1867
|
-
this.logger.debug("ignored Banning unknown block", {
|
|
1868
|
-
slot: getBlockInputSyncCacheItemSlot(block),
|
|
1869
|
-
root: getBlockInputSyncCacheItemRootHex(block),
|
|
1870
|
-
peerIdStrings: Array.from(block.peerIdStrings)
|
|
1871
|
-
.map((id) => prettyPrintPeerIdStr(id))
|
|
1872
|
-
.join(","),
|
|
1873
|
-
});
|
|
1874
|
-
}
|
|
1875
|
-
|
|
1876
|
-
// Prune knownBadBlocks
|
|
1877
|
-
pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
|
|
1878
|
-
}
|
|
1879
|
-
|
|
1880
1883
|
// Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
|
|
1881
1884
|
private removePendingPayloadAndDescendants(rootHex: RootHex, headReason: DroppedItemReason): void {
|
|
1882
|
-
// Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
|
|
1883
|
-
// later validation/finalization logic decides when it can leave memory.
|
|
1884
1885
|
if (this.pendingPayloads.delete(rootHex)) {
|
|
1885
1886
|
this.metrics?.blockInputSync.removedPayloads.inc({reason: headReason}, 1);
|
|
1886
1887
|
}
|
|
@@ -1903,13 +1904,61 @@ export class BlockInputSync {
|
|
|
1903
1904
|
}
|
|
1904
1905
|
}
|
|
1905
1906
|
|
|
1907
|
+
/**
|
|
1908
|
+
* Same as `removeAndBanAllDescendants`, and downscores every peer that referenced or served a banned item, once per
|
|
1909
|
+
* peer. Only call for consensus-layer invalidity, never for an INVALID execution payload:
|
|
1910
|
+
* https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
|
|
1911
|
+
*/
|
|
1912
|
+
private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
|
|
1913
|
+
const peersToReport = new Set<PeerIdStr>();
|
|
1914
|
+
for (const bannedBlock of this.removeAndBanAllDescendants(block, headReason)) {
|
|
1915
|
+
for (const peerIdStr of bannedBlock.peerIdStrings) {
|
|
1916
|
+
peersToReport.add(peerIdStr);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
for (const peerIdStr of peersToReport) {
|
|
1921
|
+
this.network.reportPeer(peerIdStr, PeerAction.LowToleranceError, headReason);
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
/**
|
|
1926
|
+
* Removes `block` and all its pending descendants and bans their roots in `knownBadBlocks`. Only call when the chain
|
|
1927
|
+
* is provably bad: a banned root is never searched for again. Returns the banned items.
|
|
1928
|
+
*/
|
|
1929
|
+
private removeAndBanAllDescendants(
|
|
1930
|
+
block: BlockInputSyncCacheItem,
|
|
1931
|
+
headReason: DroppedItemReason
|
|
1932
|
+
): BlockInputSyncCacheItem[] {
|
|
1933
|
+
const bannedBlocks: BlockInputSyncCacheItem[] = [];
|
|
1934
|
+
for (const badBlock of this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent)) {
|
|
1935
|
+
const rootHex = getBlockInputSyncCacheItemRootHex(badBlock);
|
|
1936
|
+
// a gossip import may race a failing sync path, never ban a root fork choice has imported
|
|
1937
|
+
if (this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
1938
|
+
continue;
|
|
1939
|
+
}
|
|
1940
|
+
this.knownBadBlocks.add(rootHex);
|
|
1941
|
+
bannedBlocks.push(badBlock);
|
|
1942
|
+
this.logger.debug("Banning unknown block", {
|
|
1943
|
+
slot: getBlockInputSyncCacheItemSlot(badBlock),
|
|
1944
|
+
root: rootHex,
|
|
1945
|
+
reason: headReason,
|
|
1946
|
+
peerIdStrings: Array.from(badBlock.peerIdStrings)
|
|
1947
|
+
.map((id) => prettyPrintPeerIdStr(id))
|
|
1948
|
+
.join(","),
|
|
1949
|
+
});
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
|
|
1953
|
+
return bannedBlocks;
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1906
1956
|
private removeAllDescendants(
|
|
1907
1957
|
block: BlockInputSyncCacheItem,
|
|
1908
1958
|
headReason: DroppedItemReason,
|
|
1909
1959
|
descendantReason: DroppedItemReason = DroppedItemReason.invalidParent
|
|
1910
1960
|
): BlockInputSyncCacheItem[] {
|
|
1911
1961
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1912
|
-
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
1913
1962
|
// Get all blocks that are a descendant of this one (index 0 is the head item itself)
|
|
1914
1963
|
const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
|
|
1915
1964
|
|
|
@@ -1926,8 +1975,8 @@ export class BlockInputSync {
|
|
|
1926
1975
|
// Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
|
|
1927
1976
|
// importBlock()-owned lifecycle.
|
|
1928
1977
|
this.logger.debug("Removing bad/unknown/incomplete BlockInputSyncCacheItem", {
|
|
1929
|
-
slot,
|
|
1930
|
-
|
|
1978
|
+
slot: getBlockInputSyncCacheItemSlot(block),
|
|
1979
|
+
root: rootHex,
|
|
1931
1980
|
});
|
|
1932
1981
|
}
|
|
1933
1982
|
|
package/src/util/execution.ts
CHANGED
|
@@ -260,20 +260,21 @@ export async function getDataColumnSidecarsFromExecution(
|
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
/** engine_getPayloadBodiesByHashV2: every EL must accept requests of up to 32 hashes, larger ones may fail with -38004 */
|
|
263
|
-
const MAX_BODIES_PER_REQUEST = 32;
|
|
263
|
+
export const MAX_BODIES_PER_REQUEST = 32;
|
|
264
264
|
|
|
265
265
|
type SlotEnvelopeBytes = {slot: Slot; envelopeBytes: Uint8Array};
|
|
266
266
|
|
|
267
267
|
type RangeEntry = ArchivedEnvelope & {slot: Slot};
|
|
268
268
|
|
|
269
|
-
/** What
|
|
270
|
-
export type
|
|
269
|
+
/** What an envelope that cannot be rebuilt (EL-unavailable body or body root mismatch) means on a given serving path */
|
|
270
|
+
export type ReconstructMissPolicy = "throw" | "omit";
|
|
271
271
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
272
|
+
/**
|
|
273
|
+
* An archived envelope that could not be rebuilt. `"unavailable"`: the EL does not have the block or its
|
|
274
|
+
* block access list (BODY_UNAVAILABLE). `"mismatch"`: an EL body does not hash to its stored root, a local
|
|
275
|
+
* inconsistency (BODY_ROOT_MISMATCH). `error` carries the matching code for paths that surface it.
|
|
276
|
+
*/
|
|
277
|
+
export type RebuildMiss = {slot: Slot; reason: "unavailable" | "mismatch"; error: EnvelopeReconstructionError};
|
|
277
278
|
|
|
278
279
|
/**
|
|
279
280
|
* Stream finalized envelopes over [startSlot, endSlot) as serialized bytes, rebuilding header
|
|
@@ -405,7 +406,14 @@ async function reconstructEnvelopesBatch(
|
|
|
405
406
|
// A zero-length block access list cannot be valid, RLP encodes an empty list as 0xc0
|
|
406
407
|
if (body == null || body.withdrawals == null || body.blockAccessList == null || body.blockAccessList.length === 0) {
|
|
407
408
|
metrics?.payloadEnvelopeReconstruction.envelopes.inc({result: "unavailable"});
|
|
408
|
-
return {
|
|
409
|
+
return {
|
|
410
|
+
slot,
|
|
411
|
+
reason: "unavailable",
|
|
412
|
+
error: new EnvelopeReconstructionError(
|
|
413
|
+
{code: EnvelopeReconstructionErrorCode.BODY_UNAVAILABLE, slot},
|
|
414
|
+
`execution client cannot serve the payload body or block access list for archived envelope slot=${slot}`
|
|
415
|
+
),
|
|
416
|
+
};
|
|
409
417
|
}
|
|
410
418
|
try {
|
|
411
419
|
const envelope = signedHeaderEnvelopeToFull(headerEnvelope, {
|