@lodestar/beacon-node 1.47.0-dev.bd761ec9ea → 1.47.0-dev.beabd3a65c
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 +2 -1
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +2 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +6 -2
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +14 -5
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.js +5 -0
- package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +6 -1
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +28 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +121 -13
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +7 -2
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +7 -1
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +5 -1
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +7 -13
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +16 -11
- 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 +3 -1
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/package.json +31 -31
- package/src/api/impl/beacon/blocks/index.ts +2 -1
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
- package/src/chain/chain.ts +6 -1
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +143 -14
- package/src/metrics/metrics/lodestar.ts +12 -3
- package/src/network/processor/gossipHandlers.ts +5 -1
- package/src/sync/unknownBlock.ts +8 -15
- package/src/sync/utils/downloadByRange.ts +21 -12
- package/src/sync/utils/downloadByRoot.ts +3 -1
package/src/sync/unknownBlock.ts
CHANGED
|
@@ -544,15 +544,7 @@ export class BlockInputSync {
|
|
|
544
544
|
return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
|
|
545
545
|
}
|
|
546
546
|
|
|
547
|
-
|
|
548
|
-
if (parentPayloadInput) {
|
|
549
|
-
if (parentPayloadInput.getBlockHashHex() === parentBlockHashHex) {
|
|
550
|
-
return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
|
|
554
|
-
}
|
|
555
|
-
|
|
547
|
+
// Parent is in fork choice but its payload `parentBlockHashHex` isn't revealed yet
|
|
556
548
|
return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
|
|
557
549
|
}
|
|
558
550
|
|
|
@@ -894,9 +886,9 @@ export class BlockInputSync {
|
|
|
894
886
|
this.pendingBlocks.delete(blockRootHex);
|
|
895
887
|
|
|
896
888
|
if (isForkPostGloas(fork)) {
|
|
897
|
-
const payloadInput = this.chain.seenPayloadEnvelopeInputCache.
|
|
889
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(blockRootHex);
|
|
898
890
|
if (!payloadInput) {
|
|
899
|
-
this.logger.
|
|
891
|
+
this.logger.debug("PayloadEnvelopeInput unavailable during unknown sync processReadyBlock()", logCtx);
|
|
900
892
|
} else {
|
|
901
893
|
// Similar to the gossip path: immediately attempt fetch of data columns from the execution engine.
|
|
902
894
|
// The bid already carries the kzg commitments, so there is no reason to wait for the payload to arrive.
|
|
@@ -969,12 +961,12 @@ export class BlockInputSync {
|
|
|
969
961
|
*/
|
|
970
962
|
private async reconcilePayloadEnvelope(pendingPayload: PendingPayloadEnvelope): Promise<void> {
|
|
971
963
|
const rootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
|
|
964
|
+
|
|
972
965
|
if (this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
|
|
973
966
|
this.pendingPayloads.delete(rootHex);
|
|
974
967
|
return;
|
|
975
968
|
}
|
|
976
969
|
|
|
977
|
-
const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
|
|
978
970
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
979
971
|
// Block not in fork choice yet. payloadInput may be seeded from the block body during download, so a
|
|
980
972
|
// non-null payloadInput does not imply the block is imported; defer regardless and pull the block first.
|
|
@@ -990,8 +982,9 @@ export class BlockInputSync {
|
|
|
990
982
|
return;
|
|
991
983
|
}
|
|
992
984
|
|
|
985
|
+
const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
993
986
|
if (!payloadInput) {
|
|
994
|
-
this.logger.debug("
|
|
987
|
+
this.logger.debug("PayloadEnvelopeInput not yet reloadable for imported block, will retry", {
|
|
995
988
|
root: rootHex,
|
|
996
989
|
});
|
|
997
990
|
return;
|
|
@@ -1187,7 +1180,7 @@ export class BlockInputSync {
|
|
|
1187
1180
|
let slot = getPayloadSyncCacheItemSlot(cacheItem);
|
|
1188
1181
|
let payloadInput = isPendingPayloadInput(cacheItem)
|
|
1189
1182
|
? cacheItem.payloadInput
|
|
1190
|
-
: this.chain.seenPayloadEnvelopeInputCache.
|
|
1183
|
+
: await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
1191
1184
|
let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
|
|
1192
1185
|
|
|
1193
1186
|
let i = 0;
|
|
@@ -1220,7 +1213,7 @@ export class BlockInputSync {
|
|
|
1220
1213
|
slot = envelope.message.payload.slotNumber;
|
|
1221
1214
|
}
|
|
1222
1215
|
|
|
1223
|
-
payloadInput ??= this.chain.seenPayloadEnvelopeInputCache.
|
|
1216
|
+
payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
|
|
1224
1217
|
if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
1225
1218
|
// Block not in fork choice yet. Validating now would throw BLOCK_ROOT_UNKNOWN, so keep the downloaded
|
|
1226
1219
|
// envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
|
|
@@ -136,6 +136,8 @@ export function cacheByRangeResponses({
|
|
|
136
136
|
const source = BlockInputSource.byRange;
|
|
137
137
|
const updatedBatchBlocks = new Map<Slot, IBlockInput>(batchBlocks.map((block) => [block.slot, block]));
|
|
138
138
|
|
|
139
|
+
const payloadEnvelopes = new Map<Slot, PayloadEnvelopeInput>(existingPayloadEnvelopes);
|
|
140
|
+
|
|
139
141
|
const blocks = responses.validatedBlocks ?? [];
|
|
140
142
|
for (let i = 0; i < blocks.length; i++) {
|
|
141
143
|
const {block, blockRoot} = blocks[i];
|
|
@@ -172,15 +174,17 @@ export function cacheByRangeResponses({
|
|
|
172
174
|
// later step) can throw and abort the batch — otherwise a gloas block would sit in
|
|
173
175
|
// seenBlockInputCache but unseeded here, and payload-by-root sync would later throw "Missing
|
|
174
176
|
// PayloadEnvelopeInput for known block" (see issue #9306). add() is idempotent.
|
|
175
|
-
if (isForkPostGloas(blockInput.forkName)) {
|
|
176
|
-
seenPayloadEnvelopeInputCache.add({
|
|
177
|
+
if (isForkPostGloas(blockInput.forkName) && !payloadEnvelopes.has(blockInput.slot)) {
|
|
178
|
+
const payloadInput = seenPayloadEnvelopeInputCache.add({
|
|
177
179
|
blockRootHex: blockInput.blockRootHex,
|
|
178
180
|
block: blockInput.getBlock() as SignedBeaconBlock<ForkPostGloas>,
|
|
179
181
|
forkName: blockInput.forkName,
|
|
180
182
|
sampledColumns: custodyConfig.sampledColumns,
|
|
181
183
|
custodyColumns: custodyConfig.custodyColumns,
|
|
182
|
-
|
|
184
|
+
seenTimestampSec,
|
|
185
|
+
source: PayloadEnvelopeInputSource.byRange,
|
|
183
186
|
});
|
|
187
|
+
payloadEnvelopes.set(blockInput.slot, payloadInput);
|
|
184
188
|
}
|
|
185
189
|
}
|
|
186
190
|
|
|
@@ -222,17 +226,22 @@ export function cacheByRangeResponses({
|
|
|
222
226
|
}
|
|
223
227
|
}
|
|
224
228
|
|
|
225
|
-
let payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null =
|
|
226
|
-
existingPayloadEnvelopes !== null ? new Map(existingPayloadEnvelopes) : null;
|
|
227
229
|
if (downloadedPayloadEnvelopes !== null) {
|
|
228
|
-
payloadEnvelopes ??= new Map();
|
|
229
230
|
for (const [slot, envelope] of downloadedPayloadEnvelopes) {
|
|
230
|
-
|
|
231
|
-
|
|
231
|
+
// the only PayloadEnvelopeInput miss is the dangling parent, which we can get from the seen cache
|
|
232
|
+
let payloadInput = payloadEnvelopes.get(slot);
|
|
232
233
|
if (payloadInput === undefined) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
234
|
+
if (updatedBatchBlocks.has(slot)) {
|
|
235
|
+
throw new Error(
|
|
236
|
+
`Missing PayloadEnvelopeInput for in-batch slot ${slot} root ${toRootHex(envelope.message.beaconBlockRoot)}`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
payloadInput = seenPayloadEnvelopeInputCache.get(toRootHex(envelope.message.beaconBlockRoot));
|
|
240
|
+
}
|
|
241
|
+
if (payloadInput === undefined) {
|
|
242
|
+
throw new Error(
|
|
243
|
+
`Missing PayloadEnvelopeInput for slot ${slot} root ${toRootHex(envelope.message.beaconBlockRoot)}`
|
|
244
|
+
);
|
|
236
245
|
}
|
|
237
246
|
|
|
238
247
|
if (!payloadInput.hasPayloadEnvelope()) {
|
|
@@ -262,7 +271,7 @@ export function cacheByRangeResponses({
|
|
|
262
271
|
// Gloas columns are attached to the matching PayloadEnvelopeInput, NOT to IBlockInput.
|
|
263
272
|
// Gloas DataColumnSidecar has `slot` directly (no signedBlockHeader).
|
|
264
273
|
const dataSlot = firstColumn.slot;
|
|
265
|
-
const payloadInput = payloadEnvelopes
|
|
274
|
+
const payloadInput = payloadEnvelopes.get(dataSlot);
|
|
266
275
|
if (!payloadInput) {
|
|
267
276
|
// Should not happen: we built payloadInputs for all gloas blocks above
|
|
268
277
|
continue;
|
|
@@ -13,6 +13,7 @@ import {BlobIndex, ColumnIndex, SignedBeaconBlock, Slot, deneb, fulu} from "@lod
|
|
|
13
13
|
import {LodestarError, byteArrayEquals, fromHex, prettyPrintIndices, toHex, toRootHex} from "@lodestar/utils";
|
|
14
14
|
import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
|
|
15
15
|
import {BlockInputSource, IBlockInput} from "../../chain/blocks/blockInput/types.js";
|
|
16
|
+
import {PayloadEnvelopeInputSource} from "../../chain/blocks/payloadEnvelopeInput/index.js";
|
|
16
17
|
import {ChainEventEmitter} from "../../chain/emitter.js";
|
|
17
18
|
import {IBeaconChain} from "../../chain/interface.js";
|
|
18
19
|
import {validateBlockBlobSidecars} from "../../chain/validation/blobSidecar.js";
|
|
@@ -122,7 +123,8 @@ export async function downloadByRoot({
|
|
|
122
123
|
forkName: blockInput.forkName,
|
|
123
124
|
sampledColumns: chain.custodyConfig.sampledColumns,
|
|
124
125
|
custodyColumns: chain.custodyConfig.custodyColumns,
|
|
125
|
-
|
|
126
|
+
seenTimestampSec: Date.now() / 1000,
|
|
127
|
+
source: PayloadEnvelopeInputSource.byRoot,
|
|
126
128
|
});
|
|
127
129
|
}
|
|
128
130
|
|