@lodestar/beacon-node 1.42.0-dev.b2b4af3e21 → 1.42.0-dev.bc0be71fb0

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 (149) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +11 -11
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/debug/index.js.map +1 -1
  5. package/lib/chain/ColumnReconstructionTracker.d.ts +2 -1
  6. package/lib/chain/ColumnReconstructionTracker.d.ts.map +1 -1
  7. package/lib/chain/ColumnReconstructionTracker.js +5 -5
  8. package/lib/chain/ColumnReconstructionTracker.js.map +1 -1
  9. package/lib/chain/GetBlobsTracker.d.ts +2 -1
  10. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  11. package/lib/chain/GetBlobsTracker.js +14 -12
  12. package/lib/chain/GetBlobsTracker.js.map +1 -1
  13. package/lib/chain/blocks/blockInput/blockInput.d.ts +5 -5
  14. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  15. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  16. package/lib/chain/blocks/blockInput/types.d.ts +4 -4
  17. package/lib/chain/blocks/blockInput/types.d.ts.map +1 -1
  18. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  19. package/lib/chain/blocks/importBlock.js +13 -1
  20. package/lib/chain/blocks/importBlock.js.map +1 -1
  21. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +14 -6
  22. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  23. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +33 -2
  24. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  25. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +2 -1
  26. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  27. package/lib/chain/chain.d.ts +3 -2
  28. package/lib/chain/chain.d.ts.map +1 -1
  29. package/lib/chain/chain.js +55 -20
  30. package/lib/chain/chain.js.map +1 -1
  31. package/lib/chain/emitter.d.ts +29 -7
  32. package/lib/chain/emitter.d.ts.map +1 -1
  33. package/lib/chain/emitter.js +12 -3
  34. package/lib/chain/emitter.js.map +1 -1
  35. package/lib/chain/errors/dataColumnSidecarError.d.ts +31 -1
  36. package/lib/chain/errors/dataColumnSidecarError.d.ts.map +1 -1
  37. package/lib/chain/errors/dataColumnSidecarError.js +7 -0
  38. package/lib/chain/errors/dataColumnSidecarError.js.map +1 -1
  39. package/lib/chain/interface.d.ts +4 -2
  40. package/lib/chain/interface.d.ts.map +1 -1
  41. package/lib/chain/seenCache/seenGossipBlockInput.d.ts +1 -1
  42. package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
  43. package/lib/chain/seenCache/seenGossipBlockInput.js +2 -2
  44. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  45. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +1 -1
  46. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  47. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +2 -2
  48. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  49. package/lib/chain/validation/dataColumnSidecar.d.ts +11 -4
  50. package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
  51. package/lib/chain/validation/dataColumnSidecar.js +184 -5
  52. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  53. package/lib/db/buckets.d.ts +2 -2
  54. package/lib/db/buckets.d.ts.map +1 -1
  55. package/lib/db/buckets.js +2 -2
  56. package/lib/db/buckets.js.map +1 -1
  57. package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
  58. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  59. package/lib/db/repositories/dataColumnSidecar.d.ts.map +1 -1
  60. package/lib/db/repositories/dataColumnSidecar.js +4 -2
  61. package/lib/db/repositories/dataColumnSidecar.js.map +1 -1
  62. package/lib/db/repositories/dataColumnSidecarArchive.d.ts.map +1 -1
  63. package/lib/db/repositories/dataColumnSidecarArchive.js +4 -2
  64. package/lib/db/repositories/dataColumnSidecarArchive.js.map +1 -1
  65. package/lib/metrics/metrics/lodestar.d.ts +20 -0
  66. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  67. package/lib/metrics/metrics/lodestar.js +33 -0
  68. package/lib/metrics/metrics/lodestar.js.map +1 -1
  69. package/lib/network/interface.d.ts +3 -2
  70. package/lib/network/interface.d.ts.map +1 -1
  71. package/lib/network/network.d.ts +3 -2
  72. package/lib/network/network.d.ts.map +1 -1
  73. package/lib/network/network.js +3 -0
  74. package/lib/network/network.js.map +1 -1
  75. package/lib/network/processor/extractSlotRootFns.d.ts +1 -1
  76. package/lib/network/processor/extractSlotRootFns.d.ts.map +1 -1
  77. package/lib/network/processor/extractSlotRootFns.js +25 -5
  78. package/lib/network/processor/extractSlotRootFns.js.map +1 -1
  79. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  80. package/lib/network/processor/gossipHandlers.js +242 -66
  81. package/lib/network/processor/gossipHandlers.js.map +1 -1
  82. package/lib/network/processor/index.d.ts +11 -1
  83. package/lib/network/processor/index.d.ts.map +1 -1
  84. package/lib/network/processor/index.js +234 -22
  85. package/lib/network/processor/index.js.map +1 -1
  86. package/lib/network/reqresp/types.d.ts +3 -3
  87. package/lib/network/reqresp/types.d.ts.map +1 -1
  88. package/lib/network/reqresp/types.js +9 -3
  89. package/lib/network/reqresp/types.js.map +1 -1
  90. package/lib/sync/unknownBlock.js +2 -2
  91. package/lib/sync/unknownBlock.js.map +1 -1
  92. package/lib/sync/utils/downloadByRange.d.ts +3 -3
  93. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  94. package/lib/sync/utils/downloadByRange.js +4 -2
  95. package/lib/sync/utils/downloadByRange.js.map +1 -1
  96. package/lib/sync/utils/downloadByRoot.d.ts +3 -3
  97. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  98. package/lib/sync/utils/downloadByRoot.js +10 -5
  99. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  100. package/lib/util/blobs.d.ts +3 -3
  101. package/lib/util/blobs.d.ts.map +1 -1
  102. package/lib/util/blobs.js +21 -10
  103. package/lib/util/blobs.js.map +1 -1
  104. package/lib/util/dataColumns.d.ts +18 -11
  105. package/lib/util/dataColumns.d.ts.map +1 -1
  106. package/lib/util/dataColumns.js +51 -17
  107. package/lib/util/dataColumns.js.map +1 -1
  108. package/lib/util/execution.d.ts +6 -2
  109. package/lib/util/execution.d.ts.map +1 -1
  110. package/lib/util/execution.js +49 -25
  111. package/lib/util/execution.js.map +1 -1
  112. package/lib/util/sszBytes.d.ts +25 -1
  113. package/lib/util/sszBytes.d.ts.map +1 -1
  114. package/lib/util/sszBytes.js +189 -2
  115. package/lib/util/sszBytes.js.map +1 -1
  116. package/package.json +15 -15
  117. package/src/api/impl/beacon/blocks/index.ts +17 -14
  118. package/src/api/impl/debug/index.ts +2 -2
  119. package/src/chain/ColumnReconstructionTracker.ts +6 -5
  120. package/src/chain/GetBlobsTracker.ts +14 -12
  121. package/src/chain/blocks/blockInput/blockInput.ts +8 -8
  122. package/src/chain/blocks/blockInput/types.ts +4 -4
  123. package/src/chain/blocks/importBlock.ts +18 -1
  124. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +53 -12
  125. package/src/chain/blocks/payloadEnvelopeInput/types.ts +2 -1
  126. package/src/chain/chain.ts +63 -24
  127. package/src/chain/emitter.ts +25 -7
  128. package/src/chain/errors/dataColumnSidecarError.ts +32 -1
  129. package/src/chain/interface.ts +4 -2
  130. package/src/chain/seenCache/seenGossipBlockInput.ts +2 -2
  131. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +2 -2
  132. package/src/chain/validation/dataColumnSidecar.ts +230 -7
  133. package/src/db/buckets.ts +2 -2
  134. package/src/db/repositories/dataColumnSidecar.ts +4 -2
  135. package/src/db/repositories/dataColumnSidecarArchive.ts +4 -2
  136. package/src/metrics/metrics/lodestar.ts +34 -0
  137. package/src/network/interface.ts +3 -2
  138. package/src/network/network.ts +7 -4
  139. package/src/network/processor/extractSlotRootFns.ts +32 -6
  140. package/src/network/processor/gossipHandlers.ts +305 -79
  141. package/src/network/processor/index.ts +304 -22
  142. package/src/network/reqresp/types.ts +13 -5
  143. package/src/sync/unknownBlock.ts +3 -3
  144. package/src/sync/utils/downloadByRange.ts +9 -7
  145. package/src/sync/utils/downloadByRoot.ts +16 -12
  146. package/src/util/blobs.ts +35 -15
  147. package/src/util/dataColumns.ts +69 -25
  148. package/src/util/execution.ts +49 -30
  149. package/src/util/sszBytes.ts +245 -3
