@lodestar/beacon-node 1.37.0-dev.194afd5582 → 1.37.0-dev.2d3601648b

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 (63) hide show
  1. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  2. package/lib/chain/blocks/importBlock.js +2 -0
  3. package/lib/chain/blocks/importBlock.js.map +1 -1
  4. package/lib/chain/blocks/writeBlockInputToDb.d.ts.map +1 -1
  5. package/lib/chain/blocks/writeBlockInputToDb.js +14 -1
  6. package/lib/chain/blocks/writeBlockInputToDb.js.map +1 -1
  7. package/lib/chain/seenCache/seenGossipBlockInput.d.ts +4 -1
  8. package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
  9. package/lib/chain/seenCache/seenGossipBlockInput.js +19 -1
  10. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  11. package/lib/chain/validation/blobSidecar.d.ts.map +1 -1
  12. package/lib/chain/validation/blobSidecar.js +28 -23
  13. package/lib/chain/validation/blobSidecar.js.map +1 -1
  14. package/lib/chain/validation/block.d.ts.map +1 -1
  15. package/lib/chain/validation/block.js +10 -7
  16. package/lib/chain/validation/block.js.map +1 -1
  17. package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
  18. package/lib/chain/validation/dataColumnSidecar.js +30 -25
  19. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  20. package/lib/network/interface.d.ts +3 -3
  21. package/lib/network/interface.d.ts.map +1 -1
  22. package/lib/network/network.d.ts +3 -3
  23. package/lib/network/network.d.ts.map +1 -1
  24. package/lib/network/network.js +3 -3
  25. package/lib/network/network.js.map +1 -1
  26. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  27. package/lib/network/processor/gossipHandlers.js +2 -0
  28. package/lib/network/processor/gossipHandlers.js.map +1 -1
  29. package/lib/network/reqresp/utils/collect.d.ts +3 -3
  30. package/lib/network/reqresp/utils/collect.d.ts.map +1 -1
  31. package/lib/network/reqresp/utils/collect.js +7 -3
  32. package/lib/network/reqresp/utils/collect.js.map +1 -1
  33. package/lib/network/reqresp/utils/collectSequentialBlocksInRange.d.ts +3 -2
  34. package/lib/network/reqresp/utils/collectSequentialBlocksInRange.d.ts.map +1 -1
  35. package/lib/network/reqresp/utils/collectSequentialBlocksInRange.js +5 -3
  36. package/lib/network/reqresp/utils/collectSequentialBlocksInRange.js.map +1 -1
  37. package/lib/sync/backfill/backfill.d.ts.map +1 -1
  38. package/lib/sync/backfill/backfill.js +37 -14
  39. package/lib/sync/backfill/backfill.js.map +1 -1
  40. package/lib/sync/backfill/verify.d.ts +4 -4
  41. package/lib/sync/backfill/verify.d.ts.map +1 -1
  42. package/lib/sync/backfill/verify.js +6 -6
  43. package/lib/sync/backfill/verify.js.map +1 -1
  44. package/lib/sync/utils/downloadByRange.js +1 -1
  45. package/lib/sync/utils/downloadByRange.js.map +1 -1
  46. package/lib/sync/utils/downloadByRoot.js +1 -1
  47. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  48. package/package.json +14 -14
  49. package/src/chain/blocks/importBlock.ts +3 -0
  50. package/src/chain/blocks/writeBlockInputToDb.ts +13 -1
  51. package/src/chain/seenCache/seenGossipBlockInput.ts +21 -1
  52. package/src/chain/validation/blobSidecar.ts +32 -25
  53. package/src/chain/validation/block.ts +11 -7
  54. package/src/chain/validation/dataColumnSidecar.ts +37 -29
  55. package/src/network/interface.ts +2 -9
  56. package/src/network/network.ts +8 -9
  57. package/src/network/processor/gossipHandlers.ts +2 -0
  58. package/src/network/reqresp/utils/collect.ts +12 -6
  59. package/src/network/reqresp/utils/collectSequentialBlocksInRange.ts +10 -6
  60. package/src/sync/backfill/backfill.ts +40 -16
  61. package/src/sync/backfill/verify.ts +10 -10
  62. package/src/sync/utils/downloadByRange.ts +1 -1
  63. package/src/sync/utils/downloadByRoot.ts +1 -1
