@lodestar/beacon-node 1.50.0-dev.9e2fc57acd → 1.50.0-dev.a28be61ecb

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.
Files changed (92) hide show
  1. package/lib/api/impl/beacon/pool/index.js +4 -4
  2. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  3. package/lib/chain/archiveStore/archiveStore.d.ts +1 -0
  4. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  5. package/lib/chain/archiveStore/archiveStore.js +6 -2
  6. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  7. package/lib/chain/archiveStore/utils/pruneHistory.d.ts +4 -1
  8. package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
  9. package/lib/chain/archiveStore/utils/pruneHistory.js +4 -3
  10. package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
  11. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  12. package/lib/chain/blocks/importBlock.js +4 -0
  13. package/lib/chain/blocks/importBlock.js.map +1 -1
  14. package/lib/chain/chain.js +3 -3
  15. package/lib/chain/chain.js.map +1 -1
  16. package/lib/chain/errors/gossipValidation.d.ts +2 -1
  17. package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
  18. package/lib/chain/errors/gossipValidation.js +1 -0
  19. package/lib/chain/errors/gossipValidation.js.map +1 -1
  20. package/lib/chain/initState.d.ts +2 -9
  21. package/lib/chain/initState.d.ts.map +1 -1
  22. package/lib/chain/initState.js +5 -38
  23. package/lib/chain/initState.js.map +1 -1
  24. package/lib/chain/opPools/opPool.d.ts +5 -4
  25. package/lib/chain/opPools/opPool.d.ts.map +1 -1
  26. package/lib/chain/opPools/opPool.js +62 -18
  27. package/lib/chain/opPools/opPool.js.map +1 -1
  28. package/lib/chain/opPools/utils.d.ts +4 -1
  29. package/lib/chain/opPools/utils.d.ts.map +1 -1
  30. package/lib/chain/opPools/utils.js +11 -1
  31. package/lib/chain/opPools/utils.js.map +1 -1
  32. package/lib/chain/validation/attesterSlashing.d.ts +4 -4
  33. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  34. package/lib/chain/validation/attesterSlashing.js +3 -0
  35. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  36. package/lib/chain/validation/proposerSlashing.d.ts +3 -3
  37. package/lib/chain/validation/proposerSlashing.d.ts.map +1 -1
  38. package/lib/chain/validation/proposerSlashing.js +3 -0
  39. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  40. package/lib/db/beacon.d.ts.map +1 -1
  41. package/lib/db/beacon.js +2 -0
  42. package/lib/db/beacon.js.map +1 -1
  43. package/lib/db/repositories/proposerSlashing.d.ts +1 -0
  44. package/lib/db/repositories/proposerSlashing.d.ts.map +1 -1
  45. package/lib/db/repositories/proposerSlashing.js +5 -1
  46. package/lib/db/repositories/proposerSlashing.js.map +1 -1
  47. package/lib/index.d.ts +1 -1
  48. package/lib/index.d.ts.map +1 -1
  49. package/lib/index.js +1 -1
  50. package/lib/index.js.map +1 -1
  51. package/lib/network/processor/gossipHandlers.js +4 -4
  52. package/lib/network/processor/gossipHandlers.js.map +1 -1
  53. package/lib/network/processor/gossipValidatorFn.d.ts +3 -1
  54. package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
  55. package/lib/network/processor/gossipValidatorFn.js +1 -1
  56. package/lib/network/processor/gossipValidatorFn.js.map +1 -1
  57. package/lib/network/processor/index.d.ts +1 -0
  58. package/lib/network/processor/index.d.ts.map +1 -1
  59. package/lib/network/processor/index.js +28 -8
  60. package/lib/network/processor/index.js.map +1 -1
  61. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
  62. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +41 -26
  63. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
  64. package/lib/sync/unknownBlock.d.ts +9 -5
  65. package/lib/sync/unknownBlock.d.ts.map +1 -1
  66. package/lib/sync/unknownBlock.js +83 -42
  67. package/lib/sync/unknownBlock.js.map +1 -1
  68. package/lib/util/execution.d.ts +2 -0
  69. package/lib/util/execution.d.ts.map +1 -1
  70. package/lib/util/execution.js +1 -1
  71. package/lib/util/execution.js.map +1 -1
  72. package/package.json +15 -15
  73. package/src/api/impl/beacon/pool/index.ts +4 -4
  74. package/src/chain/archiveStore/archiveStore.ts +9 -3
  75. package/src/chain/archiveStore/utils/pruneHistory.ts +6 -4
  76. package/src/chain/blocks/importBlock.ts +4 -0
  77. package/src/chain/chain.ts +3 -3
  78. package/src/chain/errors/gossipValidation.ts +1 -0
  79. package/src/chain/initState.ts +8 -60
  80. package/src/chain/opPools/opPool.ts +91 -18
  81. package/src/chain/opPools/utils.ts +31 -3
  82. package/src/chain/validation/attesterSlashing.ts +7 -4
  83. package/src/chain/validation/proposerSlashing.ts +7 -4
  84. package/src/db/beacon.ts +2 -0
  85. package/src/db/repositories/proposerSlashing.ts +6 -1
  86. package/src/index.ts +1 -1
  87. package/src/network/processor/gossipHandlers.ts +4 -4
  88. package/src/network/processor/gossipValidatorFn.ts +1 -1
  89. package/src/network/processor/index.ts +34 -8
  90. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +42 -28
  91. package/src/sync/unknownBlock.ts +94 -46
  92. package/src/util/execution.ts +1 -1