@@ -15,6 +15,7 @@ import {
15
15
  BUILDER_INDEX_SELF_BUILD,
16
16
  EFFECTIVE_BALANCE_INCREMENT,
17
17
  type ForkPostFulu,
18
+ type ForkPostGloas,
18
19
  GENESIS_SLOT,
19
20
  SLOTS_PER_EPOCH,
20
21
  isForkPostElectra,
@@ -34,7 +35,7 @@ import {
34
35
  BeaconBlock,
35
36
  BlindedBeaconBlock,
36
37
  BlindedBeaconBlockBody,
37
- DataColumnSidecars,
38
+ DataColumnSidecar,
38
39
  Epoch,
39
40
  Root,
40
41
  RootHex,
@@ -504,7 +505,11 @@ export class BeaconChain implements IBeaconChain {
504
505
  }
505
506
 
506
507
  seenBlock(blockRoot: RootHex): boolean {
507
- return this.seenBlockInputCache.has(blockRoot) || this.forkChoice.hasBlockHex(blockRoot);
508
+ return this.seenBlockInputCache.hasBlock(blockRoot) || this.forkChoice.hasBlockHexUnsafe(blockRoot);
509
+ }
510
+
511
+ seenPayloadEnvelope(blockRoot: RootHex): boolean {
512
+ return this.seenPayloadEnvelopeInputCache.hasPayload(blockRoot) || this.forkChoice.hasPayloadHexUnsafe(blockRoot);
508
513
  }
509
514
 
510
515
  regenCanAcceptWork(): boolean {
@@ -873,20 +878,32 @@ export class BeaconChain implements IBeaconChain {
873
878
  );
874
879
  }
875
880
 
876
- async getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<DataColumnSidecars> {
877
- const blockInput = this.seenBlockInputCache.get(blockRootHex);
878
- if (blockInput) {
879
- if (!isBlockInputColumns(blockInput)) {
880
- throw new Error(`Expected block input to have columns: slot=${blockSlot} root=${blockRootHex}`);
881
+ async getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<DataColumnSidecar[]> {
882
+ const fork = this.config.getForkName(blockSlot);
883
+
884
+ if (isForkPostGloas(fork)) {
885
+ // After gloas, columns are tracked in PayloadEnvelopeInput
886
+ const payloadInput = this.seenPayloadEnvelopeInputCache.get(blockRootHex);
887
+ if (payloadInput) {
888
+ return payloadInput.getAllColumns();
889
+ }
890
+ } else {
891
+ // Before gloas, columns are tracked in BlockInput
892
+ const blockInput = this.seenBlockInputCache.get(blockRootHex);
893
+ if (blockInput) {
894
+ if (!isBlockInputColumns(blockInput)) {
895
+ throw new Error(`Expected block input to have columns: slot=${blockSlot} root=${blockRootHex}`);
896
+ }
897
+ return blockInput.getAllColumns();
881
898
  }
882
- return blockInput.getAllColumns();
883
899
  }
900
+
884
901
  const sidecarsUnfinalized = await this.db.dataColumnSidecar.values(fromHex(blockRootHex));
885
902
  if (sidecarsUnfinalized.length > 0) {
886
- return sidecarsUnfinalized as DataColumnSidecars;
903
+ return sidecarsUnfinalized;
887
904
  }
888
905
  const sidecarsFinalized = await this.db.dataColumnSidecarArchive.values(blockSlot);
889
- return sidecarsFinalized as DataColumnSidecars;
906
+ return sidecarsFinalized;
890
907
  }
891
908
 
892
909
  async getSerializedDataColumnSidecars(
@@ -894,23 +911,45 @@ export class BeaconChain implements IBeaconChain {
894
911
  blockRootHex: string,
895
912
  indices: number[]
896
913
  ): Promise<(Uint8Array | undefined)[]> {
897
- const blockInput = this.seenBlockInputCache.get(blockRootHex);
898
- if (blockInput) {
899
- if (!isBlockInputColumns(blockInput)) {
900
- throw new Error(`Expected block input to have columns: slot=${blockSlot} root=${blockRootHex}`);
914
+ const fork = this.config.getForkName(blockSlot);
915
+
916
+ if (isForkPostGloas(fork)) {
917
+ // After gloas, columns are tracked in PayloadEnvelopeInput
918
+ const payloadInput = this.seenPayloadEnvelopeInputCache.get(blockRootHex);
919
+ if (payloadInput) {
920
+ return indices.map((index) => {
921
+ const sidecar = payloadInput.getColumn(index);
922
+ if (!sidecar) {
923
+ return undefined;
924
+ }
925
+ const serialized = this.serializedCache.get(sidecar);
926
+ if (serialized) {
927
+ return serialized;
928
+ }
929
+ return sszTypesFor(fork as ForkPostGloas).DataColumnSidecar.serialize(sidecar);
930
+ });
901
931
  }
902
- return indices.map((index) => {
903
- const sidecar = blockInput.getColumn(index);
904
- if (!sidecar) {
905
- return undefined;
906
- }
907
- const serialized = this.serializedCache.get(sidecar);
908
- if (serialized) {
909
- return serialized;
932
+ } else {
933
+ // Before gloas, columns are tracked in BlockInput
934
+ const blockInput = this.seenBlockInputCache.get(blockRootHex);
935
+ if (blockInput) {
936
+ if (!isBlockInputColumns(blockInput)) {
937
+ throw new Error(`Expected block input to have columns: slot=${blockSlot} root=${blockRootHex}`);
910
938
  }
911
- return sszTypesFor(blockInput.forkName as ForkPostFulu).DataColumnSidecar.serialize(sidecar);
912
- });
939
+ return indices.map((index) => {
940
+ const sidecar = blockInput.getColumn(index);
941
+ if (!sidecar) {
942
+ return undefined;
943
+ }
944
+ const serialized = this.serializedCache.get(sidecar);
945
+ if (serialized) {
946
+ return serialized;
947
+ }
948
+ return sszTypesFor(blockInput.forkName as ForkPostFulu).DataColumnSidecar.serialize(sidecar);
949
+ });
950
+ }
913
951
  }
952
+
914
953
  const sidecarsUnfinalized = await this.db.dataColumnSidecar.getManyBinary(fromHex(blockRootHex), indices);
915
954
  if (sidecarsUnfinalized.some((sidecar) => sidecar != null)) {
916
955
  return sidecarsUnfinalized;
@@ -3,7 +3,8 @@ import {StrictEventEmitter} from "strict-event-emitter-types";
3
3
  import {routes} from "@lodestar/api";
4
4
  import {CheckpointWithPayloadStatus} from "@lodestar/fork-choice";
5
5
  import {IBeaconStateView} from "@lodestar/state-transition";
6
- import {DataColumnSidecars, RootHex, deneb, phase0} from "@lodestar/types";
6
+ import {DataColumnSidecar, RootHex, deneb, phase0} from "@lodestar/types";
7
+ import {SignedExecutionPayloadEnvelope} from "@lodestar/types/gloas";
7
8
  import {PeerIdStr} from "../util/peerId.js";
8
9
  import {BlockInputSource, IBlockInput} from "./blocks/blockInput/types.js";
9
10
 
@@ -54,13 +55,22 @@ export enum ChainEvent {
54
55
  */
55
56
  updateStatus = "updateStatus",
56
57
  /**
57
- * Trigger a BlockInputSync for blocks where the parentRoot is not known to fork choice
58
+ * Trigger BlockInputSync to find parent of a SignedBeaconBlock received
59
+ * Post-gloas, missing parent could be a SignedBeaconBlock and/or a SignedExecutionPayloadEnvelope
58
60
  */
59
- unknownParent = "unknownParent",
61
+ blockUnknownParent = "blockUnknownParent",
60
62
  /**
61
- * Trigger BlockInputSync for objects that correspond to a block that is not known to fork choice
63
+ * Trigger BlockInputSync to find a SignedBeaconBlock given a SignedExecutionPayloadEnvelop received
64
+ */
65
+ envelopeUnknownBlock = "envelopeUnknownBlock",
66
+ /**
67
+ * Trigger BlockInputSync to find a SignedBeaconBlock with specified block root.
62
68
  */
63
69
  unknownBlockRoot = "unknownBlockRoot",
70
+ /**
71
+ * Trigger BlockInputSync to find a SignedExecutionPayloadEnvelope with specified block root.
72
+ */
73
+ unknownEnvelopeBlockRoot = "unknownEnvelopeBlockRoot",
64
74
  /**
65
75
  * Trigger BlockInputSync for blocks that are partially received via gossip but are not complete by time the
66
76
  * cut-off window passes for waiting on gossip
@@ -75,9 +85,15 @@ export type ReorgEventData = routes.events.EventData[routes.events.EventType.cha
75
85
  type ApiEvents = {[K in routes.events.EventType]: (data: routes.events.EventData[K]) => void};
76
86
 
77
87
  export type ChainEventData = {
78
- [ChainEvent.unknownParent]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
88
+ [ChainEvent.blockUnknownParent]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
89
+ [ChainEvent.envelopeUnknownBlock]: {
90
+ envelope: SignedExecutionPayloadEnvelope;
91
+ peer?: PeerIdStr;
92
+ source: BlockInputSource;
93
+ };
79
94
  [ChainEvent.unknownBlockRoot]: {rootHex: RootHex; peer?: PeerIdStr; source: BlockInputSource};
80
95
  [ChainEvent.incompleteBlockInput]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
96
+ [ChainEvent.unknownEnvelopeBlockRoot]: {rootHex: RootHex; peer?: PeerIdStr; source: BlockInputSource};
81
97
  };
82
98
 
83
99
  export type IChainEvents = ApiEvents & {
@@ -88,7 +104,7 @@ export type IChainEvents = ApiEvents & {
88
104
 
89
105
  [ChainEvent.updateTargetCustodyGroupCount]: (targetGroupCount: number) => void;
90
106
 
91
- [ChainEvent.publishDataColumns]: (sidecars: DataColumnSidecars) => void;
107
+ [ChainEvent.publishDataColumns]: (sidecars: DataColumnSidecar[]) => void;
92
108
 
93
109
  [ChainEvent.publishBlobSidecars]: (sidecars: deneb.BlobSidecar[]) => void;
94
110
 
@@ -96,9 +112,11 @@ export type IChainEvents = ApiEvents & {
96
112
 
97
113
  // Sync events that are chain->chain. Initiated from network requests but do not cross the network
98
114
  // barrier so are considered ChainEvent(s).
99
- [ChainEvent.unknownParent]: (data: ChainEventData[ChainEvent.unknownParent]) => void;
115
+ [ChainEvent.blockUnknownParent]: (data: ChainEventData[ChainEvent.blockUnknownParent]) => void;
116
+ [ChainEvent.envelopeUnknownBlock]: (data: ChainEventData[ChainEvent.envelopeUnknownBlock]) => void;
100
117
  [ChainEvent.unknownBlockRoot]: (data: ChainEventData[ChainEvent.unknownBlockRoot]) => void;
101
118
  [ChainEvent.incompleteBlockInput]: (data: ChainEventData[ChainEvent.incompleteBlockInput]) => void;
119
+ [ChainEvent.unknownEnvelopeBlockRoot]: (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRoot]) => void;
102
120
  };
103
121
 
104
122
  /**
@@ -1,3 +1,4 @@
1
+ import {ForkName} from "@lodestar/params";
1
2
  import {RootHex, Slot, SubnetID} from "@lodestar/types";
2
3
  import {LodestarError} from "@lodestar/utils";
3
4
  import {GossipActionError} from "./gossipValidation.js";
@@ -6,6 +7,7 @@ export enum DataColumnSidecarErrorCode {
6
7
  INVALID_INDEX = "DATA_COLUMN_SIDECAR_ERROR_INVALID_INDEX",
7
8
  NO_COMMITMENTS = "DATA_COLUMN_SIDECAR_ERROR_NO_COMMITMENTS",
8
9
  MISMATCHED_LENGTHS = "DATA_COLUMN_SIDECAR_ERROR_MISMATCHED_LENGTHS",
10
+ INCORRECT_TYPE = "DATA_COLUMN_SIDECAR_ERROR_INCORRECT_TYPE",
9
11
  INVALID_SUBNET = "DATA_COLUMN_SIDECAR_ERROR_INVALID_SUBNET",
10
12
  INVALID_KZG_PROOF = "DATA_COLUMN_SIDECAR_ERROR_INVALID_KZG_PROOF",
11
13
  TOO_MANY_KZG_COMMITMENTS = "DATA_COLUMN_SIDECAR_ERROR_TOO_MANY_KZG_COMMITMENTS",
@@ -18,6 +20,10 @@ export enum DataColumnSidecarErrorCode {
18
20
  INCORRECT_SIDECAR_COUNT = "DATA_COLUMN_SIDECAR_ERROR_INCORRECT_SIDECAR_COUNT",
19
21
  /** Sidecar doesn't match block */
20
22
  INCORRECT_BLOCK = "DATA_COLUMN_SIDECAR_ERROR_INCORRECT_BLOCK",
23
+ /** Sidecar slot doesn't match block slot */
24
+ INCORRECT_SIDECAR_SLOT = "DATA_COLUMN_SIDECAR_ERROR_INCORRECT_SIDECAR_SLOT",
25
+ /** Sidecar referenced block is not the expected block type */
26
+ INCORRECT_BLOCK_TYPE = "DATA_COLUMN_SIDECAR_ERROR_INCORRECT_BLOCK_TYPE",
21
27
  /** Sidecar cell count not as expected */
22
28
  INCORRECT_CELL_COUNT = "DATA_COLUMN_SIDECAR_ERROR_INCORRECT_CELL_COUNT",
23
29
  /** Sidecar kzg proof count not as expected */
@@ -32,10 +38,12 @@ export enum DataColumnSidecarErrorCode {
32
38
  FUTURE_SLOT = "DATA_COLUMN_SIDECAR_ERROR_FUTURE_SLOT",
33
39
  WOULD_REVERT_FINALIZED_SLOT = "DATA_COLUMN_SIDECAR_ERROR_WOULD_REVERT_FINALIZED_SLOT",
34
40
  PARENT_UNKNOWN = "DATA_COLUMN_SIDECAR_ERROR_PARENT_UNKNOWN",
41
+ BLOCK_UNKNOWN = "DATA_COLUMN_SIDECAR_ERROR_BLOCK_UNKNOWN",
35
42
  NOT_LATER_THAN_PARENT = "DATA_COLUMN_SIDECAR_ERROR_NOT_LATER_THAN_PARENT",
36
43
  PROPOSAL_SIGNATURE_INVALID = "DATA_COLUMN_SIDECAR_ERROR_PROPOSAL_SIGNATURE_INVALID",
37
44
  INCLUSION_PROOF_INVALID = "DATA_COLUMN_SIDECAR_ERROR_INCLUSION_PROOF_INVALID",
38
45
  INCORRECT_PROPOSER = "DATA_COLUMN_SIDECAR_ERROR_INCORRECT_PROPOSER",
46
+ PAYLOAD_ENVELOPE_INPUT_MISSING = "DATA_COLUMN_SIDECAR_ERROR_PAYLOAD_ENVELOPE_INPUT_MISSING",
39
47
  }
40
48
 
41
49
  export type DataColumnSidecarErrorType =
@@ -47,6 +55,12 @@ export type DataColumnSidecarErrorType =
47
55
  commitmentsLength: number;
48
56
  proofsLength: number;
49
57
  }
58
+ | {
59
+ code: DataColumnSidecarErrorCode.INCORRECT_TYPE;
60
+ slot: Slot;
61
+ columnIndex: number;
62
+ fork: ForkName;
63
+ }
50
64
  | {code: DataColumnSidecarErrorCode.INVALID_SUBNET; columnIndex: number; gossipSubnet: SubnetID}
51
65
  | {
52
66
  code: DataColumnSidecarErrorCode.TOO_MANY_KZG_COMMITMENTS;
@@ -63,6 +77,11 @@ export type DataColumnSidecarErrorType =
63
77
  parentRoot: RootHex;
64
78
  slot: Slot;
65
79
  }
80
+ | {
81
+ code: DataColumnSidecarErrorCode.BLOCK_UNKNOWN;
82
+ blockRoot: RootHex;
83
+ slot: Slot;
84
+ }
66
85
  | {
67
86
  code: DataColumnSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID;
68
87
  slot: Slot;
@@ -80,6 +99,17 @@ export type DataColumnSidecarErrorType =
80
99
  expected: string;
81
100
  actual: string;
82
101
  }
102
+ | {
103
+ code: DataColumnSidecarErrorCode.INCORRECT_BLOCK_TYPE;
104
+ slot: Slot;
105
+ columnIndex: number;
106
+ }
107
+ | {
108
+ code: DataColumnSidecarErrorCode.INCORRECT_SIDECAR_SLOT;
109
+ columnIndex: number;
110
+ expected: Slot;
111
+ actual: Slot;
112
+ }
83
113
  | {
84
114
  code: DataColumnSidecarErrorCode.INCORRECT_HEADER_ROOT;
85
115
  slot: number;
@@ -97,7 +127,8 @@ export type DataColumnSidecarErrorType =
97
127
  actual: number;
98
128
  }
99
129
  | {code: DataColumnSidecarErrorCode.INVALID_KZG_PROOF_BATCH; slot: number; reason: string}
100
- | {code: DataColumnSidecarErrorCode.INCORRECT_PROPOSER; actualProposerIndex: number; expectedProposerIndex: number};
130
+ | {code: DataColumnSidecarErrorCode.INCORRECT_PROPOSER; actualProposerIndex: number; expectedProposerIndex: number}
131
+ | {code: DataColumnSidecarErrorCode.PAYLOAD_ENVELOPE_INPUT_MISSING; slot: Slot; blockRoot: RootHex};
101
132
 
102
133
  export class DataColumnSidecarGossipError extends GossipActionError<DataColumnSidecarErrorType> {}
103
134
  export class DataColumnSidecarValidationError extends LodestarError<DataColumnSidecarErrorType> {}
@@ -5,7 +5,7 @@ import {EpochShuffling, IBeaconStateView, PubkeyCache} from "@lodestar/state-tra
5
5
  import {
6
6
  BeaconBlock,
7
7
  BlindedBeaconBlock,
8
- DataColumnSidecars,
8
+ DataColumnSidecar,
9
9
  Epoch,
10
10
  Root,
11
11
  RootHex,
@@ -159,6 +159,8 @@ export interface IBeaconChain {
159
159
  close(): Promise<void>;
160
160
  /** Chain has seen the specified block root or not. The block may not be processed yet, use forkchoice.hasBlock to check it */
161
161
  seenBlock(blockRoot: RootHex): boolean;
162
+ /** Chain has seen a SignedExecutionPayloadEnvelope for this block root (via seenCache or fork choice FULL variant) */
163
+ seenPayloadEnvelope(blockRoot: RootHex): boolean;
162
164
  /** Populate in-memory caches with persisted data. Call at least once on startup */
163
165
  loadFromDisk(): Promise<void>;
164
166
  /** Persist in-memory data to the DB. Call at least once before stopping the process */
@@ -217,7 +219,7 @@ export interface IBeaconChain {
217
219
  ): Promise<{block: SignedBeaconBlock; executionOptimistic: boolean; finalized: boolean} | null>;
218
220
  getBlobSidecars(blockSlot: Slot, blockRootHex: string): Promise<deneb.BlobSidecars | null>;
219
221
  getSerializedBlobSidecars(blockSlot: Slot, blockRootHex: string): Promise<Uint8Array | null>;
220
- getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<DataColumnSidecars>;
222
+ getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<DataColumnSidecar[]>;
221
223
  getSerializedDataColumnSidecars(
222
224
  blockSlot: Slot,
223
225
  blockRootHex: string,
@@ -149,8 +149,8 @@ export class SeenBlockInput {
149
149
  });
150
150
  }
151
151
 
152
- has(rootHex: RootHex): boolean {
153
- return this.blockInputs.has(rootHex);
152
+ hasBlock(rootHex: RootHex): boolean {
153
+ return this.blockInputs.get(rootHex)?.hasBlock() ?? false;
154
154
  }
155
155
 
156
156
  get(rootHex: RootHex): IBlockInput | undefined {
@@ -84,8 +84,8 @@ export class SeenPayloadEnvelopeInput {
84
84
  return this.payloadInputs.get(blockRootHex);
85
85
  }
86
86
 
87
- has(blockRootHex: RootHex): boolean {
88
- return this.payloadInputs.has(blockRootHex);
87
+ hasPayload(blockRootHex: RootHex): boolean {
88
+ return this.payloadInputs.get(blockRootHex)?.hasPayloadEnvelope() ?? false;
89
89
  }
90
90
 
91
91
  prune(blockRootHex: RootHex): void {
@@ -10,11 +10,13 @@ import {
10
10
  getBlockHeaderProposerSignatureSetByHeaderSlot,
11
11
  getBlockHeaderProposerSignatureSetByParentStateSlot,
12
12
  } from "@lodestar/state-transition";
13
- import {DataColumnSidecar, Root, Slot, SubnetID, fulu, ssz} from "@lodestar/types";
13
+ import {DataColumnSidecar, Root, Slot, SubnetID, fulu, gloas, ssz} from "@lodestar/types";
14
14
  import {byteArrayEquals, toRootHex, verifyMerkleBranch} from "@lodestar/utils";
15
15
  import {BeaconMetrics} from "../../metrics/metrics/beacon.js";
16
16
  import {Metrics} from "../../metrics/metrics.js";
17
+ import {getDataColumnSidecarSlot} from "../../util/dataColumns.js";
17
18
  import {kzg} from "../../util/kzg.js";
19
+ import {PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
18
20
  import {
19
21
  DataColumnSidecarErrorCode,
20
22
  DataColumnSidecarGossipError,
@@ -26,7 +28,7 @@ import {RegenCaller} from "../regen/interface.js";
26
28
 
27
29
  // SPEC FUNCTION
28
30
  // https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.4/specs/fulu/p2p-interface.md#data_column_sidecar_subnet_id
29
- export async function validateGossipDataColumnSidecar(
31
+ export async function validateGossipFuluDataColumnSidecar(
30
32
  chain: IBeaconChain,
31
33
  dataColumnSidecar: fulu.DataColumnSidecar,
32
34
  gossipSubnet: SubnetID,
@@ -36,7 +38,7 @@ export async function validateGossipDataColumnSidecar(
36
38
  const blockRootHex = toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader));
37
39
 
38
40
  // 1) [REJECT] The sidecar is valid as verified by verify_data_column_sidecar
39
- verifyDataColumnSidecar(chain.config, dataColumnSidecar);
41
+ verifyFuluDataColumnSidecar(chain.config, dataColumnSidecar);
40
42
 
41
43
  // 2) [REJECT] The sidecar is for the correct subnet -- i.e. compute_subnet_for_data_column_sidecar(sidecar.index) == subnet_id
42
44
  if (computeSubnetForDataColumnSidecar(chain.config, dataColumnSidecar) !== gossipSubnet) {
@@ -203,11 +205,75 @@ export async function validateGossipDataColumnSidecar(
203
205
  // -- Handled in seenGossipBlockInput
204
206
  }
205
207
 
208
+ // SPEC FUNCTION
209
+ // https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.3/specs/gloas/p2p-interface.md#data_column_sidecar_subnet_id
210
+ export async function validateGossipGloasDataColumnSidecar(
211
+ chain: IBeaconChain,
212
+ payloadInput: PayloadEnvelopeInput,
213
+ dataColumnSidecar: gloas.DataColumnSidecar,
214
+ gossipSubnet: SubnetID,
215
+ metrics: Metrics | null
216
+ ): Promise<void> {
217
+ const blockRootHex = toRootHex(dataColumnSidecar.beaconBlockRoot);
218
+ const block = chain.forkChoice.getBlockHexDefaultStatus(blockRootHex);
219
+
220
+ // [IGNORE] A valid block for the sidecar's `slot` has been seen.
221
+ if (block === null) {
222
+ throw new DataColumnSidecarGossipError(GossipAction.IGNORE, {
223
+ code: DataColumnSidecarErrorCode.BLOCK_UNKNOWN,
224
+ blockRoot: blockRootHex,
225
+ slot: dataColumnSidecar.slot,
226
+ });
227
+ }
228
+
229
+ // [REJECT] The sidecar slot matches the slot of the block with root beacon_block_root.
230
+ if (block.slot !== dataColumnSidecar.slot) {
231
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
232
+ code: DataColumnSidecarErrorCode.INCORRECT_SIDECAR_SLOT,
233
+ columnIndex: dataColumnSidecar.index,
234
+ expected: block.slot,
235
+ actual: dataColumnSidecar.slot,
236
+ });
237
+ }
238
+
239
+ // [REJECT] The sidecar must pass verify_data_column_sidecar against the block commitments
240
+ const kzgCommitments = payloadInput.getBlobKzgCommitments();
241
+ verifyGloasDataColumnSidecar(dataColumnSidecar, kzgCommitments);
242
+
243
+ // [REJECT] The sidecar must be on the correct subnet
244
+ if (computeSubnetForDataColumnSidecar(chain.config, dataColumnSidecar) !== gossipSubnet) {
245
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
246
+ code: DataColumnSidecarErrorCode.INVALID_SUBNET,
247
+ columnIndex: dataColumnSidecar.index,
248
+ gossipSubnet,
249
+ });
250
+ }
251
+
252
+ // [REJECT] The sidecar kzg proofs must verify
253
+ const kzgProofTimer = metrics?.peerDas.dataColumnSidecarKzgProofsVerificationTime.startTimer();
254
+ try {
255
+ await verifyDataColumnSidecarKzgProofs(
256
+ kzgCommitments,
257
+ Array.from({length: dataColumnSidecar.column.length}, () => dataColumnSidecar.index),
258
+ dataColumnSidecar.column,
259
+ dataColumnSidecar.kzgProofs
260
+ );
261
+ } catch {
262
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
263
+ code: DataColumnSidecarErrorCode.INVALID_KZG_PROOF,
264
+ slot: dataColumnSidecar.slot,
265
+ columnIndex: dataColumnSidecar.index,
266
+ });
267
+ } finally {
268
+ kzgProofTimer?.();
269
+ }
270
+ }
271
+
206
272
  /**
207
273
  * SPEC FUNCTION
208
274
  * https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.4/specs/fulu/p2p-interface.md#verify_data_column_sidecar
209
275
  */
210
- function verifyDataColumnSidecar(config: ChainForkConfig, dataColumnSidecar: fulu.DataColumnSidecar): void {
276
+ function verifyFuluDataColumnSidecar(config: ChainForkConfig, dataColumnSidecar: fulu.DataColumnSidecar): void {
211
277
  if (dataColumnSidecar.index >= NUMBER_OF_COLUMNS) {
212
278
  throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
213
279
  code: DataColumnSidecarErrorCode.INVALID_INDEX,
@@ -250,6 +316,41 @@ function verifyDataColumnSidecar(config: ChainForkConfig, dataColumnSidecar: ful
250
316
  }
251
317
  }
252
318
 
319
+ /**
320
+ * SPEC FUNCTION
321
+ * https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.3/specs/gloas/p2p-interface.md#modified-verify_data_column_sidecar
322
+ */
323
+ function verifyGloasDataColumnSidecar(dataColumnSidecar: gloas.DataColumnSidecar, kzgCommitments: Uint8Array[]): void {
324
+ const slot = getDataColumnSidecarSlot(dataColumnSidecar);
325
+ if (dataColumnSidecar.index >= NUMBER_OF_COLUMNS) {
326
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
327
+ code: DataColumnSidecarErrorCode.INVALID_INDEX,
328
+ slot,
329
+ columnIndex: dataColumnSidecar.index,
330
+ });
331
+ }
332
+
333
+ if (dataColumnSidecar.column.length === 0) {
334
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
335
+ code: DataColumnSidecarErrorCode.NO_COMMITMENTS,
336
+ slot,
337
+ columnIndex: dataColumnSidecar.index,
338
+ });
339
+ }
340
+
341
+ if (
342
+ dataColumnSidecar.column.length !== kzgCommitments.length ||
343
+ dataColumnSidecar.column.length !== dataColumnSidecar.kzgProofs.length
344
+ ) {
345
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
346
+ code: DataColumnSidecarErrorCode.MISMATCHED_LENGTHS,
347
+ columnLength: dataColumnSidecar.column.length,
348
+ commitmentsLength: kzgCommitments.length,
349
+ proofsLength: dataColumnSidecar.kzgProofs.length,
350
+ });
351
+ }
352
+ }
353
+
253
354
  /**
254
355
  * SPEC FUNCTION
255
356
  * https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.4/specs/fulu/p2p-interface.md#verify_data_column_sidecar_kzg_proofs
@@ -287,19 +388,19 @@ export function verifyDataColumnSidecarInclusionProof(dataColumnSidecar: fulu.Da
287
388
  }
288
389
 
289
390
  /**
290
- * Validate a subset of data column sidecars in a block
391
+ * Validate a subset of fulu data column sidecars against a block
291
392
  *
292
393
  * Requires the block to be known to the node
293
394
  *
294
395
  * NOTE: chain is optional to skip signature verification. Helpful for testing purposes and so that can control whether
295
396
  * signature gets checked depending on the reqresp method that is being checked
296
397
  */
297
- export async function validateBlockDataColumnSidecars(
398
+ export async function validateFuluBlockDataColumnSidecars(
298
399
  chain: IBeaconChain | null,
299
400
  blockSlot: Slot,
300
401
  blockRoot: Root,
301
402
  blockBlobCount: number,
302
- dataColumnSidecars: fulu.DataColumnSidecars,
403
+ dataColumnSidecars: fulu.DataColumnSidecar[],
303
404
  metrics?: BeaconMetrics["peerDas"] | null
304
405
  ): Promise<void> {
305
406
  metrics?.dataColumnSidecarProcessingRequests.inc(dataColumnSidecars.length);
@@ -467,6 +568,128 @@ export async function validateBlockDataColumnSidecars(
467
568
  "DataColumnSidecar has invalid KZG proof batch"
468
569
  );
469
570
  }
571
+
572
+ metrics?.dataColumnSidecarProcessingSuccesses.inc();
573
+ } finally {
574
+ verificationTimer?.();
575
+ }
576
+ }
577
+
578
+ /**
579
+ * Validate a subset of gloas data column sidecars against a block
580
+ * Gloas sidecars don't carry signed block headers, kzg commitments, or inclusion proofs
581
+ */
582
+ export async function validateGloasBlockDataColumnSidecars(
583
+ blockSlot: Slot,
584
+ blockRoot: Root,
585
+ blockKzgCommitments: Uint8Array[],
586
+ dataColumnSidecars: gloas.DataColumnSidecar[],
587
+ metrics?: BeaconMetrics["peerDas"] | null
588
+ ): Promise<void> {
589
+ metrics?.dataColumnSidecarProcessingRequests.inc(dataColumnSidecars.length);
590
+ const verificationTimer = metrics?.dataColumnSidecarGossipVerificationTime.startTimer();
591
+ try {
592
+ if (dataColumnSidecars.length === 0) {
593
+ return;
594
+ }
595
+
596
+ if (blockKzgCommitments.length === 0) {
597
+ throw new DataColumnSidecarValidationError(
598
+ {
599
+ code: DataColumnSidecarErrorCode.INCORRECT_SIDECAR_COUNT,
600
+ slot: blockSlot,
601
+ expected: 0,
602
+ actual: dataColumnSidecars.length,
603
+ },
604
+ "Block has no blob commitments but data column sidecars were provided"
605
+ );
606
+ }
607
+
608
+ const commitments: Uint8Array[] = [];
609
+ const cellIndices: number[] = [];
610
+ const cells: Uint8Array[] = [];
611
+ const proofs: Uint8Array[] = [];
612
+ for (const columnSidecar of dataColumnSidecars) {
613
+ if (columnSidecar.slot !== blockSlot) {
614
+ throw new DataColumnSidecarValidationError({
615
+ code: DataColumnSidecarErrorCode.INCORRECT_SIDECAR_SLOT,
616
+ columnIndex: columnSidecar.index,
617
+ expected: blockSlot,
618
+ actual: columnSidecar.slot,
619
+ });
620
+ }
621
+
622
+ if (!byteArrayEquals(columnSidecar.beaconBlockRoot, blockRoot)) {
623
+ throw new DataColumnSidecarValidationError({
624
+ code: DataColumnSidecarErrorCode.INCORRECT_BLOCK,
625
+ slot: blockSlot,
626
+ columnIndex: columnSidecar.index,
627
+ expected: toRootHex(blockRoot),
628
+ actual: toRootHex(columnSidecar.beaconBlockRoot),
629
+ });
630
+ }
631
+
632
+ if (columnSidecar.index >= NUMBER_OF_COLUMNS) {
633
+ throw new DataColumnSidecarValidationError(
634
+ {
635
+ code: DataColumnSidecarErrorCode.INVALID_INDEX,
636
+ slot: blockSlot,
637
+ columnIndex: columnSidecar.index,
638
+ },
639
+ "DataColumnSidecar has invalid index"
640
+ );
641
+ }
642
+
643
+ if (columnSidecar.column.length !== blockKzgCommitments.length) {
644
+ throw new DataColumnSidecarValidationError({
645
+ code: DataColumnSidecarErrorCode.INCORRECT_CELL_COUNT,
646
+ slot: blockSlot,
647
+ columnIndex: columnSidecar.index,
648
+ expected: blockKzgCommitments.length,
649
+ actual: columnSidecar.column.length,
650
+ });
651
+ }
652
+
653
+ if (columnSidecar.column.length !== columnSidecar.kzgProofs.length) {
654
+ throw new DataColumnSidecarValidationError({
655
+ code: DataColumnSidecarErrorCode.INCORRECT_KZG_PROOF_COUNT,
656
+ slot: blockSlot,
657
+ columnIndex: columnSidecar.index,
658
+ expected: columnSidecar.column.length,
659
+ actual: columnSidecar.kzgProofs.length,
660
+ });
661
+ }
662
+
663
+ commitments.push(...blockKzgCommitments);
664
+ cellIndices.push(...Array.from({length: columnSidecar.column.length}, () => columnSidecar.index));
665
+ cells.push(...columnSidecar.column);
666
+ proofs.push(...columnSidecar.kzgProofs);
667
+ }
668
+
669
+ let reason: string | undefined;
670
+ // batch verification for the cases: downloadByRange and downloadByRoot
671
+ const kzgVerificationTimer = metrics?.kzgVerificationDataColumnBatchTime.startTimer();
672
+ try {
673
+ const valid = await kzg.asyncVerifyCellKzgProofBatch(commitments, cellIndices, cells, proofs);
674
+ if (!valid) {
675
+ reason = "Invalid KZG proof batch";
676
+ }
677
+ } catch (e) {
678
+ reason = (e as Error).message;
679
+ } finally {
680
+ kzgVerificationTimer?.();
681
+ }
682
+ if (reason !== undefined) {
683
+ throw new DataColumnSidecarValidationError(
684
+ {
685
+ code: DataColumnSidecarErrorCode.INVALID_KZG_PROOF_BATCH,
686
+ slot: blockSlot,
687
+ reason,
688
+ },
689
+ "DataColumnSidecar has invalid KZG proof batch"
690
+ );
691
+ }
692
+
470
693
  metrics?.dataColumnSidecarProcessingSuccesses.inc();
471
694
  } finally {
472
695
  verificationTimer?.();
package/src/db/buckets.ts CHANGED
@@ -67,8 +67,8 @@ export enum Bucket {
67
67
  // lightClient_bestLightClientUpdate = 55, // SyncPeriod -> LightClientUpdate // DEPRECATED on v1.5.0
68
68
  lightClient_bestLightClientUpdate = 56, // SyncPeriod -> [Slot, LightClientUpdate]
69
69
 
70
- fulu_dataColumnSidecars = 57, // FULU BeaconBlockRoot -> DataColumnSidecars
71
- fulu_dataColumnSidecarsArchive = 58, // FULU BeaconBlockSlot -> DataColumnSidecars
70
+ allForks_dataColumnSidecars = 57, // BeaconBlockRoot -> DataColumnSidecars
71
+ allForks_dataColumnSidecarsArchive = 58, // BeaconBlockSlot -> DataColumnSidecars
72
72
 
73
73
  gloas_executionPayloadEnvelope = 59, // GLOAS BeaconBlockRoot -> SignedExecutionPayloadEnvelope
74
74
  gloas_executionPayloadEnvelopeArchive = 60, // GLOAS Slot -> SignedExecutionPayloadEnvelope
@@ -18,8 +18,10 @@ type BlockRoot = Root;
18
18
  */
19
19
  export class DataColumnSidecarRepository extends PrefixedRepository<BlockRoot, ColumnIndex, DataColumnSidecar> {
20
20
  constructor(config: ChainForkConfig, db: Db) {
21
- const bucket = Bucket.fulu_dataColumnSidecars;
22
- super(config, db, bucket, ssz.fulu.DataColumnSidecar, getBucketNameByValue(bucket));
21
+ const bucket = Bucket.allForks_dataColumnSidecars;
22
+ // Type won't be used since we select it dynamically based on fork
23
+ const type = ssz.fulu.DataColumnSidecar;
24
+ super(config, db, bucket, type, getBucketNameByValue(bucket));
23
25
  }
24
26
 
25
27
  /**