@@ -134,16 +134,20 @@ export async function validateGossipBlobSidecar(
134
134
  });
135
135
  });
136
136
 
137
- // [REJECT] The proposer signature, signed_beacon_block.signature, is valid with respect to the proposer_index pubkey.
138
- const signatureSet = getBlockHeaderProposerSignatureSetByParentStateSlot(blockState, blobSidecar.signedBlockHeader);
139
- // Don't batch so verification is not delayed
140
- if (!(await chain.bls.verifySignatureSets([signatureSet], {verifyOnMainThread: true}))) {
141
- throw new BlobSidecarGossipError(GossipAction.REJECT, {
142
- code: BlobSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID,
143
- blockRoot: blockHex,
144
- index: blobSidecar.index,
145
- slot: blobSlot,
146
- });
137
+ if (!chain.seenBlockInputCache.isVerifiedProposerSignature(blobSlot, blockHex)) {
138
+ // [REJECT] The proposer signature, signed_beacon_block.signature, is valid with respect to the proposer_index pubkey.
139
+ const signatureSet = getBlockHeaderProposerSignatureSetByParentStateSlot(blockState, blobSidecar.signedBlockHeader);
140
+ // Don't batch so verification is not delayed
141
+ if (!(await chain.bls.verifySignatureSets([signatureSet], {verifyOnMainThread: true}))) {
142
+ throw new BlobSidecarGossipError(GossipAction.REJECT, {
143
+ code: BlobSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID,
144
+ blockRoot: blockHex,
145
+ index: blobSidecar.index,
146
+ slot: blobSlot,
147
+ });
148
+ }
149
+
150
+ chain.seenBlockInputCache.markVerifiedProposerSignature(blobSlot, blockHex);
147
151
  }
148
152
 
149
153
  // verify if the blob inclusion proof is correct
@@ -231,22 +235,25 @@ export async function validateBlockBlobSidecars(
231
235
  }
232
236
 
233
237
  if (chain !== null) {
234
- const headState = await chain.getHeadState();
235
- const signatureSet = getBlockHeaderProposerSignatureSetByHeaderSlot(headState, firstSidecarSignedBlockHeader);
238
+ const blockRootHex = toRootHex(blockRoot);
239
+ if (!chain.seenBlockInputCache.isVerifiedProposerSignature(blockSlot, blockRootHex)) {
240
+ const headState = await chain.getHeadState();
241
+ const signatureSet = getBlockHeaderProposerSignatureSetByHeaderSlot(headState, firstSidecarSignedBlockHeader);
236
242
 
237
- if (
238
- !(await chain.bls.verifySignatureSets([signatureSet], {
239
- batchable: true,
240
- priority: true,
241
- verifyOnMainThread: false,
242
- }))
243
- ) {
244
- throw new BlobSidecarValidationError({
245
- code: BlobSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID,
246
- blockRoot: toRootHex(blockRoot),
247
- slot: blockSlot,
248
- index: blobSidecars[0].index,
249
- });
243
+ if (
244
+ !(await chain.bls.verifySignatureSets([signatureSet], {
245
+ verifyOnMainThread: true,
246
+ }))
247
+ ) {
248
+ throw new BlobSidecarValidationError({
249
+ code: BlobSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID,
250
+ blockRoot: blockRootHex,
251
+ slot: blockSlot,
252
+ index: blobSidecars[0].index,
253
+ });
254
+ }
255
+
256
+ chain.seenBlockInputCache.markVerifiedProposerSignature(blockSlot, blockRootHex);
250
257
  }
251
258
  }
252
259
 
@@ -153,13 +153,17 @@ export async function validateGossipBlock(
153
153
  }
154
154
 
155
155
  // [REJECT] The proposer signature, signed_beacon_block.signature, is valid with respect to the proposer_index pubkey.
156
- const signatureSet = getBlockProposerSignatureSet(blockState, signedBlock);
157
- // Don't batch so verification is not delayed
158
- if (!(await chain.bls.verifySignatureSets([signatureSet], {verifyOnMainThread: true}))) {
159
- throw new BlockGossipError(GossipAction.REJECT, {
160
- code: BlockErrorCode.PROPOSAL_SIGNATURE_INVALID,
161
- blockSlot,
162
- });
156
+ if (!chain.seenBlockInputCache.isVerifiedProposerSignature(blockSlot, blockRoot)) {
157
+ const signatureSet = getBlockProposerSignatureSet(blockState, signedBlock);
158
+ // Don't batch so verification is not delayed
159
+ if (!(await chain.bls.verifySignatureSets([signatureSet], {verifyOnMainThread: true}))) {
160
+ throw new BlockGossipError(GossipAction.REJECT, {
161
+ code: BlockErrorCode.PROPOSAL_SIGNATURE_INVALID,
162
+ blockSlot,
163
+ });
164
+ }
165
+
166
+ chain.seenBlockInputCache.markVerifiedProposerSignature(blockSlot, blockRoot);
163
167
  }
164
168
 
165
169
  // [REJECT] The block is proposed by the expected proposer_index for the block's slot in the context of the current
@@ -32,6 +32,7 @@ export async function validateGossipDataColumnSidecar(
32
32
  metrics: Metrics | null
33
33
  ): Promise<void> {
34
34
  const blockHeader = dataColumnSidecar.signedBlockHeader.message;
35
+ const blockRootHex = toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader));
35
36
 
36
37
  // 1) [REJECT] The sidecar is valid as verified by verify_data_column_sidecar
37
38
  verifyDataColumnSidecar(chain.config, dataColumnSidecar);
@@ -135,20 +136,23 @@ export async function validateGossipDataColumnSidecar(
135
136
  blockState,
136
137
  dataColumnSidecar.signedBlockHeader
137
138
  );
138
- // Don't batch so verification is not delayed
139
- if (
140
- !(await chain.bls.verifySignatureSets([signatureSet], {
141
- verifyOnMainThread: blockHeader.slot > chain.forkChoice.getHead().slot,
142
- }))
143
- ) {
144
- const blockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(dataColumnSidecar.signedBlockHeader.message);
145
- const blockRootHex = toRootHex(blockRoot);
146
- throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
147
- code: DataColumnSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID,
148
- blockRoot: blockRootHex,
149
- index: dataColumnSidecar.index,
150
- slot: blockHeader.slot,
151
- });
139
+
140
+ if (!chain.seenBlockInputCache.isVerifiedProposerSignature(blockHeader.slot, blockRootHex)) {
141
+ if (
142
+ !(await chain.bls.verifySignatureSets([signatureSet], {
143
+ // verify on main thread so that we only need to verify block proposer signature once per block
144
+ verifyOnMainThread: true,
145
+ }))
146
+ ) {
147
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
148
+ code: DataColumnSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID,
149
+ blockRoot: blockRootHex,
150
+ index: dataColumnSidecar.index,
151
+ slot: blockHeader.slot,
152
+ });
153
+ }
154
+
155
+ chain.seenBlockInputCache.markVerifiedProposerSignature(blockHeader.slot, blockRootHex);
152
156
  }
