@lodestar/beacon-node 1.49.0-dev.4d35c8b82e → 1.49.0-dev.57ffc39074

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 (128) hide show
  1. package/lib/api/impl/beacon/blocks/index.js +2 -2
  2. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  3. package/lib/api/impl/validator/index.d.ts.map +1 -1
  4. package/lib/api/impl/validator/index.js +9 -7
  5. package/lib/api/impl/validator/index.js.map +1 -1
  6. package/lib/chain/archiveStore/historicalState/metrics.d.ts.map +1 -1
  7. package/lib/chain/archiveStore/historicalState/metrics.js +4 -0
  8. package/lib/chain/archiveStore/historicalState/metrics.js.map +1 -1
  9. package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
  10. package/lib/chain/archiveStore/utils/pruneHistory.js +14 -3
  11. package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
  12. package/lib/chain/blocks/index.js +2 -2
  13. package/lib/chain/blocks/index.js.map +1 -1
  14. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +1 -1
  15. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  16. package/lib/chain/emitter.d.ts +10 -0
  17. package/lib/chain/emitter.d.ts.map +1 -1
  18. package/lib/chain/emitter.js +4 -0
  19. package/lib/chain/emitter.js.map +1 -1
  20. package/lib/chain/errors/attesterSlashingError.d.ts +4 -1
  21. package/lib/chain/errors/attesterSlashingError.d.ts.map +1 -1
  22. package/lib/chain/errors/attesterSlashingError.js +1 -0
  23. package/lib/chain/errors/attesterSlashingError.js.map +1 -1
  24. package/lib/chain/errors/payloadAttestation.d.ts +4 -0
  25. package/lib/chain/errors/payloadAttestation.d.ts.map +1 -1
  26. package/lib/chain/errors/payloadAttestation.js +1 -0
  27. package/lib/chain/errors/payloadAttestation.js.map +1 -1
  28. package/lib/chain/errors/proposerSlashingError.d.ts +4 -1
  29. package/lib/chain/errors/proposerSlashingError.d.ts.map +1 -1
  30. package/lib/chain/errors/proposerSlashingError.js +1 -0
  31. package/lib/chain/errors/proposerSlashingError.js.map +1 -1
  32. package/lib/chain/options.d.ts +0 -4
  33. package/lib/chain/options.d.ts.map +1 -1
  34. package/lib/chain/options.js +0 -1
  35. package/lib/chain/options.js.map +1 -1
  36. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  37. package/lib/chain/produceBlock/produceBlockBody.js +6 -6
  38. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  39. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +2 -1
  40. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  41. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +3 -2
  42. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  43. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  44. package/lib/chain/validation/attesterSlashing.js +1 -2
  45. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  46. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  47. package/lib/chain/validation/payloadAttestationMessage.js +8 -1
  48. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  49. package/lib/chain/validation/proposerSlashing.js +1 -2
  50. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  51. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  52. package/lib/chain/validatorMonitor.js +2 -2
  53. package/lib/chain/validatorMonitor.js.map +1 -1
  54. package/lib/db/repositories/blockArchive.d.ts +5 -0
  55. package/lib/db/repositories/blockArchive.d.ts.map +1 -1
  56. package/lib/db/repositories/blockArchive.js +36 -1
  57. package/lib/db/repositories/blockArchive.js.map +1 -1
  58. package/lib/metrics/metrics/lodestar.d.ts +19 -4
  59. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  60. package/lib/metrics/metrics/lodestar.js +38 -1
  61. package/lib/metrics/metrics/lodestar.js.map +1 -1
  62. package/lib/network/gossip/encoding.d.ts +1 -2
  63. package/lib/network/gossip/encoding.d.ts.map +1 -1
  64. package/lib/network/gossip/encoding.js +5 -10
  65. package/lib/network/gossip/encoding.js.map +1 -1
  66. package/lib/network/gossip/gossipsub.d.ts.map +1 -1
  67. package/lib/network/gossip/gossipsub.js +16 -1
  68. package/lib/network/gossip/gossipsub.js.map +1 -1
  69. package/lib/network/gossip/topic.d.ts +9 -6
  70. package/lib/network/gossip/topic.d.ts.map +1 -1
  71. package/lib/network/gossip/topic.js +23 -8
  72. package/lib/network/gossip/topic.js.map +1 -1
  73. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  74. package/lib/network/processor/gossipHandlers.js +16 -5
  75. package/lib/network/processor/gossipHandlers.js.map +1 -1
  76. package/lib/network/processor/gossipValidatorFn.d.ts +2 -0
  77. package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
  78. package/lib/network/processor/gossipValidatorFn.js +88 -7
  79. package/lib/network/processor/gossipValidatorFn.js.map +1 -1
  80. package/lib/network/processor/index.d.ts +6 -2
  81. package/lib/network/processor/index.d.ts.map +1 -1
  82. package/lib/network/processor/index.js +62 -24
  83. package/lib/network/processor/index.js.map +1 -1
  84. package/lib/network/reqresp/protocols.d.ts.map +1 -1
  85. package/lib/network/reqresp/protocols.js +19 -5
  86. package/lib/network/reqresp/protocols.js.map +1 -1
  87. package/lib/sync/types.d.ts +39 -0
  88. package/lib/sync/types.d.ts.map +1 -1
  89. package/lib/sync/types.js +42 -0
  90. package/lib/sync/types.js.map +1 -1
  91. package/lib/sync/unknownBlock.d.ts +16 -0
  92. package/lib/sync/unknownBlock.d.ts.map +1 -1
  93. package/lib/sync/unknownBlock.js +186 -13
  94. package/lib/sync/unknownBlock.js.map +1 -1
  95. package/lib/util/sszBytes.d.ts +5 -0
  96. package/lib/util/sszBytes.d.ts.map +1 -1
  97. package/lib/util/sszBytes.js +13 -1
  98. package/lib/util/sszBytes.js.map +1 -1
  99. package/package.json +14 -14
  100. package/src/api/impl/beacon/blocks/index.ts +2 -2
  101. package/src/api/impl/validator/index.ts +9 -7
  102. package/src/chain/archiveStore/historicalState/metrics.ts +4 -0
  103. package/src/chain/archiveStore/utils/pruneHistory.ts +14 -4
  104. package/src/chain/blocks/index.ts +2 -2
  105. package/src/chain/blocks/payloadEnvelopeInput/types.ts +1 -1
  106. package/src/chain/emitter.ts +7 -2
  107. package/src/chain/errors/attesterSlashingError.ts +3 -1
  108. package/src/chain/errors/payloadAttestation.ts +2 -0
  109. package/src/chain/errors/proposerSlashingError.ts +3 -1
  110. package/src/chain/options.ts +0 -5
  111. package/src/chain/produceBlock/produceBlockBody.ts +17 -6
  112. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +3 -2
  113. package/src/chain/validation/attesterSlashing.ts +1 -2
  114. package/src/chain/validation/payloadAttestationMessage.ts +9 -0
  115. package/src/chain/validation/proposerSlashing.ts +1 -2
  116. package/src/chain/validatorMonitor.ts +12 -2
  117. package/src/db/repositories/blockArchive.ts +38 -1
  118. package/src/metrics/metrics/lodestar.ts +46 -3
  119. package/src/network/gossip/encoding.ts +5 -8
  120. package/src/network/gossip/gossipsub.ts +19 -2
  121. package/src/network/gossip/topic.ts +25 -7
  122. package/src/network/processor/gossipHandlers.ts +18 -5
  123. package/src/network/processor/gossipValidatorFn.ts +111 -7
  124. package/src/network/processor/index.ts +81 -24
  125. package/src/network/reqresp/protocols.ts +31 -6
  126. package/src/sync/types.ts +44 -3
  127. package/src/sync/unknownBlock.ts +209 -13
  128. package/src/util/sszBytes.ts +18 -0
