@lodestar/beacon-node 1.43.0-dev.ca1fc40294 → 1.43.0-dev.dfb984e779
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 +3 -2
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.js +1 -1
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +6 -3
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +26 -14
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +73 -77
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.d.ts +5 -3
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +28 -10
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.js +2 -2
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +14 -20
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts +23 -2
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +81 -12
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts +3 -2
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +30 -5
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.js +15 -4
- package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +24 -0
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +76 -0
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
- package/lib/chain/chain.d.ts +3 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +14 -3
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +8 -1
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +2 -0
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +1 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +5 -0
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
- package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/forkChoice/index.js +2 -2
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +3 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +30 -10
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -2
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +34 -13
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +11 -4
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +20 -18
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +1 -0
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +13 -1
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +11 -1
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +1 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +4 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/processor/gossipHandlers.js +4 -6
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/node/notifier.js +7 -1
- package/lib/node/notifier.js.map +1 -1
- package/lib/sync/range/batch.d.ts +12 -2
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +56 -30
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +6 -2
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +4 -3
- 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 +17 -6
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/types.d.ts +34 -0
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js +34 -0
- package/lib/sync/types.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +24 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +649 -53
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts +46 -10
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +147 -24
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRoot.js +6 -2
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
- package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
- package/lib/sync/utils/pendingBlocksTree.js +0 -9
- package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
- package/package.json +16 -15
- package/src/api/impl/beacon/blocks/index.ts +5 -2
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/chain/blocks/importBlock.ts +4 -2
- package/src/chain/blocks/importExecutionPayload.ts +92 -97
- package/src/chain/blocks/index.ts +44 -13
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
- package/src/chain/blocks/types.ts +14 -25
- package/src/chain/blocks/utils/chainSegment.ts +106 -17
- package/src/chain/blocks/verifyBlock.ts +35 -6
- package/src/chain/blocks/verifyBlocksSanityChecks.ts +16 -7
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +129 -0
- package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
- package/src/chain/chain.ts +23 -3
- package/src/chain/errors/blockError.ts +4 -1
- package/src/chain/errors/executionPayloadBid.ts +6 -0
- package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
- package/src/chain/forkChoice/index.ts +2 -2
- package/src/chain/interface.ts +7 -1
- package/src/chain/prepareNextSlot.ts +42 -12
- package/src/chain/produceBlock/produceBlockBody.ts +37 -11
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +22 -20
- package/src/chain/validation/block.ts +1 -0
- package/src/chain/validation/executionPayloadBid.ts +14 -0
- package/src/chain/validation/executionPayloadEnvelope.ts +12 -2
- package/src/metrics/metrics/lodestar.ts +4 -0
- package/src/network/processor/gossipHandlers.ts +6 -6
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
- package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
- package/src/node/notifier.ts +8 -1
- package/src/sync/range/batch.ts +90 -35
- package/src/sync/range/chain.ts +13 -5
- package/src/sync/range/range.ts +18 -6
- package/src/sync/types.ts +72 -0
- package/src/sync/unknownBlock.ts +810 -57
- package/src/sync/utils/downloadByRange.ts +256 -39
- package/src/sync/utils/downloadByRoot.ts +12 -2
- package/src/sync/utils/pendingBlocksTree.ts +0 -15
package/src/sync/range/batch.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {ForkName, isForkPostDeneb, isForkPostFulu} from "@lodestar/params";
|
|
2
|
+
import {ForkName, isForkPostDeneb, isForkPostFulu, isForkPostGloas} from "@lodestar/params";
|
|
3
3
|
import {Epoch, RootHex, Slot, phase0} from "@lodestar/types";
|
|
4
4
|
import {LodestarError} from "@lodestar/utils";
|
|
5
5
|
import {isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
|
|
6
6
|
import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
|
|
7
7
|
import {isDaOutOfRange} from "../../chain/blocks/blockInput/utils.js";
|
|
8
|
+
import {PayloadEnvelopeInput} from "../../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
8
9
|
import {BlockError, BlockErrorCode} from "../../chain/errors/index.js";
|
|
9
10
|
import {PeerSyncMeta} from "../../network/peers/peersData.js";
|
|
10
11
|
import {IClock} from "../../util/clock.js";
|
|
@@ -46,19 +47,36 @@ export type Attempt = {
|
|
|
46
47
|
export type AwaitingDownloadState = {
|
|
47
48
|
status: BatchStatus.AwaitingDownload;
|
|
48
49
|
blocks: IBlockInput[];
|
|
50
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
49
51
|
};
|
|
50
52
|
|
|
51
53
|
export type DownloadSuccessState = {
|
|
52
54
|
status: BatchStatus.AwaitingProcessing;
|
|
53
55
|
blocks: IBlockInput[];
|
|
56
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
54
57
|
};
|
|
55
58
|
|
|
56
59
|
export type BatchState =
|
|
57
60
|
| AwaitingDownloadState
|
|
58
|
-
| {
|
|
61
|
+
| {
|
|
62
|
+
status: BatchStatus.Downloading;
|
|
63
|
+
peer: PeerIdStr;
|
|
64
|
+
blocks: IBlockInput[];
|
|
65
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
66
|
+
}
|
|
59
67
|
| DownloadSuccessState
|
|
60
|
-
| {
|
|
61
|
-
|
|
68
|
+
| {
|
|
69
|
+
status: BatchStatus.Processing;
|
|
70
|
+
blocks: IBlockInput[];
|
|
71
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
72
|
+
attempt: Attempt;
|
|
73
|
+
}
|
|
74
|
+
| {
|
|
75
|
+
status: BatchStatus.AwaitingValidation;
|
|
76
|
+
blocks: IBlockInput[];
|
|
77
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
|
|
78
|
+
attempt: Attempt;
|
|
79
|
+
};
|
|
62
80
|
|
|
63
81
|
export type BatchMetadata = {
|
|
64
82
|
startEpoch: Epoch;
|
|
@@ -85,7 +103,7 @@ export class Batch {
|
|
|
85
103
|
/** Block, blob and column requests that are used to determine the best peer and are used in downloadByRange */
|
|
86
104
|
requests: DownloadByRangeRequests;
|
|
87
105
|
/** State of the batch. */
|
|
88
|
-
state: BatchState = {status: BatchStatus.AwaitingDownload, blocks: []};
|
|
106
|
+
state: BatchState = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
|
|
89
107
|
/** Peers that provided good data */
|
|
90
108
|
goodPeers: PeerIdStr[] = [];
|
|
91
109
|
/** The `Attempts` that have been made and failed to send us this batch. */
|
|
@@ -129,35 +147,33 @@ export class Batch {
|
|
|
129
147
|
count: this.count,
|
|
130
148
|
step: 1,
|
|
131
149
|
};
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
count: this.count,
|
|
138
|
-
columns: this.custodyConfig.sampledColumns,
|
|
139
|
-
},
|
|
140
|
-
};
|
|
150
|
+
const requests: DownloadByRangeRequests = {blocksRequest};
|
|
151
|
+
|
|
152
|
+
// Post-Gloas envelopes are required for block processing, independent of DA retention window.
|
|
153
|
+
if (isForkPostGloas(this.forkName)) {
|
|
154
|
+
requests.envelopesRequest = {startSlot: this.startSlot, count: this.count};
|
|
141
155
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
},
|
|
156
|
+
|
|
157
|
+
if (isForkPostFulu(this.forkName) && withinValidRequestWindow) {
|
|
158
|
+
requests.columnsRequest = {
|
|
159
|
+
startSlot: this.startSlot,
|
|
160
|
+
count: this.count,
|
|
161
|
+
columns: this.custodyConfig.sampledColumns,
|
|
149
162
|
};
|
|
163
|
+
} else if (isForkPostDeneb(this.forkName) && withinValidRequestWindow) {
|
|
164
|
+
requests.blobsRequest = {startSlot: this.startSlot, count: this.count};
|
|
150
165
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
};
|
|
166
|
+
|
|
167
|
+
return requests;
|
|
154
168
|
}
|
|
155
169
|
|
|
156
170
|
// subsequent request where part of the epoch has already been downloaded. Need to figure out what is the beginning
|
|
157
171
|
// of the range where download needs to resume
|
|
158
172
|
let blockStartSlot = this.startSlot;
|
|
159
173
|
let dataStartSlot = this.startSlot;
|
|
174
|
+
let envelopeStartSlot = this.startSlot;
|
|
160
175
|
const neededColumns = new Set<number>();
|
|
176
|
+
const envelopesBySlot = this.state.payloadEnvelopes ?? new Map<Slot, PayloadEnvelopeInput>();
|
|
161
177
|
|
|
162
178
|
// ensure blocks are in slot-wise order
|
|
163
179
|
for (const blockInput of blocks) {
|
|
@@ -175,6 +191,13 @@ export class Batch {
|
|
|
175
191
|
if (blockInput.hasBlock() && blockStartSlot === blockSlot) {
|
|
176
192
|
blockStartSlot = blockSlot + 1;
|
|
177
193
|
}
|
|
194
|
+
if (
|
|
195
|
+
blockInput.hasBlock() &&
|
|
196
|
+
envelopeStartSlot === blockSlot &&
|
|
197
|
+
envelopesBySlot.get(blockSlot)?.hasPayloadEnvelope()
|
|
198
|
+
) {
|
|
199
|
+
envelopeStartSlot = blockSlot + 1;
|
|
200
|
+
}
|
|
178
201
|
if (!blockInput.hasAllData()) {
|
|
179
202
|
if (isBlockInputColumns(blockInput)) {
|
|
180
203
|
for (const index of blockInput.getMissingSampledColumnMeta().missing) {
|
|
@@ -216,6 +239,13 @@ export class Batch {
|
|
|
216
239
|
// dataSlot will still have a value but do not create a request for preDeneb forks
|
|
217
240
|
}
|
|
218
241
|
|
|
242
|
+
if (isForkPostGloas(this.forkName) && envelopeStartSlot <= endSlot) {
|
|
243
|
+
requests.envelopesRequest = {
|
|
244
|
+
startSlot: envelopeStartSlot,
|
|
245
|
+
count: endSlot - envelopeStartSlot + 1,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
219
249
|
return requests;
|
|
220
250
|
}
|
|
221
251
|
|
|
@@ -263,6 +293,10 @@ export class Batch {
|
|
|
263
293
|
return this.state.blocks;
|
|
264
294
|
}
|
|
265
295
|
|
|
296
|
+
getPayloadEnvelopes(): Map<Slot, PayloadEnvelopeInput> | null {
|
|
297
|
+
return this.state.payloadEnvelopes;
|
|
298
|
+
}
|
|
299
|
+
|
|
266
300
|
/**
|
|
267
301
|
* AwaitingDownload -> Downloading
|
|
268
302
|
*/
|
|
@@ -271,13 +305,22 @@ export class Batch {
|
|
|
271
305
|
throw new BatchError(this.wrongStatusErrorType(BatchStatus.AwaitingDownload));
|
|
272
306
|
}
|
|
273
307
|
|
|
274
|
-
this.state = {
|
|
308
|
+
this.state = {
|
|
309
|
+
status: BatchStatus.Downloading,
|
|
310
|
+
peer,
|
|
311
|
+
blocks: this.state.blocks,
|
|
312
|
+
payloadEnvelopes: this.state.payloadEnvelopes,
|
|
313
|
+
};
|
|
275
314
|
}
|
|
276
315
|
|
|
277
316
|
/**
|
|
278
317
|
* Downloading -> AwaitingProcessing
|
|
279
318
|
*/
|
|
280
|
-
downloadingSuccess(
|
|
319
|
+
downloadingSuccess(
|
|
320
|
+
peer: PeerIdStr,
|
|
321
|
+
blocks: IBlockInput[],
|
|
322
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null
|
|
323
|
+
): DownloadSuccessState {
|
|
281
324
|
if (this.state.status !== BatchStatus.Downloading) {
|
|
282
325
|
throw new BatchError(this.wrongStatusErrorType(BatchStatus.Downloading));
|
|
283
326
|
}
|
|
@@ -305,11 +348,13 @@ export class Batch {
|
|
|
305
348
|
status: this.state.status,
|
|
306
349
|
});
|
|
307
350
|
}
|
|
351
|
+
const newPayloadEnvelopes = payloadEnvelopes ?? this.state.payloadEnvelopes;
|
|
352
|
+
|
|
308
353
|
if (allComplete) {
|
|
309
|
-
this.state = {status: BatchStatus.AwaitingProcessing, blocks};
|
|
354
|
+
this.state = {status: BatchStatus.AwaitingProcessing, blocks, payloadEnvelopes: newPayloadEnvelopes};
|
|
310
355
|
} else {
|
|
311
356
|
this.requests = this.getRequests(blocks);
|
|
312
|
-
this.state = {status: BatchStatus.AwaitingDownload, blocks};
|
|
357
|
+
this.state = {status: BatchStatus.AwaitingDownload, blocks, payloadEnvelopes: newPayloadEnvelopes};
|
|
313
358
|
}
|
|
314
359
|
|
|
315
360
|
return this.state as DownloadSuccessState;
|
|
@@ -328,25 +373,30 @@ export class Batch {
|
|
|
328
373
|
throw new BatchError(this.errorType({code: BatchErrorCode.MAX_DOWNLOAD_ATTEMPTS}));
|
|
329
374
|
}
|
|
330
375
|
|
|
331
|
-
this.state = {
|
|
376
|
+
this.state = {
|
|
377
|
+
status: BatchStatus.AwaitingDownload,
|
|
378
|
+
blocks: this.state.blocks,
|
|
379
|
+
payloadEnvelopes: this.state.payloadEnvelopes,
|
|
380
|
+
};
|
|
332
381
|
}
|
|
333
382
|
|
|
334
383
|
/**
|
|
335
384
|
* AwaitingProcessing -> Processing
|
|
336
385
|
*/
|
|
337
|
-
startProcessing(): IBlockInput[] {
|
|
386
|
+
startProcessing(): {blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null} {
|
|
338
387
|
if (this.state.status !== BatchStatus.AwaitingProcessing) {
|
|
339
388
|
throw new BatchError(this.wrongStatusErrorType(BatchStatus.AwaitingProcessing));
|
|
340
389
|
}
|
|
341
390
|
|
|
342
391
|
const blocks = this.state.blocks;
|
|
392
|
+
const payloadEnvelopes = this.state.payloadEnvelopes;
|
|
343
393
|
const hash = hashBlocks(blocks, this.config); // tracks blocks to report peer on processing error
|
|
344
394
|
// Reset goodPeers in case another download attempt needs to be made. When Attempt is successful or not the peers
|
|
345
395
|
// that the data came from will be handled by the Attempt that goes for processing
|
|
346
396
|
const peers = this.goodPeers;
|
|
347
397
|
this.goodPeers = [];
|
|
348
|
-
this.state = {status: BatchStatus.Processing, blocks, attempt: {peers, hash}};
|
|
349
|
-
return blocks;
|
|
398
|
+
this.state = {status: BatchStatus.Processing, blocks, payloadEnvelopes, attempt: {peers, hash}};
|
|
399
|
+
return {blocks, payloadEnvelopes};
|
|
350
400
|
}
|
|
351
401
|
|
|
352
402
|
/**
|
|
@@ -357,7 +407,12 @@ export class Batch {
|
|
|
357
407
|
throw new BatchError(this.wrongStatusErrorType(BatchStatus.Processing));
|
|
358
408
|
}
|
|
359
409
|
|
|
360
|
-
this.state = {
|
|
410
|
+
this.state = {
|
|
411
|
+
status: BatchStatus.AwaitingValidation,
|
|
412
|
+
blocks: this.state.blocks,
|
|
413
|
+
payloadEnvelopes: this.state.payloadEnvelopes,
|
|
414
|
+
attempt: this.state.attempt,
|
|
415
|
+
};
|
|
361
416
|
}
|
|
362
417
|
|
|
363
418
|
/**
|
|
@@ -408,7 +463,7 @@ export class Batch {
|
|
|
408
463
|
|
|
409
464
|
// remove any downloaded blocks and re-attempt
|
|
410
465
|
// TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
|
|
411
|
-
this.state = {status: BatchStatus.AwaitingDownload, blocks: []};
|
|
466
|
+
this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
|
|
412
467
|
}
|
|
413
468
|
|
|
414
469
|
private onProcessingError(attempt: Attempt): void {
|
|
@@ -419,7 +474,7 @@ export class Batch {
|
|
|
419
474
|
|
|
420
475
|
// remove any downloaded blocks and re-attempt
|
|
421
476
|
// TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
|
|
422
|
-
this.state = {status: BatchStatus.AwaitingDownload, blocks: []};
|
|
477
|
+
this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
|
|
423
478
|
}
|
|
424
479
|
|
|
425
480
|
/** Helper to construct typed BatchError. Stack traces are correct as the error is thrown above */
|
package/src/sync/range/chain.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {ErrorAborted, LodestarError, Logger, toRootHex} from "@lodestar/utils";
|
|
|
4
4
|
import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
|
|
5
5
|
import {BlockInputErrorCode} from "../../chain/blocks/blockInput/errors.js";
|
|
6
6
|
import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
|
|
7
|
+
import {PayloadEnvelopeInput} from "../../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
7
8
|
import {BlobSidecarErrorCode} from "../../chain/errors/blobSidecarError.js";
|
|
8
9
|
import {DataColumnSidecarErrorCode} from "../../chain/errors/dataColumnSidecarError.js";
|
|
9
10
|
import {Metrics} from "../../metrics/metrics.js";
|
|
@@ -44,13 +45,19 @@ export type SyncChainFns = {
|
|
|
44
45
|
* Must return if ALL blocks are processed successfully
|
|
45
46
|
* If SOME blocks are processed must throw BlockProcessorError()
|
|
46
47
|
*/
|
|
47
|
-
processChainSegment: (
|
|
48
|
+
processChainSegment: (
|
|
49
|
+
blocks: IBlockInput[],
|
|
50
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
51
|
+
syncType: RangeSyncType
|
|
52
|
+
) => Promise<void>;
|
|
48
53
|
/** Must download blocks, and validate their range */
|
|
49
54
|
downloadByRange: (
|
|
50
55
|
peer: PeerSyncMeta,
|
|
51
56
|
batch: Batch,
|
|
52
57
|
syncType: RangeSyncType
|
|
53
|
-
) => Promise<
|
|
58
|
+
) => Promise<
|
|
59
|
+
WarnResult<{blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null}, DownloadByRangeError>
|
|
60
|
+
>;
|
|
54
61
|
/** Report peer for negative actions. Decouples from the full network instance */
|
|
55
62
|
reportPeer: (peer: PeerIdStr, action: PeerAction, actionName: string) => void;
|
|
56
63
|
/** Gets current peer custodyColumns and earliestAvailableSlot */
|
|
@@ -516,7 +523,8 @@ export class SyncChain {
|
|
|
516
523
|
});
|
|
517
524
|
this.metrics?.syncRange.downloadByRange.success.inc();
|
|
518
525
|
const {warnings, result} = res.result;
|
|
519
|
-
const
|
|
526
|
+
const {blocks: downloadedBlocks, payloadEnvelopes} = result;
|
|
527
|
+
const downloadSuccessOutput = batch.downloadingSuccess(peer.peerId, downloadedBlocks, payloadEnvelopes);
|
|
520
528
|
const logMeta: Record<string, number> = {
|
|
521
529
|
blockCount: downloadSuccessOutput.blocks.length,
|
|
522
530
|
};
|
|
@@ -578,10 +586,10 @@ export class SyncChain {
|
|
|
578
586
|
* Sends `batch` to the processor. Note: batch may be empty
|
|
579
587
|
*/
|
|
580
588
|
private async processBatch(batch: Batch): Promise<void> {
|
|
581
|
-
const blocks = batch.startProcessing();
|
|
589
|
+
const {blocks, payloadEnvelopes} = batch.startProcessing();
|
|
582
590
|
|
|
583
591
|
// wrapError ensures to never call both batch success() and batch error()
|
|
584
|
-
const res = await wrapError(this.processChainSegment(blocks, this.syncType));
|
|
592
|
+
const res = await wrapError(this.processChainSegment(blocks, payloadEnvelopes, this.syncType));
|
|
585
593
|
|
|
586
594
|
if (!res.err) {
|
|
587
595
|
batch.processingSuccess();
|
package/src/sync/range/range.ts
CHANGED
|
@@ -172,7 +172,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
/** Convenience method for `SyncChain` */
|
|
175
|
-
private processChainSegment: SyncChainFns["processChainSegment"] = async (blocks, syncType) => {
|
|
175
|
+
private processChainSegment: SyncChainFns["processChainSegment"] = async (blocks, payloadEnvelopes, syncType) => {
|
|
176
176
|
// Not trusted, verify signatures
|
|
177
177
|
const flags: ImportBlockOpts = {
|
|
178
178
|
// Only skip importing attestations for finalized sync. For head sync attestation are valuable.
|
|
@@ -192,9 +192,15 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
192
192
|
|
|
193
193
|
if (this.opts?.disableProcessAsChainSegment) {
|
|
194
194
|
// Should only be used for debugging or testing
|
|
195
|
-
for (const block of blocks)
|
|
195
|
+
for (const block of blocks) {
|
|
196
|
+
await this.chain.processBlock(block, flags);
|
|
197
|
+
const payloadEnvelope = payloadEnvelopes?.get(block.slot);
|
|
198
|
+
if (payloadEnvelope) {
|
|
199
|
+
await this.chain.processExecutionPayload(payloadEnvelope);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
196
202
|
} else {
|
|
197
|
-
await this.chain.processChainSegment(blocks, flags);
|
|
203
|
+
await this.chain.processChainSegment(blocks, payloadEnvelopes, flags);
|
|
198
204
|
}
|
|
199
205
|
};
|
|
200
206
|
|
|
@@ -209,13 +215,19 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
209
215
|
peerDasMetrics: this.chain.metrics?.peerDas,
|
|
210
216
|
...batch.getRequestsForPeer(peer),
|
|
211
217
|
});
|
|
212
|
-
const
|
|
218
|
+
const {responses, payloadEnvelopes: downloadedPayloadEnvelopes} = result;
|
|
219
|
+
const {blocks, payloadEnvelopes} = cacheByRangeResponses({
|
|
213
220
|
cache: this.chain.seenBlockInputCache,
|
|
221
|
+
seenPayloadEnvelopeInputCache: this.chain.seenPayloadEnvelopeInputCache,
|
|
214
222
|
peerIdStr: peer.peerId,
|
|
215
|
-
responses
|
|
223
|
+
responses,
|
|
216
224
|
batchBlocks,
|
|
225
|
+
downloadedPayloadEnvelopes,
|
|
226
|
+
existingPayloadEnvelopes: batch.getPayloadEnvelopes(),
|
|
227
|
+
custodyConfig: this.chain.custodyConfig,
|
|
228
|
+
seenTimestampSec: Date.now() / 1000,
|
|
217
229
|
});
|
|
218
|
-
return {result:
|
|
230
|
+
return {result: {blocks, payloadEnvelopes}, warnings};
|
|
219
231
|
};
|
|
220
232
|
|
|
221
233
|
private pruneBlockInputs: SyncChainFns["pruneBlockInputs"] = (blocks: IBlockInput[]) => {
|
package/src/sync/types.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import {RootHex, Slot} from "@lodestar/types";
|
|
2
|
+
import {SignedExecutionPayloadEnvelope} from "@lodestar/types/gloas";
|
|
3
|
+
import {toRootHex} from "@lodestar/utils";
|
|
2
4
|
import {IBlockInput} from "../chain/blocks/blockInput/index.js";
|
|
5
|
+
import {PayloadEnvelopeInput} from "../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
3
6
|
|
|
4
7
|
export enum PendingBlockType {
|
|
5
8
|
/**
|
|
@@ -26,6 +29,14 @@ export enum PendingBlockInputStatus {
|
|
|
26
29
|
processing = "processing",
|
|
27
30
|
}
|
|
28
31
|
|
|
32
|
+
export enum PendingPayloadInputStatus {
|
|
33
|
+
pending = "pending",
|
|
34
|
+
fetching = "fetching",
|
|
35
|
+
waitingForBlock = "waiting_for_block",
|
|
36
|
+
downloaded = "downloaded",
|
|
37
|
+
processing = "processing",
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
export type PendingBlockInput = {
|
|
30
41
|
status: PendingBlockInputStatus;
|
|
31
42
|
blockInput: IBlockInput;
|
|
@@ -44,10 +55,47 @@ export type PendingRootHex = {
|
|
|
44
55
|
|
|
45
56
|
export type BlockInputSyncCacheItem = PendingBlockInput | PendingRootHex;
|
|
46
57
|
|
|
58
|
+
export type PendingPayloadInput = {
|
|
59
|
+
status:
|
|
60
|
+
| PendingPayloadInputStatus.pending
|
|
61
|
+
| PendingPayloadInputStatus.fetching
|
|
62
|
+
| PendingPayloadInputStatus.downloaded
|
|
63
|
+
| PendingPayloadInputStatus.processing;
|
|
64
|
+
payloadInput: PayloadEnvelopeInput;
|
|
65
|
+
timeAddedSec: number;
|
|
66
|
+
timeSyncedSec?: number;
|
|
67
|
+
peerIdStrings: Set<string>;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export type PendingPayloadRootHex = {
|
|
71
|
+
status: PendingPayloadInputStatus.pending | PendingPayloadInputStatus.fetching;
|
|
72
|
+
rootHex: RootHex;
|
|
73
|
+
timeAddedSec: number;
|
|
74
|
+
timeSyncedSec?: number;
|
|
75
|
+
peerIdStrings: Set<string>;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export type PendingPayloadEnvelope = {
|
|
79
|
+
status: PendingPayloadInputStatus.waitingForBlock;
|
|
80
|
+
envelope: SignedExecutionPayloadEnvelope;
|
|
81
|
+
timeAddedSec: number;
|
|
82
|
+
peerIdStrings: Set<string>;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export type PayloadSyncCacheItem = PendingPayloadInput | PendingPayloadRootHex | PendingPayloadEnvelope;
|
|
86
|
+
|
|
47
87
|
export function isPendingBlockInput(pending: BlockInputSyncCacheItem): pending is PendingBlockInput {
|
|
48
88
|
return "blockInput" in pending;
|
|
49
89
|
}
|
|
50
90
|
|
|
91
|
+
export function isPendingPayloadInput(pending: PayloadSyncCacheItem): pending is PendingPayloadInput {
|
|
92
|
+
return "payloadInput" in pending;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function isPendingPayloadEnvelope(pending: PayloadSyncCacheItem): pending is PendingPayloadEnvelope {
|
|
96
|
+
return "envelope" in pending;
|
|
97
|
+
}
|
|
98
|
+
|
|
51
99
|
export function getBlockInputSyncCacheItemRootHex(block: BlockInputSyncCacheItem): RootHex {
|
|
52
100
|
return isPendingBlockInput(block) ? block.blockInput.blockRootHex : block.rootHex;
|
|
53
101
|
}
|
|
@@ -55,3 +103,27 @@ export function getBlockInputSyncCacheItemRootHex(block: BlockInputSyncCacheItem
|
|
|
55
103
|
export function getBlockInputSyncCacheItemSlot(block: BlockInputSyncCacheItem): Slot | string {
|
|
56
104
|
return isPendingBlockInput(block) ? block.blockInput.slot : "unknown";
|
|
57
105
|
}
|
|
106
|
+
|
|
107
|
+
export function getPayloadSyncCacheItemRootHex(payload: PayloadSyncCacheItem): RootHex {
|
|
108
|
+
if (isPendingPayloadInput(payload)) {
|
|
109
|
+
return payload.payloadInput.blockRootHex;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (isPendingPayloadEnvelope(payload)) {
|
|
113
|
+
return toRootHex(payload.envelope.message.beaconBlockRoot);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return payload.rootHex;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function getPayloadSyncCacheItemSlot(payload: PayloadSyncCacheItem): Slot | string {
|
|
120
|
+
if (isPendingPayloadInput(payload)) {
|
|
121
|
+
return payload.payloadInput.slot;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (isPendingPayloadEnvelope(payload)) {
|
|
125
|
+
return payload.envelope.message.payload.slotNumber;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return "unknown";
|
|
129
|
+
}
|