@@ -2,14 +2,20 @@ import { RespStatus, ResponseError } from "@lodestar/reqresp";
2
2
  import { computeEpochAtSlot } from "@lodestar/state-transition";
3
3
  import { toRootHex } from "@lodestar/utils";
4
4
  import { EnvelopeReconstructionError } from "../../../chain/errors/index.js";
5
+ import { MAX_BODIES_PER_REQUEST } from "../../../util/execution.js";
5
6
  import { prettyPrintPeerId } from "../../util.js";
6
7
  export async function* onExecutionPayloadEnvelopesByRoot(requestBody, chain, db, peerId, peerClient) {
7
8
  // The gloas req/resp spec uses MIN_EPOCHS_FOR_BLOCK_REQUESTS to define the minimum range peers MUST serve.
8
9
  // Archival nodes may still serve older retained payloads to allow genesis sync.
9
- // Resolve slots first so archived header envelopes are rebuilt in one EL batch, not one call per root
10
+ // Resolve slots first so archived envelopes can be reconstructed in EL batches.
11
+ // Duplicate roots are served once, since each archived envelope costs an EL fetch and a rebuild.
10
12
  const requests = [];
13
+ const seenRoots = new Set();
11
14
  for (const root of requestBody) {
12
15
  const rootHex = toRootHex(root);
16
+ if (seenRoots.has(rootHex))
17
+ continue;
18
+ seenRoots.add(rootHex);
13
19
  const block = chain.forkChoice.getBlockHexDefaultStatus(rootHex);
14
20
  // If the block is not in fork choice, it may be finalized. Attempt to find its slot in block archive
15
21
  const slot = block ? block.slot : await db.blockArchive.getSlotByRoot(root);
@@ -23,33 +29,42 @@ export async function* onExecutionPayloadEnvelopesByRoot(requestBody, chain, db,
23
29
  }
24
30
  requests.push({ blockSlot: slot, blockRootHex: rootHex });
25
31
  }
26
- let envelopesBytes;
27
- try {
28
- // by-root allows omission, so a mismatched envelope is left out rather than failing the response
29
- envelopesBytes = await chain.getSerializedExecutionPayloadEnvelopes(requests, "omit");
30
- }
31
- catch (e) {
32
- if (e instanceof EnvelopeReconstructionError) {
33
- throw new ResponseError(RespStatus.RESOURCE_UNAVAILABLE, `Failed to reconstruct archived envelopes: ${e.message}`);
32
+ // Yield between EL batches so the first response does not wait for the entire request.
33
+ let yielded = 0;
34
+ for (let i = 0; i < requests.length; i += MAX_BODIES_PER_REQUEST) {
35
+ const batch = requests.slice(i, i + MAX_BODIES_PER_REQUEST);
36
+ let envelopesBytes;
37
+ try {
38
+ // By-root allows omission, so a mismatched envelope is left out rather than failing the response.
39
+ envelopesBytes = await chain.getSerializedExecutionPayloadEnvelopes(batch, "omit");
34
40
  }
35
- throw e;
36
- }
37
- for (let i = 0; i < requests.length; i++) {
38
- const { blockSlot, blockRootHex } = requests[i];
39
- const envelopeBytes = envelopesBytes[i];
40
- if (envelopeBytes) {
41
- yield {
42
- data: envelopeBytes,
43
- boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(blockSlot)),
44
- };
41
+ catch (e) {
42
+ if (e instanceof EnvelopeReconstructionError) {
43
+ // By-root permits partial responses, so an EL failure can end the response here.
44
+ if (yielded > 0)
45
+ return;
46
+ throw new ResponseError(RespStatus.RESOURCE_UNAVAILABLE, `Failed to reconstruct archived envelopes: ${e.message}`);
47
+ }
48
+ throw e;
45
49
  }
46
- else {
47
- chain.logger.debug("Cannot serve ExecutionPayloadEnvelopesByRoot: envelope not found", {
48
- slot: blockSlot,
49
- root: blockRootHex,
50
- peer: prettyPrintPeerId(peerId),
51
- client: peerClient,
52
- });
50
+ for (let j = 0; j < batch.length; j++) {
51
+ const { blockSlot, blockRootHex } = batch[j];
52
+ const envelopeBytes = envelopesBytes[j];
53
+ if (envelopeBytes) {
54
+ yielded++;
55
+ yield {
56
+ data: envelopeBytes,
57
+ boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(blockSlot)),
58
+ };
59
+ }
60
+ else {
61
+ chain.logger.debug("Cannot serve ExecutionPayloadEnvelopesByRoot: envelope not found", {
62
+ slot: blockSlot,
63
+ root: blockRootHex,
64
+ peer: prettyPrintPeerId(peerId),
65
+ client: peerClient,
66
+ });
67
+ }
53
68
  }
54
69
  }
55
70
  }
@@ -1 +1 @@
1
- {"version":3,"file":"executionPayloadEnvelopesByRoot.js","sourceRoot":"","sources":["../../../../src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,UAAU,EAAE,aAAa,EAAmB,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAC,kBAAkB,EAAC,MAAM,4BAA4B,CAAC;AAE9D,OAAO,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAC,2BAA2B,EAAC,MAAM,gCAAgC,CAAC;AAI3E,OAAO,EAAC,iBAAiB,EAAC,MAAM,eAAe,CAAC;AAEhD,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,iCAAiC,CACtD,WAAmD,EACnD,KAAmB,EACnB,EAAa,EACb,MAAc,EACd,UAAkB;IAElB,2GAA2G;IAC3G,gFAAgF;IAEhF,sGAAsG;IACtG,MAAM,QAAQ,GAA+C,EAAE,CAAC;IAChE,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC;QACjE,qGAAqG;QACrG,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAE5E,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,KAAK,CAAC,MAAM,CAAC,KAAK,CAChB,8FAA8F,EAC9F;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC;gBAC/B,MAAM,EAAE,UAAU;aACnB,CACF,CAAC;YACF,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,cAAqC,CAAC;IAC1C,IAAI,CAAC;QACH,iGAAiG;QACjG,cAAc,GAAG,MAAM,KAAK,CAAC,sCAAsC,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxF,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,2BAA2B,EAAE,CAAC;YAC7C,MAAM,IAAI,aAAa,CACrB,UAAU,CAAC,oBAAoB,EAC/B,6CAA6C,CAAC,CAAC,OAAO,EAAE,CACzD,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,EAAC,SAAS,EAAE,YAAY,EAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QACxC,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM;gBACJ,IAAI,EAAE,aAAa;gBACnB,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;aAC7E,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,kEAAkE,EAAE;gBACrF,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC;gBAC/B,MAAM,EAAE,UAAU;aACnB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"executionPayloadEnvelopesByRoot.js","sourceRoot":"","sources":["../../../../src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts"],"names":[],"mappings":"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"}
@@ -156,14 +156,18 @@ export declare class BlockInputSync {
156
156
  * Also verifies the received block root + returns the peer that provided the block for future downscoring.
157
157
  */
158
158
  private fetchBlockInput;
159
+ private removePendingPayloadAndDescendants;
159
160
  /**
160
- * Gets all descendant blocks of `block` recursively from `pendingBlocks`.
161
- * Assumes that if a parent block does not exist or is not processable, all descendant blocks are bad too.
162
- * Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
163
- * referenced more than one bad block.
161
+ * Same as `removeAndBanAllDescendants`, and downscores every peer that referenced or served a banned item, once per
162
+ * peer. Only call for consensus-layer invalidity, never for an INVALID execution payload:
163
+ * https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
164
164
  */
165
165
  private removeAndDownScoreAllDescendants;
166
- private removePendingPayloadAndDescendants;
166
+ /**
167
+ * Removes `block` and all its pending descendants and bans their roots in `knownBadBlocks`. Only call when the chain
168
+ * is provably bad: a banned root is never searched for again. Returns the banned items.
169
+ */
170
+ private removeAndBanAllDescendants;
167
171
  private removeAllDescendants;
168
172
  private getMaxDownloadAttempts;
169
173
  }
@@ -1 +1 @@
1
- {"version":3,"file":"unknownBlock.d.ts","sourceRoot":"","sources":["../../src/sync/unknownBlock.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"unknownBlock.d.ts","sourceRoot":"","sources":["../../src/sync/unknownBlock.ts"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@ import { BlockError, BlockErrorCode } from "../chain/errors/index.js";
11
11
  import { ChainEvent } from "../chain/index.js";
12
12
  import { validateGloasBlockDataColumnSidecars } from "../chain/validation/dataColumnSidecar.js";
13
13
  import { validateGossipExecutionPayloadEnvelope } from "../chain/validation/executionPayloadEnvelope.js";
14
- import { NetworkEvent, prettyPrintPeerIdStr } from "../network/index.js";
14
+ import { NetworkEvent, PeerAction, prettyPrintPeerIdStr } from "../network/index.js";
15
15
  import { MAX_PEERS_PER_ROOT } from "../network/processor/constants.js";
16
16
  import { ClockEvent } from "../util/clock.js";
17
17
  import { shuffle } from "../util/shuffle.js";
@@ -378,6 +378,10 @@ export class BlockInputSync {
378
378
  });
379
379
  };
380
380
  addByRootHex = (rootHex, peerIdStr) => {
381
+ if (this.knownBadBlocks.has(rootHex)) {
382
+ this.logger.debug("Ignoring known bad block root", { root: rootHex, peerIdStr: peerIdStr ?? "unknown peer" });
383
+ return false;
384
+ }
381
385
  let pendingBlock = this.pendingBlocks.get(rootHex);
382
386
  let added = false;
383
387
  if (!pendingBlock) {
@@ -409,6 +413,10 @@ export class BlockInputSync {
409
413
  return added;
410
414
  };
411
415
  addByBlockInput = (blockInput, peerIdStr) => {
416
+ if (this.knownBadBlocks.has(blockInput.blockRootHex)) {
417
+ this.logger.debug("Ignoring known bad block", { slot: blockInput.slot, root: blockInput.blockRootHex, peerIdStr });
418
+ return;
419
+ }
412
420
  let pendingBlock = this.pendingBlocks.get(blockInput.blockRootHex);
413
421
  // if entry is missing or was added via rootHex and now we have more complete information overwrite
414
422
  // the existing information with the more complete cache entry
@@ -441,6 +449,14 @@ export class BlockInputSync {
441
449
  }
442
450
  };
443
451
  addByPayloadRootHex = (rootHex, peerIdStr, slot) => {
452
+ if (this.knownBadBlocks.has(rootHex)) {
453
+ this.logger.debug("Ignoring payload for known bad block root", {
454
+ slot: slot ?? "unknown",
455
+ root: rootHex,
456
+ peerIdStr,
457
+ });
458
+ return false;
459
+ }
444
460
  let pendingPayload = this.pendingPayloads.get(rootHex);
445
461
  let added = false;
446
462
  if (!pendingPayload) {
@@ -499,6 +515,14 @@ export class BlockInputSync {
499
515
  return this.chain.seenPayloadEnvelopeInputCache.get(rootHex)?.slot;
500
516
  }
501
517
  addByPayloadInput = (payloadInput, peerIdStr, envelope) => {
518
+ if (this.knownBadBlocks.has(payloadInput.blockRootHex)) {
519
+ this.logger.debug("Ignoring payload input for known bad block root", {
520
+ slot: payloadInput.slot,
521
+ root: payloadInput.blockRootHex,
522
+ peerIdStr,
523
+ });
524
+ return;
525
+ }
502
526
  const pendingPayload = this.toPendingPayloadInput(payloadInput, this.pendingPayloads.get(payloadInput.blockRootHex), envelope);
503
527
  if (peerIdStr && pendingPayload.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
504
528
  pendingPayload.peerIdStrings.add(peerIdStr);
@@ -552,6 +576,7 @@ export class BlockInputSync {
552
576
  if (this.chain.forkChoice.getBlockHexAndBlockHash(parentRootHex, parentBlockHashHex) !== null) {
553
577
  return { kind: "ready" };
554
578
  }
579
+ // The parent's payload is known but does not match `parentBlockHashHex`
555
580
  if (this.chain.forkChoice.hasPayloadHexUnsafe(parentRootHex)) {
556
581
  return { kind: "invalidParentPayload", parentRootHex, parentBlockHashHex };
557
582
  }
@@ -882,7 +907,8 @@ export class BlockInputSync {
882
907
  }
883
908
  else if (blockSlot <= finalizedSlot) {
884
909
  // the common ancestor of the downloading chain and canonical chain should be at least the finalized slot and
885
- // we should found it through forkchoice. If not, we should penalize all peers sending us this block chain
910
+ // we should found it through forkchoice. If not, drop the chain without penalizing peers because pending entries are
911
+ // block retained on failed download, so finalization can pass the block while it is still pending
886
912
  // 0 - 1 - ... - n - finalizedSlot
887
913
  // \
888
914
  // parent 1 - parent 2 - ... - unknownParent block
@@ -890,7 +916,7 @@ export class BlockInputSync {
890
916
  ...logCtx2,
891
917
  finalizedSlot,
892
918
  });
893
- this.removeAndDownScoreAllDescendants(block, DroppedItemReason.belowFinalized);
919
+ this.removeAllDescendants(block, DroppedItemReason.belowFinalized);
894
920
  }
895
921
  else {
896
922
  this.onUnknownBlockRoot({ rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot });
@@ -1009,14 +1035,17 @@ export class BlockInputSync {
1009
1035
  this.removeAllDescendants(pendingBlock, DroppedItemReason.elError, DroppedItemReason.elError);
1010
1036
  break;
1011
1037
  case BlockErrorCode.EXECUTION_ENGINE_INVALID:
1012
- // the peer served a bad block
1038
+ // Ban but do not downscore: optimistic-sync peers may forward and serve blocks whose payload is later
1039
+ // rejected by the execution engine. Per the spec, an INVALID execution payload SHOULD NOT cause a peer
1040
+ // to be down-scored or disconnected, only consensus-layer invalidity MAY.
1041
+ // https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
1013
1042
  this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
1014
- this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
1043
+ this.removeAndBanAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
1015
1044
  break;
1016
1045
  default:
1017
1046
  // Block is not correct with respect to our chain. Log error loudly
1018
1047
  this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
1019
- this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
1048
+ this.removeAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
1020
1049
  }
1021
1050
  }
1022
1051
  // Probably a queue error or something unwanted happened, mark as pending to try again latter
@@ -1254,10 +1283,10 @@ export class BlockInputSync {
1254
1283
  throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: ${reason}`);
1255
1284
  }
1256
1285
  const { peerId, client: peerClient } = peerMeta;
1257
- cacheItem.peerIdStrings.add(peerId);
1258
1286
  try {
1259
1287
  if (!envelope) {
1260
1288
  envelope = await this.fetchExecutionPayloadEnvelope(peerId, blockRoot, rootHex);
1289
+ cacheItem.peerIdStrings.add(peerId);
1261
1290
  const slotWasUnknown = typeof slot !== "number";
1262
1291
  slot = envelope.message.payload.slotNumber;
1263
1292
  if (slotWasUnknown) {
@@ -1292,6 +1321,8 @@ export class BlockInputSync {
1292
1321
  const missing = pendingPayload.payloadInput.getMissingSampledColumnMeta().missing;
1293
1322
  if (missing.length > 0) {
1294
1323
  const columnSidecars = await this.fetchPayloadColumns(peerMeta, pendingPayload.payloadInput, missing);
1324
+ // toPendingPayloadInput copied cacheItem's set, so add to the object that is carried forward
1325
+ pendingPayload.peerIdStrings.add(peerId);
1295
1326
  const seenTimestampSec = Date.now() / 1000;
1296
1327
  for (const columnSidecar of columnSidecars) {
1297
1328
  if (pendingPayload.payloadInput.hasColumn(columnSidecar.index)) {
@@ -1433,7 +1464,6 @@ export class BlockInputSync {
1433
1464
  throw Error(message);
1434
1465
  }
1435
1466
  const { peerId, client: peerClient } = peerMeta;
1436
- cacheItem.peerIdStrings.add(peerId);
1437
1467
  try {
1438
1468
  const downloadResult = await downloadByRoot({
1439
1469
  config: this.config,
@@ -1444,6 +1474,7 @@ export class BlockInputSync {
1444
1474
  cacheItem,
1445
1475
  });
1446
1476
  cacheItem = downloadResult.result;
1477
+ cacheItem.peerIdStrings.add(peerId);
1447
1478
  if (slot === undefined) {
1448
1479
  slot = cacheItem.blockInput.slot;
1449
1480
  // we were not able to observe the time into slot when starting the fetch, do it now
@@ -1545,37 +1576,6 @@ export class BlockInputSync {
1545
1576
  this.metrics?.blockInputSync.fetchPeers.set({ result: FetchResult.FailureMaxAttempts }, i - 1);
1546
1577
  throw Error(message);
1547
1578
  }
1548
- /**
1549
- * Gets all descendant blocks of `block` recursively from `pendingBlocks`.
1550
- * Assumes that if a parent block does not exist or is not processable, all descendant blocks are bad too.
1551
- * Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
1552
- * referenced more than one bad block.
1553
- */
1554
- removeAndDownScoreAllDescendants(block, headReason) {
1555
- // Get all blocks that are a descendant of this one
1556
- const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
1557
- // just console log and do not penalize on pending/bad blocks for debugging
1558
- // console.log("removeAndDownscoreAllDescendants", {block});
1559
- for (const block of badPendingBlocks) {
1560
- //
1561
- // TODO(fulu): why is this commented out here?
1562
- //
1563
- // this.knownBadBlocks.add(block.blockRootHex);
1564
- // for (const peerIdStr of block.peerIdStrings) {
1565
- // // TODO: Refactor peerRpcScores to work with peerIdStr only
1566
- // this.network.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadBlockByRoot");
1567
- // }
1568
- this.logger.debug("ignored Banning unknown block", {
1569
- slot: getBlockInputSyncCacheItemSlot(block),
1570
- root: getBlockInputSyncCacheItemRootHex(block),
1571
- peerIdStrings: Array.from(block.peerIdStrings)
1572
- .map((id) => prettyPrintPeerIdStr(id))
1573
- .join(","),
1574
- });
1575
- }
1576
- // Prune knownBadBlocks
1577
- pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
1578
- }
1579
1579
  // Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
1580
1580
  removePendingPayloadAndDescendants(rootHex, headReason) {
1581
1581
  // Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
@@ -1600,9 +1600,50 @@ export class BlockInputSync {
1600
1600
  });
1601
1601
  }
1602
1602
  }
1603
+ /**
1604
+ * Same as `removeAndBanAllDescendants`, and downscores every peer that referenced or served a banned item, once per
1605
+ * peer. Only call for consensus-layer invalidity, never for an INVALID execution payload:
1606
+ * https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
1607
+ */
1608
+ removeAndDownScoreAllDescendants(block, headReason) {
1609
+ const peersToReport = new Set();
1610
+ for (const bannedBlock of this.removeAndBanAllDescendants(block, headReason)) {
1611
+ for (const peerIdStr of bannedBlock.peerIdStrings) {
1612
+ peersToReport.add(peerIdStr);
1613
+ }
1614
+ }
1615
+ for (const peerIdStr of peersToReport) {
1616
+ this.network.reportPeer(peerIdStr, PeerAction.LowToleranceError, headReason);
1617
+ }
1618
+ }
1619
+ /**
1620
+ * Removes `block` and all its pending descendants and bans their roots in `knownBadBlocks`. Only call when the chain
1621
+ * is provably bad: a banned root is never searched for again. Returns the banned items.
1622
+ */
1623
+ removeAndBanAllDescendants(block, headReason) {
1624
+ const bannedBlocks = [];
1625
+ for (const badBlock of this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent)) {
1626
+ const rootHex = getBlockInputSyncCacheItemRootHex(badBlock);
1627
+ // a gossip import may race a failing sync path, never ban a root fork choice has imported
1628
+ if (this.chain.forkChoice.hasBlockHex(rootHex)) {
1629
+ continue;
1630
+ }
1631
+ this.knownBadBlocks.add(rootHex);
1632
+ bannedBlocks.push(badBlock);
1633
+ this.logger.debug("Banning unknown block", {
1634
+ slot: getBlockInputSyncCacheItemSlot(badBlock),
1635
+ root: rootHex,
1636
+ reason: headReason,
1637
+ peerIdStrings: Array.from(badBlock.peerIdStrings)
1638
+ .map((id) => prettyPrintPeerIdStr(id))
1639
+ .join(","),
1640
+ });
1641
+ }
1642
+ pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
1643
+ return bannedBlocks;
1644
+ }
1603
1645
  removeAllDescendants(block, headReason, descendantReason = DroppedItemReason.invalidParent) {
1604
1646
  const rootHex = getBlockInputSyncCacheItemRootHex(block);
1605
- const slot = getBlockInputSyncCacheItemSlot(block);
1606
1647
  // Get all blocks that are a descendant of this one (index 0 is the head item itself)
1607
1648
  const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
1608
1649
  for (const [i, block] of badPendingBlocks.entries()) {
@@ -1618,8 +1659,8 @@ export class BlockInputSync {
1618
1659
  // Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
1619
1660
  // importBlock()-owned lifecycle.
1620
1661
  this.logger.debug("Removing bad/unknown/incomplete BlockInputSyncCacheItem", {
1621
- slot,
1622
- blockRoot: rootHex,
1662
+ slot: getBlockInputSyncCacheItemSlot(block),
1663
+ root: rootHex,
1623
1664
  });
1624
1665
  }
1625
1666
  return badPendingBlocks;