@@ -6,6 +6,10 @@ import { INetwork } from "../network/index.js";
6
6
  import { PeerSyncMeta } from "../network/peers/peersData.js";
7
7
  import { PeerIdStr } from "../util/peerId.js";
8
8
  import { SyncOptions } from "./options.js";
9
+ /**
10
+ * Poll pending payloads of the current slot this often, between PAYLOAD_DUE and the end of the slot.
11
+ */
12
+ export declare const PAYLOAD_POLL_INTERVAL_MS = 1000;
9
13
  /**
10
14
  * BlockInputSync is a class that handles ReqResp to find blocks and data related to a specific blockRoot. The
11
15
  * blockRoot may have been found via object gossip, or the API. Gossip objects that can trigger a search are block,
@@ -55,6 +59,11 @@ export declare class BlockInputSync {
55
59
  private subscribedToNetworkEvents;
56
60
  private peerBalancer;
57
61
  private rateLimitBackoffTimeout;
62
+ /**
63
+ * Search unknown payload starting at PAYLOAD_DUE_BPS.
64
+ */
65
+ private readonly deferredPayloadRoots;
66
+ private payloadPollAbortController;
58
67
  constructor(config: ChainForkConfig, network: INetwork, chain: IBeaconChain, logger: Logger, metrics: Metrics | null, opts?: SyncOptions | undefined);
