@lodestar/beacon-node 1.49.0-dev.c9061c6942 → 1.49.0-dev.ceea36c6f2
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.js +2 -2
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/validator/index.js +6 -6
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.js +14 -3
- package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
- package/lib/chain/blocks/index.js +2 -2
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
- package/lib/chain/emitter.d.ts +10 -0
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js +4 -0
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/errors/attesterSlashingError.d.ts +4 -1
- package/lib/chain/errors/attesterSlashingError.d.ts.map +1 -1
- package/lib/chain/errors/attesterSlashingError.js +1 -0
- package/lib/chain/errors/attesterSlashingError.js.map +1 -1
- package/lib/chain/errors/proposerSlashingError.d.ts +4 -1
- package/lib/chain/errors/proposerSlashingError.d.ts.map +1 -1
- package/lib/chain/errors/proposerSlashingError.js +1 -0
- package/lib/chain/errors/proposerSlashingError.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +6 -6
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +2 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +3 -2
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +1 -2
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +1 -2
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +2 -2
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/db/repositories/blockArchive.d.ts +5 -0
- package/lib/db/repositories/blockArchive.d.ts.map +1 -1
- package/lib/db/repositories/blockArchive.js +36 -1
- package/lib/db/repositories/blockArchive.js.map +1 -1
- package/lib/network/gossip/encoding.d.ts +1 -2
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +5 -10
- package/lib/network/gossip/encoding.js.map +1 -1
- package/lib/network/gossip/gossipsub.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.js +16 -1
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +9 -6
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +23 -8
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +16 -5
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipValidatorFn.d.ts +2 -0
- package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
- package/lib/network/processor/gossipValidatorFn.js +88 -7
- package/lib/network/processor/gossipValidatorFn.js.map +1 -1
- package/lib/network/processor/index.d.ts +6 -2
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +26 -9
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/protocols.d.ts.map +1 -1
- package/lib/network/reqresp/protocols.js +19 -5
- package/lib/network/reqresp/protocols.js.map +1 -1
- package/lib/sync/types.d.ts +4 -0
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js +4 -0
- package/lib/sync/types.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +1 -0
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +15 -0
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/sszBytes.d.ts +5 -0
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +13 -1
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +14 -14
- package/src/api/impl/beacon/blocks/index.ts +2 -2
- package/src/api/impl/validator/index.ts +6 -6
- package/src/chain/archiveStore/utils/pruneHistory.ts +14 -4
- package/src/chain/blocks/index.ts +2 -2
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +1 -1
- package/src/chain/emitter.ts +7 -2
- package/src/chain/errors/attesterSlashingError.ts +3 -1
- package/src/chain/errors/proposerSlashingError.ts +3 -1
- package/src/chain/produceBlock/produceBlockBody.ts +17 -6
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +3 -2
- package/src/chain/validation/attesterSlashing.ts +1 -2
- package/src/chain/validation/proposerSlashing.ts +1 -2
- package/src/chain/validatorMonitor.ts +12 -2
- package/src/db/repositories/blockArchive.ts +38 -1
- package/src/network/gossip/encoding.ts +5 -8
- package/src/network/gossip/gossipsub.ts +19 -2
- package/src/network/gossip/topic.ts +25 -7
- package/src/network/processor/gossipHandlers.ts +18 -5
- package/src/network/processor/gossipValidatorFn.ts +111 -7
- package/src/network/processor/index.ts +37 -9
- package/src/network/reqresp/protocols.ts +31 -6
- package/src/sync/types.ts +6 -3
- package/src/sync/unknownBlock.ts +15 -0
- package/src/util/sszBytes.ts +18 -0
|
@@ -86,8 +86,13 @@ export const MAX_AWAITING_MESSAGES_PER_ROOT: Partial<Record<GossipType, number>>
|
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
88
|
* Track the forwarded peers we already emit to UnknownBlockInput sync.
|
|
89
|
+
* envelopeSlotEmitted: whether the unknownEnvelopeBlockRootSlot event was already emitted for this root.
|
|
89
90
|
*/
|
|
90
|
-
type SearchedRootEntry = {
|
|
91
|
+
type SearchedRootEntry = {
|
|
92
|
+
blockPeerIds?: Set<PeerIdStr>;
|
|
93
|
+
envelopePeerIds?: Set<PeerIdStr>;
|
|
94
|
+
envelopeSlotEmitted?: boolean;
|
|
95
|
+
};
|
|
91
96
|
|
|
92
97
|
/**
|
|
93
98
|
* This is respective to gossipsub seenTTL (which is 550 * 0.7 = 385s), also it's respective
|
|
@@ -347,12 +352,17 @@ export class NetworkProcessor {
|
|
|
347
352
|
}
|
|
348
353
|
|
|
349
354
|
/**
|
|
350
|
-
* Search envelope via `ChainEvent.unknownEnvelopeBlockRoot` event
|
|
355
|
+
* Search envelope via `ChainEvent.unknownEnvelopeBlockRoot` / `ChainEvent.unknownEnvelopeBlockRootSlot` event
|
|
351
356
|
* Slot is the message slot, which is not necessarily the same as the envelope's slot, but it can be used for a good prune strategy.
|
|
352
357
|
* In the rare case, if 2 messages on 2 slots search for the same root (for example beacon_attestation) we may emit the same root twice but BlockInputSync should handle it well.
|
|
353
358
|
* Same peer-forwarding + dedup behavior as searchUnknownBlock.
|
|
354
359
|
*/
|
|
355
|
-
searchUnknownEnvelope(
|
|
360
|
+
searchUnknownEnvelope(
|
|
361
|
+
{slot, root}: SlotRootHex,
|
|
362
|
+
source: BlockInputSource,
|
|
363
|
+
peer?: PeerIdStr,
|
|
364
|
+
slotIsPayloadSlot = false
|
|
365
|
+
): void {
|
|
356
366
|
if (this.chain.seenPayloadEnvelope(root)) {
|
|
357
367
|
return;
|
|
358
368
|
}
|
|
@@ -369,8 +379,17 @@ export class NetworkProcessor {
|
|
|
369
379
|
forwardedPeers.add(peer);
|
|
370
380
|
shouldEmit = true;
|
|
371
381
|
}
|
|
382
|
+
// the payload-slot seed must reach the sync once, even if a slot-less trigger started the search first
|
|
383
|
+
if (slotIsPayloadSlot && !entry.envelopeSlotEmitted) {
|
|
384
|
+
shouldEmit = true;
|
|
385
|
+
}
|
|
372
386
|
if (shouldEmit) {
|
|
373
|
-
|
|
387
|
+
if (slotIsPayloadSlot) {
|
|
388
|
+
entry.envelopeSlotEmitted = true;
|
|
389
|
+
this.chain.emitter.emit(ChainEvent.unknownEnvelopeBlockRootSlot, {rootHex: root, slot, peer, source});
|
|
390
|
+
} else {
|
|
391
|
+
this.chain.emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, {rootHex: root, peer, source});
|
|
392
|
+
}
|
|
374
393
|
}
|
|
375
394
|
}
|
|
376
395
|
|
|
@@ -494,8 +513,9 @@ export class NetworkProcessor {
|
|
|
494
513
|
if (root == null) break;
|
|
495
514
|
const payloadPresent = getPayloadPresentFromPayloadAttestationMessageSerialized(message.msg.data);
|
|
496
515
|
if (payloadPresent && !this.chain.forkChoice.hasPayloadHexUnsafe(root)) {
|
|
497
|
-
// payload attestation votes that the payload is available but it is not yet known
|
|
498
|
-
|
|
516
|
+
// payload attestation votes that the payload is available but it is not yet known.
|
|
517
|
+
// the PTC vote's slot is the payload's slot
|
|
518
|
+
this.searchUnknownRoot({slot, root}, false, true, peerId, true);
|
|
499
519
|
// do not await the envelope, payload attestation processing only requires that the block is known
|
|
500
520
|
// also do not reset preprocessResult, we may already await for the block
|
|
501
521
|
}
|
|
@@ -504,7 +524,8 @@ export class NetworkProcessor {
|
|
|
504
524
|
case GossipType.data_column_sidecar: {
|
|
505
525
|
if (root == null) break;
|
|
506
526
|
if (!this.chain.forkChoice.hasPayloadHexUnsafe(root)) {
|
|
507
|
-
|
|
527
|
+
// the sidecar's slot is the block's (and so the payload's) slot
|
|
528
|
+
this.searchUnknownRoot({slot, root}, false, true, peerId, true);
|
|
508
529
|
// do not await the envelope, we can do gossip validation
|
|
509
530
|
// also do not reset preprocessResult, we may already await for the block
|
|
510
531
|
}
|
|
@@ -641,16 +662,23 @@ export class NetworkProcessor {
|
|
|
641
662
|
return true;
|
|
642
663
|
}
|
|
643
664
|
|
|
665
|
+
/**
|
|
666
|
+
* Search block/envelope given a SlotRootHex
|
|
667
|
+
* envelopeSlotIsPayloadSlot: the message slot is the payload's slot or not
|
|
668
|
+
*/
|
|
644
669
|
private searchUnknownRoot(
|
|
645
670
|
slotRoot: SlotRootHex,
|
|
646
671
|
searchBlock: boolean,
|
|
647
672
|
searchEnvelope: boolean,
|
|
648
|
-
peerId: PeerIdStr
|
|
673
|
+
peerId: PeerIdStr,
|
|
674
|
+
envelopeSlotIsPayloadSlot = false
|
|
649
675
|
): void {
|
|
650
676
|
if (!searchBlock && !searchEnvelope) return;
|
|
651
677
|
if (this.tooManySearchedRoots(slotRoot.slot, slotRoot.root)) return;
|
|
652
678
|
if (searchBlock) this.searchUnknownBlock(slotRoot, BlockInputSource.network_processor, peerId);
|
|
653
|
-
if (searchEnvelope)
|
|
679
|
+
if (searchEnvelope) {
|
|
680
|
+
this.searchUnknownEnvelope(slotRoot, BlockInputSource.network_processor, peerId, envelopeSlotIsPayloadSlot);
|
|
681
|
+
}
|
|
654
682
|
}
|
|
655
683
|
|
|
656
684
|
private pushPendingGossipsubMessageToQueue(message: PendingGossipsubMessage): void {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {BeaconConfig} from "@lodestar/config";
|
|
2
|
-
import {ForkName} from "@lodestar/params";
|
|
2
|
+
import {ForkName, isForkPostGloas} from "@lodestar/params";
|
|
3
3
|
import {ContextBytesFactory, ContextBytesType, Encoding, TypeSizes} from "@lodestar/reqresp";
|
|
4
|
+
import {computeMaxGloasDataColumnSidecarSize} from "../../util/sszBytes.js";
|
|
4
5
|
import {rateLimitQuotas} from "./rateLimit.js";
|
|
5
6
|
import {ProtocolNoHandler, ReqRespMethod, Version, requestSszTypeByMethod, responseSszTypeByMethod} from "./types.js";
|
|
6
7
|
|
|
@@ -151,18 +152,42 @@ function toProtocol(protocol: ProtocolSummary) {
|
|
|
151
152
|
encoding: Encoding.SSZ_SNAPPY,
|
|
152
153
|
contextBytes: toContextBytes(protocol.contextBytesType, config),
|
|
153
154
|
inboundRateLimits: rateLimitQuotas(fork, config)[protocol.method],
|
|
154
|
-
requestSizes: requestType === null ? null : clampTypeSizes(requestType, config),
|
|
155
|
-
responseSizes: (fork) =>
|
|
155
|
+
requestSizes: requestType === null ? null : clampTypeSizes(requestType, config.MAX_PAYLOAD_SIZE),
|
|
156
|
+
responseSizes: (fork) =>
|
|
157
|
+
clampResponseTypeSizes(
|
|
158
|
+
responseSszTypeByMethod[protocol.method](fork, protocol.version),
|
|
159
|
+
protocol.method,
|
|
160
|
+
fork,
|
|
161
|
+
config
|
|
162
|
+
),
|
|
156
163
|
};
|
|
157
164
|
};
|
|
158
165
|
}
|
|
159
166
|
|
|
167
|
+
function clampResponseTypeSizes(
|
|
168
|
+
type: TypeSizes,
|
|
169
|
+
method: ReqRespMethod,
|
|
170
|
+
fork: ForkName,
|
|
171
|
+
config: BeaconConfig
|
|
172
|
+
): TypeSizes {
|
|
173
|
+
let maxPayloadSize = config.MAX_PAYLOAD_SIZE;
|
|
174
|
+
if (isForkPostGloas(fork)) {
|
|
175
|
+
switch (method) {
|
|
176
|
+
case ReqRespMethod.DataColumnSidecarsByRange:
|
|
177
|
+
case ReqRespMethod.DataColumnSidecarsByRoot:
|
|
178
|
+
maxPayloadSize = Math.min(maxPayloadSize, computeMaxGloasDataColumnSidecarSize(config));
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return clampTypeSizes(type, maxPayloadSize);
|
|
183
|
+
}
|
|
184
|
+
|
|
160
185
|
/**
|
|
161
|
-
* Length-prefix must be within the SSZ type bounds or
|
|
186
|
+
* Length-prefix must be within the SSZ type bounds or the configured payload limit, whichever is smaller.
|
|
162
187
|
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.12/specs/phase0/p2p-interface.md#encoding-strategies
|
|
163
188
|
*/
|
|
164
|
-
function clampTypeSizes(type: TypeSizes,
|
|
165
|
-
return {minSize: type.minSize, maxSize: Math.min(type.maxSize,
|
|
189
|
+
function clampTypeSizes(type: TypeSizes, maxPayloadSize: number): TypeSizes {
|
|
190
|
+
return {minSize: type.minSize, maxSize: Math.min(type.maxSize, maxPayloadSize)};
|
|
166
191
|
}
|
|
167
192
|
|
|
168
193
|
function toContextBytes(type: ContextBytesType, config: BeaconConfig): ContextBytesFactory {
|
package/src/sync/types.ts
CHANGED
|
@@ -23,6 +23,10 @@ export enum PendingBlockType {
|
|
|
23
23
|
* Payload analog of UNKNOWN_BLOCK_ROOT: we have a beacon block root but not its execution payload envelope.
|
|
24
24
|
*/
|
|
25
25
|
UNKNOWN_PAYLOAD_BLOCK_ROOT = "unknown_payload_block_root",
|
|
26
|
+
/**
|
|
27
|
+
* Same as UNKNOWN_PAYLOAD_BLOCK_ROOT, but the trigger also carries the payload's slot.
|
|
28
|
+
*/
|
|
29
|
+
UNKNOWN_PAYLOAD_BLOCK_ROOT_SLOT = "unknown_payload_block_root_slot",
|
|
26
30
|
/**
|
|
27
31
|
* Payload analog of INCOMPLETE_BLOCK_INPUT: we have a partial payload input that did not complete in time.
|
|
28
32
|
*/
|
|
@@ -130,9 +134,8 @@ export type PendingPayloadInput = {
|
|
|
130
134
|
export type PendingPayloadRootHex = {
|
|
131
135
|
status: PendingPayloadInputStatus.pending | PendingPayloadInputStatus.fetching;
|
|
132
136
|
rootHex: RootHex;
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
// payload/block slot. See BlockInputSync.resolvePayloadSlot.
|
|
137
|
+
// slot could be via fork choice or ChainEvent.unknownEnvelopeBlockRootSlot
|
|
138
|
+
// while ChainEvent.unknownEnvelopeBlockRoot does not provide one
|
|
136
139
|
slot?: Slot;
|
|
137
140
|
timeAddedSec: number;
|
|
138
141
|
timeSyncedSec?: number;
|
package/src/sync/unknownBlock.ts
CHANGED
|
@@ -152,6 +152,7 @@ export class BlockInputSync {
|
|
|
152
152
|
this.logger.verbose("BlockInputSync enabled.");
|
|
153
153
|
this.chain.emitter.on(ChainEvent.unknownBlockRoot, this.onUnknownBlockRoot);
|
|
154
154
|
this.chain.emitter.on(ChainEvent.unknownEnvelopeBlockRoot, this.onUnknownEnvelopeBlockRoot);
|
|
155
|
+
this.chain.emitter.on(ChainEvent.unknownEnvelopeBlockRootSlot, this.onUnknownEnvelopeBlockRootSlot);
|
|
155
156
|
this.chain.emitter.on(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
|
|
156
157
|
this.chain.emitter.on(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
|
|
157
158
|
this.chain.emitter.on(ChainEvent.blockUnknownParent, this.onUnknownParent);
|
|
@@ -179,6 +180,7 @@ export class BlockInputSync {
|
|
|
179
180
|
this.clearRateLimitBackoffTimer();
|
|
180
181
|
this.chain.emitter.off(ChainEvent.unknownBlockRoot, this.onUnknownBlockRoot);
|
|
181
182
|
this.chain.emitter.off(ChainEvent.unknownEnvelopeBlockRoot, this.onUnknownEnvelopeBlockRoot);
|
|
183
|
+
this.chain.emitter.off(ChainEvent.unknownEnvelopeBlockRootSlot, this.onUnknownEnvelopeBlockRootSlot);
|
|
182
184
|
this.chain.emitter.off(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
|
|
183
185
|
this.chain.emitter.off(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
|
|
184
186
|
this.chain.emitter.off(ChainEvent.blockUnknownParent, this.onUnknownParent);
|
|
@@ -242,6 +244,19 @@ export class BlockInputSync {
|
|
|
242
244
|
}
|
|
243
245
|
};
|
|
244
246
|
|
|
247
|
+
private onUnknownEnvelopeBlockRootSlot = (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRootSlot]): void => {
|
|
248
|
+
try {
|
|
249
|
+
const isNewRoot = this.addByPayloadRootHex(data.rootHex, data.peer, data.slot);
|
|
250
|
+
if (isNewRoot) {
|
|
251
|
+
this.triggerUnknownBlockSearch();
|
|
252
|
+
this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT_SLOT});
|
|
253
|
+
this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
|
|
254
|
+
}
|
|
255
|
+
} catch (e) {
|
|
256
|
+
this.logger.debug("Error handling unknownEnvelopeBlockRootSlot event", {}, e as Error);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
245
260
|
private onIncompletePayloadEnvelope = (data: ChainEventData[ChainEvent.incompletePayloadEnvelope]): void => {
|
|
246
261
|
try {
|
|
247
262
|
this.addByPayloadInput(data.payloadInput, data.peer);
|
package/src/util/sszBytes.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {BitArray, deserializeUint8ArrayBitListFromBytes} from "@chainsafe/ssz";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
3
|
import {
|
|
4
|
+
BYTES_PER_CELL,
|
|
4
5
|
BYTES_PER_FIELD_ELEMENT,
|
|
5
6
|
FIELD_ELEMENTS_PER_BLOB,
|
|
6
7
|
ForkName,
|
|
@@ -551,6 +552,23 @@ export function getBeaconBlockRootFromDataColumnSidecarSerialized(data: Uint8Arr
|
|
|
551
552
|
return "0x" + blockRootBuf.toString("hex");
|
|
552
553
|
}
|
|
553
554
|
|
|
555
|
+
// beaconBlockRoot is the last fixed field in the Gloas layout
|
|
556
|
+
const DATA_COLUMN_SIDECAR_GLOAS_FIXED_SIZE = BEACON_BLOCK_ROOT_POSITION_IN_GLOAS_DATA_COLUMN_SIDECAR + ROOT_SIZE; // 56 bytes
|
|
557
|
+
const KZG_PROOF_SIZE = 48; // Bytes48
|
|
558
|
+
const DATA_COLUMN_SIDECAR_GLOAS_PER_BLOB_SIZE = BYTES_PER_CELL + KZG_PROOF_SIZE; // 2048 + 48 = 2096 bytes
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Gloas sidecar size bound uses the largest blob limit across the entire schedule, including future entries.
|
|
562
|
+
* https://github.com/ethereum/consensus-specs/pull/5613
|
|
563
|
+
*/
|
|
564
|
+
export function computeMaxGloasDataColumnSidecarSize(config: ChainForkConfig): number {
|
|
565
|
+
const maxBlobs = config.BLOB_SCHEDULE.reduce(
|
|
566
|
+
(max, entry) => Math.max(max, entry.MAX_BLOBS_PER_BLOCK),
|
|
567
|
+
config.MAX_BLOBS_PER_BLOCK_ELECTRA
|
|
568
|
+
);
|
|
569
|
+
return DATA_COLUMN_SIDECAR_GLOAS_FIXED_SIZE + maxBlobs * DATA_COLUMN_SIDECAR_GLOAS_PER_BLOB_SIZE;
|
|
570
|
+
}
|
|
571
|
+
|
|
554
572
|
/**
|
|
555
573
|
* SignedExecutionPayloadEnvelope SSZ Layout:
|
|
556
574
|
* ├─ 4 bytes: message offset (points to byte 100)
|