153
157
 
154
158
  // 9) [REJECT] The current finalized_checkpoint is an ancestor of the sidecar's block
@@ -326,22 +330,26 @@ export async function validateBlockDataColumnSidecars(
326
330
  }
327
331
 
328
332
  if (chain !== null) {
329
- const headState = await chain.getHeadState();
330
- const signatureSet = getBlockHeaderProposerSignatureSetByHeaderSlot(headState, firstSidecarSignedBlockHeader);
333
+ const rootHex = toRootHex(blockRoot);
334
+ const slot = firstSidecarSignedBlockHeader.message.slot;
335
+ if (!chain.seenBlockInputCache.isVerifiedProposerSignature(slot, rootHex)) {
336
+ const headState = await chain.getHeadState();
337
+ const signatureSet = getBlockHeaderProposerSignatureSetByHeaderSlot(headState, firstSidecarSignedBlockHeader);
338
+
339
+ if (
340
+ !(await chain.bls.verifySignatureSets([signatureSet], {
341
+ verifyOnMainThread: true,
342
+ }))
343
+ ) {
344
+ throw new DataColumnSidecarValidationError({
345
+ code: DataColumnSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID,
346
+ blockRoot: rootHex,
347
+ slot: blockSlot,
348
+ index: dataColumnSidecars[0].index,
349
+ });
350
+ }
331
351
 
332
- if (
333
- !(await chain.bls.verifySignatureSets([signatureSet], {
334
- batchable: true,
335
- priority: true,
336
- verifyOnMainThread: false,
337
- }))
338
- ) {
339
- throw new DataColumnSidecarValidationError({
340
- code: DataColumnSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID,
341
- blockRoot: toRootHex(blockRoot),
342
- slot: blockSlot,
343
- index: dataColumnSidecars[0].index,
344
- });
352
+ chain.seenBlockInputCache.markVerifiedProposerSignature(slot, rootHex);
345
353
  }
346
354
  }
347
355
 
@@ -27,7 +27,6 @@ import {
27
27
  Slot,
28
28
  SlotRootHex,
29
29
  SubnetID,
30
- WithBytes,
31
30
  altair,
32
31
  capella,
33
32
  deneb,
@@ -69,14 +68,8 @@ export interface INetwork extends INetworkCorePublic {
69
68
  reStatusPeers(peers: PeerIdStr[]): Promise<void>;
70
69
  searchUnknownSlotRoot(slotRoot: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void;
71
70
  // ReqResp
72
- sendBeaconBlocksByRange(
73
- peerId: PeerIdStr,
74
- request: phase0.BeaconBlocksByRangeRequest
75
- ): Promise<WithBytes<SignedBeaconBlock>[]>;
76
- sendBeaconBlocksByRoot(
77
- peerId: PeerIdStr,
78
- request: BeaconBlocksByRootRequest
79
- ): Promise<WithBytes<SignedBeaconBlock>[]>;
71
+ sendBeaconBlocksByRange(peerId: PeerIdStr, request: phase0.BeaconBlocksByRangeRequest): Promise<SignedBeaconBlock[]>;
72
+ sendBeaconBlocksByRoot(peerId: PeerIdStr, request: BeaconBlocksByRootRequest): Promise<SignedBeaconBlock[]>;
80
73
  sendBlobSidecarsByRange(peerId: PeerIdStr, request: deneb.BlobSidecarsByRangeRequest): Promise<deneb.BlobSidecar[]>;
81
74
  sendBlobSidecarsByRoot(peerId: PeerIdStr, request: BlobSidecarsByRootRequest): Promise<deneb.BlobSidecar[]>;
82
75
  sendDataColumnSidecarsByRange(
@@ -20,7 +20,6 @@ import {
20
20
  SingleAttestation,
21
21
  SlotRootHex,
22
22
  SubnetID,
23
- WithBytes,
24
23
  altair,
25
24
  capella,
26
25
  deneb,
@@ -513,7 +512,7 @@ export class Network implements INetwork {
513
512
  async sendBeaconBlocksByRange(
514
513
  peerId: PeerIdStr,
515
514
  request: phase0.BeaconBlocksByRangeRequest
516
- ): Promise<WithBytes<SignedBeaconBlock>[]> {
515
+ ): Promise<SignedBeaconBlock[]> {
517
516
  return collectSequentialBlocksInRange(
518
517
  this.sendReqRespRequest(
519
518
  peerId,
@@ -526,10 +525,7 @@ export class Network implements INetwork {
526
525
  );
527
526
  }
528
527
 
529
- async sendBeaconBlocksByRoot(
530
- peerId: PeerIdStr,
531
- request: BeaconBlocksByRootRequest
532
- ): Promise<WithBytes<SignedBeaconBlock>[]> {
528
+ async sendBeaconBlocksByRoot(peerId: PeerIdStr, request: BeaconBlocksByRootRequest): Promise<SignedBeaconBlock[]> {
533
529
  return collectMaxResponseTypedWithBytes(
534
530
  this.sendReqRespRequest(
535
531
  peerId,
@@ -539,7 +535,8 @@ export class Network implements INetwork {
539
535
  request
540
536
  ),
541
537
  request.length,
542
- responseSszTypeByMethod[ReqRespMethod.BeaconBlocksByRoot]
538
+ responseSszTypeByMethod[ReqRespMethod.BeaconBlocksByRoot],
539
+ this.chain.serializedCache
543
540
  );
544
541
  }
545
542
 
@@ -592,7 +589,8 @@ export class Network implements INetwork {
592
589
  return collectMaxResponseTyped(
593
590
  this.sendReqRespRequest(peerId, ReqRespMethod.BlobSidecarsByRoot, [Version.V1], request),
594
591
  request.length,
595
- responseSszTypeByMethod[ReqRespMethod.BlobSidecarsByRoot]
592
+ responseSszTypeByMethod[ReqRespMethod.BlobSidecarsByRoot],
593
+ this.chain.serializedCache
596
594
  );
597
595
  }
598
596
 
@@ -614,7 +612,8 @@ export class Network implements INetwork {
614
612
  return collectMaxResponseTyped(
615
613
  this.sendReqRespRequest(peerId, ReqRespMethod.DataColumnSidecarsByRoot, [Version.V1], request),
616
614
  request.reduce((total, {columns}) => total + columns.length, 0),
617
- responseSszTypeByMethod[ReqRespMethod.DataColumnSidecarsByRoot]
615
+ responseSszTypeByMethod[ReqRespMethod.DataColumnSidecarsByRoot],
616
+ this.chain.serializedCache
618
617
  );
619
618
  }
620
619
 
@@ -516,6 +516,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
516
516
  throw new GossipActionError(GossipAction.REJECT, {code: "PRE_DENEB_BLOCK"});
517
517
  }
518
518
  const blockInput = await validateBeaconBlob(blobSidecar, topic.subnet, peerIdStr, seenTimestampSec);
519
+ chain.serializedCache.set(blobSidecar, serializedData);
519
520
  if (!blockInput.hasBlockAndAllData()) {
520
521
  const cutoffTimeMs = getCutoffTimeMs(chain, blobSlot, BLOCK_AVAILABILITY_CUTOFF_MS);
521
522
  chain.logger.debug("Received gossip blob, waiting for full data availability", {
@@ -562,6 +563,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
562
563
  peerIdStr,
563
564
  seenTimestampSec
564
565
  );
566
+ chain.serializedCache.set(dataColumnSidecar, serializedData);
565
567
  const blockInputMeta = blockInput.getLogMeta();
566
568
  const {receivedColumns} = blockInputMeta;
567
569
  // it's not helpful to track every single column received
@@ -1,6 +1,6 @@
1
1
  import {Type} from "@chainsafe/ssz";
2
2
  import {RequestError, RequestErrorCode, ResponseIncoming} from "@lodestar/reqresp";
3
- import {WithBytes} from "@lodestar/types";
3
+ import {SerializedCache} from "../../../util/serializedCache.ts";
4
4
  import {ResponseTypeGetter} from "../types.js";
5
5
 
6
6
  /**
@@ -32,13 +32,16 @@ export async function collectExactOneTyped<T>(
32
32
  export async function collectMaxResponseTyped<T>(
33
33
  source: AsyncIterable<ResponseIncoming>,
34
34
  maxResponses: number,
35
- typeFn: ResponseTypeGetter<T>
35
+ typeFn: ResponseTypeGetter<T>,
36
+ serializedCache?: SerializedCache
36
37
  ): Promise<T[]> {
37
38
  // else: zero or more responses
38
39
  const responses: T[] = [];
39
40
  for await (const chunk of source) {
40
41
  const type = typeFn(chunk.fork, chunk.protocolVersion);
41
42
  const response = sszDeserializeResponse(type, chunk.data);
43
+ // optionally cache the serialized response if the cache is available
44
+ serializedCache?.set(response as object, chunk.data);
42
45
  responses.push(response);
43
46
 
44
47
  if (maxResponses !== undefined && responses.length >= maxResponses) {
@@ -58,14 +61,17 @@ export async function collectMaxResponseTyped<T>(
58
61
  export async function collectMaxResponseTypedWithBytes<T>(
59
62
  source: AsyncIterable<ResponseIncoming>,
60
63
  maxResponses: number,
61
- typeFn: ResponseTypeGetter<T>
62
- ): Promise<WithBytes<T>[]> {
64
+ typeFn: ResponseTypeGetter<T>,
65
+ serializedCache?: SerializedCache
66
+ ): Promise<T[]> {
63
67
  // else: zero or more responses
64
- const responses: WithBytes<T>[] = [];
68
+ const responses: T[] = [];
65
69
  for await (const chunk of source) {
66
70
  const type = typeFn(chunk.fork, chunk.protocolVersion);
67
71
  const data = sszDeserializeResponse(type, chunk.data);
68
- responses.push({data, bytes: chunk.data});
72
+ responses.push(data);
73
+ // optionally cache the serialized response if the cache is available
74
+ serializedCache?.set(data as object, chunk.data);
69
75
 
70
76
  if (maxResponses !== undefined && responses.length >= maxResponses) {
71
77
  break;
@@ -1,6 +1,7 @@
1
1
  import {ResponseIncoming} from "@lodestar/reqresp";
2
- import {SignedBeaconBlock, WithBytes, phase0} from "@lodestar/types";
2
+ import {SignedBeaconBlock, phase0} from "@lodestar/types";
3
3
  import {LodestarError} from "@lodestar/utils";
4
+ import {SerializedCache} from "../../../util/serializedCache.ts";
4
5
  import {ReqRespMethod, responseSszTypeByMethod} from "../types.js";
5
6
  import {sszDeserializeResponse} from "./collect.js";
6
7
 
@@ -10,9 +11,10 @@ import {sszDeserializeResponse} from "./collect.js";
10
11
  */
11
12
  export async function collectSequentialBlocksInRange(
12
13
  blockStream: AsyncIterable<ResponseIncoming>,
13
- {count, startSlot}: Pick<phase0.BeaconBlocksByRangeRequest, "count" | "startSlot">
14
- ): Promise<WithBytes<SignedBeaconBlock>[]> {
15
- const blocks: WithBytes<SignedBeaconBlock>[] = [];
14
+ {count, startSlot}: Pick<phase0.BeaconBlocksByRangeRequest, "count" | "startSlot">,
15
+ serializedCache?: SerializedCache
16
+ ): Promise<SignedBeaconBlock[]> {
17
+ const blocks: SignedBeaconBlock[] = [];
16
18
 
17
19
  for await (const chunk of blockStream) {
18
20
  const blockType = responseSszTypeByMethod[ReqRespMethod.BeaconBlocksByRange](chunk.fork, chunk.protocolVersion);
@@ -30,11 +32,13 @@ export async function collectSequentialBlocksInRange(
30
32
  }
31
33
 
32
34
  const prevBlock = blocks.at(-1);
33
- if (prevBlock && prevBlock.data.message.slot >= blockSlot) {
35
+ if (prevBlock && prevBlock.message.slot >= blockSlot) {
34
36
  throw new BlocksByRangeError({code: BlocksByRangeErrorCode.BAD_SEQUENCE});
35
37
  }
36
38
 
37
- blocks.push({data: block, bytes: chunk.data});
39
+ blocks.push(block);
40
+ // optionally cache the serialized response if the cache is available
41
+ serializedCache?.set(block, chunk.data);
38
42
  if (blocks.length >= count) {
39
43
  break; // Done, collected all blocks
40
44
  }
@@ -749,27 +749,33 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter}
749
749
  const anchorBlock = res[0];
750
750
 
751
751
  // GENESIS_SLOT doesn't has valid signature
752
- if (anchorBlock.data.message.slot === GENESIS_SLOT) return;
752
+ if (anchorBlock.message.slot === GENESIS_SLOT) return;
753
753
  await verifyBlockProposerSignature(this.chain.bls, this.chain.getHeadState(), [anchorBlock]);
754
754
 
755
755
  // We can write to the disk if this is ahead of prevFinalizedCheckpointBlock otherwise
756
756
  // we will need to go make checks on the top of sync loop before writing as it might
757
757
  // override prevFinalizedCheckpointBlock
758
- if (this.prevFinalizedCheckpointBlock.slot < anchorBlock.data.message.slot)
759
- await this.db.blockArchive.putBinary(anchorBlock.data.message.slot, anchorBlock.bytes);
758
+ if (this.prevFinalizedCheckpointBlock.slot < anchorBlock.message.slot) {
759
+ const serialized = this.chain.serializedCache.get(anchorBlock);
760
+ if (serialized) {
761
+ await this.db.blockArchive.putBinary(anchorBlock.message.slot, serialized);
762
+ } else {
763
+ await this.db.blockArchive.put(anchorBlock.message.slot, anchorBlock);
764
+ }
765
+ }
760
766
 
761
767
  this.syncAnchor = {
762
- anchorBlock: anchorBlock.data,
768
+ anchorBlock: anchorBlock,
763
769
  anchorBlockRoot,
764
- anchorSlot: anchorBlock.data.message.slot,
765
- lastBackSyncedBlock: {root: anchorBlockRoot, slot: anchorBlock.data.message.slot, block: anchorBlock.data},
770
+ anchorSlot: anchorBlock.message.slot,
771
+ lastBackSyncedBlock: {root: anchorBlockRoot, slot: anchorBlock.message.slot, block: anchorBlock},
766
772
  };
767
773
 
768
774
  this.metrics?.backfillSync.totalBlocks.inc({method: BackfillSyncMethod.blockbyroot});
769
775
 
770
776
  this.logger.verbose("Fetched new anchorBlock", {
771
777
  root: toRootHex(anchorBlockRoot),
772
- slot: anchorBlock.data.message.slot,
778
+ slot: anchorBlock.message.slot,
773
779
  });
774
780
 
775
781
  return;
@@ -825,15 +831,33 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter}
825
831
  nextAnchor.slot > this.prevFinalizedCheckpointBlock.slot
826
832
  ? verifiedBlocks
827
833
  : verifiedBlocks.slice(0, verifiedBlocks.length - 1);
828
- await this.db.blockArchive.batchPutBinary(
829
- blocksToPut.map((block) => ({
830
- key: block.data.message.slot,
831
- value: block.bytes,
832
- slot: block.data.message.slot,
833
- blockRoot: this.config.getForkTypes(block.data.message.slot).BeaconBlock.hashTreeRoot(block.data.message),
834
- parentRoot: block.data.message.parentRoot,
835
- }))
836
- );
834
+
835
+ const binaryPuts = [];
836
+ const nonBinaryPuts = [];
837
+
838
+ for (const block of blocksToPut) {
839
+ const serialized = this.chain.serializedCache.get(block);
840
+ const item = {
841
+ key: block.message.slot,
842
+ slot: block.message.slot,
843
+ blockRoot: this.config.getForkTypes(block.message.slot).BeaconBlock.hashTreeRoot(block.message),
844
+ parentRoot: block.message.parentRoot,
845
+ };
846
+
847
+ if (serialized) {
848
+ binaryPuts.push({...item, value: serialized});
849
+ } else {
850
+ nonBinaryPuts.push({...item, value: block});
851
+ }
852
+ }
853
+
854
+ if (binaryPuts.length > 0) {
855
+ await this.db.blockArchive.batchPutBinary(binaryPuts);
856
+ }
857
+ if (nonBinaryPuts.length > 0) {
858
+ await this.db.blockArchive.batchPut(nonBinaryPuts);
859
+ }
860
+
837
861
  this.metrics?.backfillSync.totalBlocks.inc({method: BackfillSyncMethod.rangesync}, verifiedBlocks.length);
838
862
  }
839
863
 
@@ -1,7 +1,7 @@
1
1
  import {BeaconConfig} from "@lodestar/config";
2
2
  import {GENESIS_SLOT} from "@lodestar/params";
3
3
  import {CachedBeaconStateAllForks, ISignatureSet, getBlockProposerSignatureSet} from "@lodestar/state-transition";
4
- import {Root, SignedBeaconBlock, Slot, WithBytes, ssz} from "@lodestar/types";
4
+ import {Root, SignedBeaconBlock, Slot, ssz} from "@lodestar/types";
5
5
  import {IBlsVerifier} from "../../chain/bls/index.js";
6
6
  import {BackfillSyncError, BackfillSyncErrorCode} from "./errors.js";
7
7
 
@@ -14,19 +14,19 @@ export type BackfillBlock = BackfillBlockHeader & {block: SignedBeaconBlock};
14
14
 
15
15
  export function verifyBlockSequence(
16
16
  config: BeaconConfig,
17
- blocks: WithBytes<SignedBeaconBlock>[],
17
+ blocks: SignedBeaconBlock[],
18
18
  anchorRoot: Root
19
19
  ): {
20
20
  nextAnchor: BackfillBlock | null;
21
- verifiedBlocks: WithBytes<SignedBeaconBlock>[];
21
+ verifiedBlocks: SignedBeaconBlock[];
22
22
  error?: BackfillSyncErrorCode.NOT_LINEAR;
23
23
  } {
24
24
  let nextRoot: Root = anchorRoot;
25
25
  let nextAnchor: BackfillBlock | null = null;
26
26
 
27
- const verifiedBlocks: WithBytes<SignedBeaconBlock>[] = [];
27
+ const verifiedBlocks: SignedBeaconBlock[] = [];
28
28
  for (const block of blocks.reverse()) {
29
- const blockRoot = config.getForkTypes(block.data.message.slot).BeaconBlock.hashTreeRoot(block.data.message);
29
+ const blockRoot = config.getForkTypes(block.message.slot).BeaconBlock.hashTreeRoot(block.message);
30
30
  if (!ssz.Root.equals(blockRoot, nextRoot)) {
31
31
  if (ssz.Root.equals(nextRoot, anchorRoot)) {
32
32
  throw new BackfillSyncError({code: BackfillSyncErrorCode.NOT_ANCHORED});
@@ -34,8 +34,8 @@ export function verifyBlockSequence(
34
34
  return {nextAnchor, verifiedBlocks, error: BackfillSyncErrorCode.NOT_LINEAR};
35
35
  }
36
36
  verifiedBlocks.push(block);
37
- nextAnchor = {block: block.data, slot: block.data.message.slot, root: nextRoot};
38
- nextRoot = block.data.message.parentRoot;
37
+ nextAnchor = {block: block, slot: block.message.slot, root: nextRoot};
38
+ nextRoot = block.message.parentRoot;
39
39
  }
40
40
  return {nextAnchor, verifiedBlocks};
41
41
  }
@@ -43,12 +43,12 @@ export function verifyBlockSequence(
43
43
  export async function verifyBlockProposerSignature(
44
44
  bls: IBlsVerifier,
45
45
  state: CachedBeaconStateAllForks,
46
- blocks: WithBytes<SignedBeaconBlock>[]
46
+ blocks: SignedBeaconBlock[]
47
47
  ): Promise<void> {
48
- if (blocks.length === 1 && blocks[0].data.message.slot === GENESIS_SLOT) return;
48
+ if (blocks.length === 1 && blocks[0].message.slot === GENESIS_SLOT) return;
49
49
  const signatures = blocks.reduce((sigs: ISignatureSet[], block) => {
50
50
  // genesis block doesn't have valid signature
51
- if (block.data.message.slot !== GENESIS_SLOT) sigs.push(getBlockProposerSignatureSet(state, block.data));
51
+ if (block.message.slot !== GENESIS_SLOT) sigs.push(getBlockProposerSignatureSet(state, block));
52
52
  return sigs;
53
53
  }, []);
54
54
 
@@ -254,7 +254,7 @@ export async function requestByRange({
254
254
  if (blocksRequest) {
255
255
  requests.push(
256
256
  network.sendBeaconBlocksByRange(peerIdStr, blocksRequest).then((blockResponse) => {
257
- blocks = blockResponse.map(({data}) => data);
257
+ blocks = blockResponse;
258
258
  })
259
259
  );
260
260
  }
@@ -314,7 +314,7 @@ export async function fetchAndValidateBlock({
314
314
  blockRoot,
315
315
  }: Omit<FetchByRootAndValidateBlockProps, "chain">): Promise<SignedBeaconBlock> {
316
316
  const response = await network.sendBeaconBlocksByRoot(peerIdStr, [blockRoot]);
317
- const block = response.at(0)?.data;
317
+ const block = response.at(0);
318
318
  if (!block) {
319
319
  throw new DownloadByRootError({
320
320
  code: DownloadByRootErrorCode.MISSING_BLOCK_RESPONSE,