59
68
  subscribeToNetwork(): void;
60
69
  unsubscribeFromNetwork(): void;
@@ -69,6 +78,7 @@ export declare class BlockInputSync {
69
78
  */
70
79
  private onIncompleteBlockInput;
71
80
  private onUnknownEnvelopeBlockRoot;
81
+ private onUnknownEnvelopeBlockRootSlot;
72
82
  private onIncompletePayloadEnvelope;
73
83
  /**
74
84
  * Process an unknownBlockParent event and register the block in `pendingBlocks` Map.
@@ -104,6 +114,12 @@ export declare class BlockInputSync {
104
114
  private triggerUnknownBlockSearch;
105
115
  private scheduleRateLimitBackoffRetry;
106
116
  private clearRateLimitBackoffTimer;
117
+ private onClockSlot;
118
+ /**
119
+ * Poll unknown payloads of the current slot.
120
+ */
121
+ private pollPayloadsAtSlot;
122
+ private addDeferredPayloadRoot;
107
123
  private downloadBlock;
108
124
  /**
109
125
  * Import a block that has already passed the local dependency checks in BlockInputSync.
@@ -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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"}
@@ -2,7 +2,7 @@ import { routes } from "@lodestar/api";
2
2
  import { ForkSeq, SLOTS_PER_EPOCH, isForkPostGloas } from "@lodestar/params";
3
3
  import { RequestError, RequestErrorCode } from "@lodestar/reqresp";
4
4
  import { computeTimeAtSlot } from "@lodestar/state-transition";
5
- import { fromHex, prettyPrintIndices, pruneSetToMax, sleep, toRootHex } from "@lodestar/utils";
5
+ import { fromHex, isErrorAborted, prettyPrintIndices, pruneSetToMax, sleep, toRootHex } from "@lodestar/utils";
6
6
  import { isBlockInputBlobs, isBlockInputColumns } from "../chain/blocks/blockInput/blockInput.js";
7
7
  import { BlockInputSource } from "../chain/blocks/blockInput/types.js";
8
8
  import { PayloadError, PayloadErrorCode } from "../chain/blocks/importExecutionPayload.js";
@@ -13,11 +13,12 @@ import { validateGloasBlockDataColumnSidecars } from "../chain/validation/dataCo
13
13
  import { validateGossipExecutionPayloadEnvelope } from "../chain/validation/executionPayloadEnvelope.js";
14
14
  import { NetworkEvent, prettyPrintPeerIdStr } from "../network/index.js";
15
15
  import { MAX_PEERS_PER_ROOT } from "../network/processor/constants.js";
16
+ import { ClockEvent } from "../util/clock.js";
16
17
  import { shuffle } from "../util/shuffle.js";
17
18
  import { sortBy } from "../util/sortBy.js";
18
19
  import { wrapError } from "../util/wrapError.js";
19
20
  import { MAX_CONCURRENT_REQUESTS } from "./constants.js";
20
- import { DroppedItemReason, PendingBlockInputStatus, PendingBlockType, PendingPayloadInputStatus, getBlockInputSyncCacheItemRootHex, getBlockInputSyncCacheItemSlot, getPayloadSyncCacheItemRootHex, getPayloadSyncCacheItemSlot, isPendingBlockInput, isPendingPayloadEnvelope, isPendingPayloadInput, } from "./types.js";
21
+ import { DeferredPayloadResult, DownloadResult, DroppedItemReason, FetchResult, PendingBlockInputStatus, PendingBlockType, PendingPayloadInputStatus, getBlockInputSyncCacheItemRootHex, getBlockInputSyncCacheItemSlot, getPayloadSyncCacheItemRootHex, getPayloadSyncCacheItemSlot, isPendingBlockInput, isPendingPayloadEnvelope, isPendingPayloadInput, } from "./types.js";
21
22
  import { DownloadByRootError, downloadByRoot } from "./utils/downloadByRoot.js";
22
23
  import { getAllDescendantBlocks, getUnknownAndAncestorBlocks } from "./utils/pendingBlocksTree.js";
23
24
  import { getRateLimitedUntilMs } from "./utils/rateLimit.js";
@@ -28,14 +29,10 @@ const MAX_PENDING_BLOCKS = 100;
28
29
  * A pending payload without slot can only stay at most 2 epochs.
29
30
  */
30
31
  const PRUNE_UNRESOLVED_SLOT_EPOCHS = 2;
31
- var FetchResult;
32
- (function (FetchResult) {
33
- FetchResult["SuccessResolved"] = "success_resolved";
34
- FetchResult["SuccessMissingParent"] = "success_missing_parent";
35
- FetchResult["SuccessLate"] = "success_late";
36
- FetchResult["FailureTriedAllPeers"] = "failure_tried_all_peers";
37
- FetchResult["FailureMaxAttempts"] = "failure_max_attempts";
38
- })(FetchResult || (FetchResult = {}));
32
+ /**
33
+ * Poll pending payloads of the current slot this often, between PAYLOAD_DUE and the end of the slot.
34
+ */
35
+ export const PAYLOAD_POLL_INTERVAL_MS = 1_000;
39
36
  class UnknownBlockRateLimitedError extends Error {
40
37
  constructor(message) {
41
38
  super(message);
@@ -92,6 +89,11 @@ export class BlockInputSync {
92
89
  subscribedToNetworkEvents = false;
93
90
  peerBalancer;
94
91
  rateLimitBackoffTimeout;
92
+ /**
93
+ * Search unknown payload starting at PAYLOAD_DUE_BPS.
94
+ */
95
+ deferredPayloadRoots = new Map();
96
+ payloadPollAbortController;
95
97
  constructor(config, network, chain, logger, metrics, opts) {
96
98
  this.config = config;
97
99
  this.network = network;
@@ -117,6 +119,7 @@ export class BlockInputSync {
117
119
  this.logger.verbose("BlockInputSync enabled.");
118
120
  this.chain.emitter.on(ChainEvent.unknownBlockRoot, this.onUnknownBlockRoot);
119
121
  this.chain.emitter.on(ChainEvent.unknownEnvelopeBlockRoot, this.onUnknownEnvelopeBlockRoot);
122
+ this.chain.emitter.on(ChainEvent.unknownEnvelopeBlockRootSlot, this.onUnknownEnvelopeBlockRootSlot);
120
123
  this.chain.emitter.on(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
121
124
  this.chain.emitter.on(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
122
125
  this.chain.emitter.on(ChainEvent.blockUnknownParent, this.onUnknownParent);
@@ -125,6 +128,7 @@ export class BlockInputSync {
125
128
  this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
126
129
  this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
127
130
  this.network.events.on(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
131
+ this.chain.clock.on(ClockEvent.slot, this.onClockSlot);
128
132
  // Seed the balancer with peers that connected before we subscribed
129
133
  for (const peerId of this.network.getConnectedPeers()) {
130
134
  try {
@@ -135,13 +139,21 @@ export class BlockInputSync {
135
139
  }
136
140
  }
137
141
  this.subscribedToNetworkEvents = true;
142
+ // we subscribe mid-slot, and a root can be deferred at any point in the slot, so start this
143
+ // slot's loop now instead of waiting for the next ClockEvent.slot
144
+ this.onClockSlot(this.chain.clock.currentSlot);
138
145
  }
139
146
  }
140
147
  unsubscribeFromNetwork() {
141
148
  this.logger.verbose("BlockInputSync disabled.");
142
149
  this.clearRateLimitBackoffTimer();
150
+ this.chain.clock.off(ClockEvent.slot, this.onClockSlot);
151
+ this.payloadPollAbortController?.abort();
152
+ this.payloadPollAbortController = undefined;
153
+ this.deferredPayloadRoots.clear();
143
154
  this.chain.emitter.off(ChainEvent.unknownBlockRoot, this.onUnknownBlockRoot);
144
155
  this.chain.emitter.off(ChainEvent.unknownEnvelopeBlockRoot, this.onUnknownEnvelopeBlockRoot);
156
+ this.chain.emitter.off(ChainEvent.unknownEnvelopeBlockRootSlot, this.onUnknownEnvelopeBlockRootSlot);
145
157
  this.chain.emitter.off(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
146
158
  this.chain.emitter.off(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
147
159
  this.chain.emitter.off(ChainEvent.blockUnknownParent, this.onUnknownParent);
@@ -202,6 +214,33 @@ export class BlockInputSync {
202
214
  this.logger.debug("Error handling unknownEnvelopeBlockRoot event", {}, e);
203
215
  }
204
216
  };
217
+ onUnknownEnvelopeBlockRootSlot = (data) => {
218
+ try {
219
+ if (data.slot === this.chain.clock.currentSlot) {
220
+ // we receive the optimistic search, the poll loop searches it at PAYLOAD_DUE or on its next
221
+ // tick. If that loop already returned - every root it watched was imported - this root waits
222
+ // for the next slot, where onClockSlot moves it to pendingPayloads. That is not the normal
223
+ // scenario, and in a forking condition it only delays the search of the extra root
224
+ const deferred = this.deferredPayloadRoots.get(data.rootHex);
225
+ if (deferred === undefined) {
226
+ this.deferredPayloadRoots.set(data.rootHex, { slot: data.slot, source: data.source, peer: data.peer });
227
+ }
228
+ else if (deferred.peer === undefined) {
229
+ deferred.peer = data.peer;
230
+ }
231
+ return;
232
+ }
233
+ const isNewRoot = this.addByPayloadRootHex(data.rootHex, data.peer, data.slot);
234
+ if (isNewRoot) {
235
+ this.triggerUnknownBlockSearch();
236
+ this.metrics?.blockInputSync.requests.inc({ type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT_SLOT });
237
+ this.metrics?.blockInputSync.payloadSource.inc({ source: data.source });
238
+ }
239
+ }
240
+ catch (e) {
241
+ this.logger.debug("Error handling unknownEnvelopeBlockRootSlot event", {}, e);
242
+ }
243
+ };
205
244
  onIncompletePayloadEnvelope = (data) => {
206
245
  try {
207
246
  this.addByPayloadInput(data.payloadInput, data.peer);
@@ -660,6 +699,111 @@ export class BlockInputSync {
660
699
  this.rateLimitBackoffTimeout = undefined;
661
700
  }
662
701
  }
702
+ onClockSlot = (slot) => {
703
+ if (!isForkPostGloas(this.config.getForkName(slot))) {
704
+ return;
705
+ }
706
+ // end the previous slot's loop, wherever it is: its sleep is bound to this same controller
707
+ this.payloadPollAbortController?.abort();
708
+ this.payloadPollAbortController = new AbortController();
709
+ // entries from an earlier slot is not polled
710
+ for (const [rootHex, { slot: deferredSlot, source, peer }] of this.deferredPayloadRoots) {
711
+ if (deferredSlot < slot) {
712
+ if (!this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
713
+ this.addDeferredPayloadRoot(rootHex, deferredSlot, source, peer);
714
+ }
715
+ this.deferredPayloadRoots.delete(rootHex);
716
+ }
717
+ }
718
+ this.pollPayloadsAtSlot(slot, this.payloadPollAbortController.signal).catch((e) => {
719
+ if (!isErrorAborted(e)) {
720
+ this.logger.debug("Error polling payloads", { slot }, e);
721
+ }
722
+ });
723
+ };
724
+ /**
725
+ * Poll unknown payloads of the current slot.
726
+ */
727
+ async pollPayloadsAtSlot(slot, signal) {
728
+ // fixed tick count so the loop cannot outlive its slot: for mainnet, it's 6 ticks
729
+ const tickCount = Math.floor((this.config.SLOT_DURATION_MS - this.config.getPayloadDueMs()) / PAYLOAD_POLL_INTERVAL_MS);
730
+ // a root still missing on several ticks is searched on each of them, recorded once
731
+ const searchedRoots = new Set();
732
+ let polls = 0;
733
+ try {
734
+ await sleep(Math.max(0, this.config.getPayloadDueMs() - this.chain.clock.msFromSlot(slot)), signal);
735
+ for (polls = 0; polls < tickCount; polls++) {
736
+ let importedCount = 0;
737
+ for (const [rootHex, { slot: deferredSlot, source, peer }] of this.deferredPayloadRoots) {
738
+ if (this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
739
+ importedCount++;
740
+ continue;
741
+ }
742
+ // copy to the regular pendingPayloads so that we can search
743
+ this.addDeferredPayloadRoot(rootHex, deferredSlot, source, peer);
744
+ searchedRoots.add(rootHex);
745
+ }
746
+ // an empty deferredPayloadRoots means there is no optimistic search comes before PAYLOAD_DUE
747
+ // we have to poll until the payload of current slot is imported or slot end
748
+ if (this.deferredPayloadRoots.size > 0 && importedCount === this.deferredPayloadRoots.size) {
749
+ if (searchedRoots.size > 0) {
750
+ // the backup search was needed
751
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({
752
+ result: DeferredPayloadResult.ImportedAfterSearch,
753
+ });
754
+ this.metrics?.blockInputSync.deferredPayloadPolls.observe(polls);
755
+ this.logger.verbose("Payload imported after unknown sync search", {
756
+ slot,
757
+ roots: Array.from(searchedRoots).join(","),
758
+ polls,
759
+ });
760
+ }
761
+ else {
762
+ // this happens most of the time on devnet
763
+ // gossip delivered everything before PAYLOAD_DUE
764
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({
765
+ result: DeferredPayloadResult.ImportedBeforeSearch,
766
+ });
767
+ }
768
+ return;
769
+ }
770
+ this.triggerUnknownBlockSearch();
771
+ if (polls < tickCount - 1) {
772
+ // no sleep after the last tick: the loop would otherwise end right at the slot boundary,
773
+ // where onClockSlot aborts it
774
+ await sleep(PAYLOAD_POLL_INTERVAL_MS, signal);
775
+ }
776
+ }
777
+ // reaching here means the early return never fired
778
+ if (this.deferredPayloadRoots.size > 0) {
779
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({ result: DeferredPayloadResult.Unresolved });
780
+ this.logger.debug("Deferred payloads still missing at end of slot", {
781
+ slot,
782
+ roots: Array.from(this.deferredPayloadRoots.keys()).join(","),
783
+ });
784
+ }
785
+ else {
786
+ // no optimistic search and no payload import ended the loop, eg a skipped slot
787
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({ result: DeferredPayloadResult.ResolvedNoRoot });
788
+ this.logger.debug("No deferred payloads at slot", {
789
+ slot,
790
+ });
791
+ }
792
+ }
793
+ catch (e) {
794
+ if (!isErrorAborted(e)) {
795
+ throw e;
796
+ }
797
+ this.logger.verbose("Payload poll aborted", { slot, polls, msIntoSlot: this.chain.clock.msFromSlot(slot) });
798
+ }
799
+ }
800
+ addDeferredPayloadRoot(rootHex, slot, source, peer) {
801
+ const isNewRoot = this.addByPayloadRootHex(rootHex, peer, slot);
802
+ if (isNewRoot) {
803
+ this.metrics?.blockInputSync.requests.inc({ type: PendingBlockType.DEFERRED_PAYLOAD_BLOCK_ROOT });
804
+ this.metrics?.blockInputSync.payloadSource.inc({ source });
805
+ }
806
+ }
663
807
  async downloadBlock(block) {
664
808
  if (block.status !== PendingBlockInputStatus.pending) {
665
809
  return;
@@ -946,14 +1090,22 @@ export class BlockInputSync {
946
1090
  return;
947
1091
  }
948
1092
  this.pendingPayloads.set(resultRootHex, pendingPayload);
1093
+ const result = isPendingPayloadEnvelope(pendingPayload)
1094
+ ? DownloadResult.WaitingForBlock
1095
+ : this.chain.forkChoice.hasPayloadHexUnsafe(resultRootHex)
1096
+ ? DownloadResult.Late
1097
+ : DownloadResult.Resolved;
1098
+ this.metrics?.blockInputSync.downloadedPayloadsResult.inc({ result });
949
1099
  if (isPendingPayloadEnvelope(pendingPayload)) {
950
1100
  await this.reconcilePayloadEnvelope(pendingPayload);
951
1101
  }
952
1102
  else if (pendingPayload.status === PendingPayloadInputStatus.downloaded) {
1103
+ this.metrics?.blockInputSync.elapsedTimeTillPayloadReceived.observe(Date.now() / 1000 - computeTimeAtSlot(this.config, pendingPayload.payloadInput.slot, this.chain.genesisTime));
953
1104
  await this.processPayload(pendingPayload);
954
1105
  }
955
1106
  return;
956
1107
  }
1108
+ this.metrics?.blockInputSync.downloadedPayloadsResult.inc({ result: DownloadResult.Failed });
957
1109
  this.logger.debug("Ignoring unknown payload root after failed download", logCtx, res.err);
958
1110
  if (!isPendingPayloadEnvelope(payload)) {
959
1111
  payload.status = PendingPayloadInputStatus.pending;
@@ -1050,6 +1202,10 @@ export class BlockInputSync {
1050
1202
  ? cacheItem.payloadInput
1051
1203
  : await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
1052
1204
  let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
1205
+ const fetchStartSec = Date.now() / 1000;
1206
+ if (typeof slot === "number") {
1207
+ this.metrics?.blockInputSync.payloadFetchBegin.observe(this.chain.clock.secFromSlot(slot, fetchStartSec));
1208
+ }
1053
1209
  let i = 0;
1054
1210
  let deferredByRateLimit = false;
1055
1211
  while (i++ < this.getMaxDownloadAttempts()) {
@@ -1065,6 +1221,8 @@ export class BlockInputSync {
1065
1221
  const reason = pendingColumns.size > 0
1066
1222
  ? `cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`
1067
1223
  : "no peer available to download pending payload";
1224
+ this.metrics?.blockInputSync.payloadFetchTime.observe({ result: FetchResult.FailureTriedAllPeers }, Date.now() / 1000 - fetchStartSec);
1225
+ this.metrics?.blockInputSync.payloadFetchPeers.set({ result: FetchResult.FailureTriedAllPeers }, i);
1068
1226
  throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: ${reason}`);
1069
1227
  }
1070
1228
  const { peerId, client: peerClient } = peerMeta;
@@ -1072,7 +1230,12 @@ export class BlockInputSync {
1072
1230
  try {
1073
1231
  if (!envelope) {
1074
1232
  envelope = await this.fetchExecutionPayloadEnvelope(peerId, blockRoot, rootHex);
1233
+ const slotWasUnknown = typeof slot !== "number";
1075
1234
  slot = envelope.message.payload.slotNumber;
1235
+ if (slotWasUnknown) {
1236
+ // we were not able to observe the time into slot when starting the fetch, do it now
1237
+ this.metrics?.blockInputSync.payloadFetchBegin.observe(this.chain.clock.secFromSlot(slot, fetchStartSec));
1238
+ }
1076
1239
  }
1077
1240
  payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
1078
1241
  if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
@@ -1080,6 +1243,8 @@ export class BlockInputSync {
1080
1243
  // envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
1081
1244
  // payloadInput may be seeded from the block body during download, so a non-null payloadInput does not
1082
1245
  // imply the block is imported.
1246
+ this.metrics?.blockInputSync.payloadFetchTime.observe({ result: FetchResult.SuccessWaitingForBlock }, Date.now() / 1000 - fetchStartSec);
1247
+ this.metrics?.blockInputSync.payloadFetchPeers.set({ result: FetchResult.SuccessWaitingForBlock }, i);
1083
1248
  return {
1084
1249
  status: PendingPayloadInputStatus.waitingForBlock,
1085
1250
  envelope,
@@ -1124,6 +1289,12 @@ export class BlockInputSync {
1124
1289
  hasAllData: pendingPayload.payloadInput.hasAllData(),
1125
1290
  });
1126
1291
  if (pendingPayload.status === PendingPayloadInputStatus.downloaded) {
1292
+ // late = the payload got imported (via gossip) while we were downloading, same as the block path
1293
+ const result = this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)
1294
+ ? FetchResult.SuccessLate
1295
+ : FetchResult.SuccessResolved;
1296
+ this.metrics?.blockInputSync.payloadFetchTime.observe({ result }, Date.now() / 1000 - fetchStartSec);
1297
+ this.metrics?.blockInputSync.payloadFetchPeers.set({ result }, i);
1127
1298
  return pendingPayload;
1128
1299
  }
1129
1300
  cacheItem = pendingPayload;
@@ -1155,6 +1326,8 @@ export class BlockInputSync {
1155
1326
  this.peerBalancer.onRequestCompleted(peerId);
1156
1327
  }
1157
1328
  }
1329
+ this.metrics?.blockInputSync.payloadFetchTime.observe({ result: FetchResult.FailureMaxAttempts }, Date.now() / 1000 - fetchStartSec);
1330
+ this.metrics?.blockInputSync.payloadFetchPeers.set({ result: FetchResult.FailureMaxAttempts }, i - 1);
1158
1331
  if (deferredByRateLimit && this.peerBalancer.getNextRateLimitRetryAt() !== null) {
1159
1332
  throw new UnknownBlockRateLimitedError(`Error fetching payload with slot=${slot} root=${rootHex} after ${i - 1} attempts: peers are rate-limited`);
1160
1333
  }
@@ -1227,7 +1400,7 @@ export class BlockInputSync {
1227
1400
  }
1228
1401
  // no more peer with needed columns to try, throw error
1229
1402
  const message = `Error fetching UnknownBlockRoot slot=${slot} root=${rootHex} after ${i}: cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`;
1230
- this.metrics?.blockInputSync.fetchTimeSec.observe({ result: FetchResult.FailureTriedAllPeers }, Date.now() / 1000 - fetchStartSec);
1403
+ this.metrics?.blockInputSync.fetchTime.observe({ result: FetchResult.FailureTriedAllPeers }, Date.now() / 1000 - fetchStartSec);
1231
1404
  this.metrics?.blockInputSync.fetchPeers.set({ result: FetchResult.FailureTriedAllPeers }, i);
1232
1405
  throw Error(message);
1233
1406
  }
@@ -1309,7 +1482,7 @@ export class BlockInputSync {
1309
1482
  : this.chain.forkChoice.hasBlockHex(cacheItem.blockInput.parentRootHex)
1310
1483
  ? FetchResult.SuccessResolved
1311
1484
  : FetchResult.SuccessMissingParent;
1312
- this.metrics?.blockInputSync.fetchTimeSec.observe({ result }, Date.now() / 1000 - fetchStartSec);
1485
+ this.metrics?.blockInputSync.fetchTime.observe({ result }, Date.now() / 1000 - fetchStartSec);
1313
1486
  this.metrics?.blockInputSync.fetchPeers.set({ result }, i);
1314
1487
  return cacheItem;
1315
1488
  }
@@ -1336,7 +1509,7 @@ export class BlockInputSync {
1336
1509
  throw new Error(`${message} Missing column indices=${prettyPrintIndices(missing)}.`);
1337
1510
  }
1338
1511
  }
1339
- this.metrics?.blockInputSync.fetchTimeSec.observe({ result: FetchResult.FailureMaxAttempts }, Date.now() / 1000 - fetchStartSec);
1512
+ this.metrics?.blockInputSync.fetchTime.observe({ result: FetchResult.FailureMaxAttempts }, Date.now() / 1000 - fetchStartSec);
1340
1513
  this.metrics?.blockInputSync.fetchPeers.set({ result: FetchResult.FailureMaxAttempts }, i - 1);
1341
1514
  throw Error(message);
1342
1515
  }