@lodestar/beacon-node 1.48.0-dev.e1303d42b0 → 1.48.0-dev.e17b11435f
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/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +39 -39
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.js +12 -1
- package/lib/chain/archiveStore/historicalState/metrics.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +0 -13
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +10 -1
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/chain.d.ts +5 -0
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +67 -38
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +1 -1
- package/lib/chain/emitter.js +1 -1
- package/lib/chain/errors/blockError.d.ts +3 -5
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +2 -2
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +0 -11
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +0 -2
- package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/errors/gossipValidation.d.ts +2 -1
- package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
- package/lib/chain/errors/gossipValidation.js +1 -0
- package/lib/chain/errors/gossipValidation.js.map +1 -1
- package/lib/chain/prepareNextSlot.js +13 -13
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +46 -64
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +9 -50
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +0 -29
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts +7 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +22 -5
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +4 -1
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +0 -6
- package/lib/network/gossip/encoding.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +2 -1
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +4 -20
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/processor/index.d.ts +49 -3
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +243 -98
- 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 +6 -22
- package/lib/network/reqresp/protocols.js.map +1 -1
- package/lib/network/reqresp/rateLimit.js +2 -1
- package/lib/network/reqresp/rateLimit.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +3 -1
- package/lib/sync/range/range.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/validator/index.ts +44 -43
- package/src/chain/archiveStore/historicalState/metrics.ts +14 -1
- package/src/chain/blocks/importBlock.ts +0 -13
- package/src/chain/blocks/utils/chainSegment.ts +10 -1
- package/src/chain/chain.ts +74 -46
- package/src/chain/emitter.ts +1 -1
- package/src/chain/errors/blockError.ts +3 -3
- package/src/chain/errors/executionPayloadEnvelope.ts +0 -9
- package/src/chain/errors/gossipValidation.ts +1 -0
- package/src/chain/prepareNextSlot.ts +16 -16
- package/src/chain/produceBlock/produceBlockBody.ts +50 -71
- package/src/chain/validation/block.ts +9 -66
- package/src/chain/validation/executionPayloadEnvelope.ts +0 -37
- package/src/chain/validatorMonitor.ts +24 -7
- package/src/execution/engine/mock.ts +4 -1
- package/src/network/gossip/encoding.ts +0 -6
- package/src/network/gossip/topic.ts +3 -25
- package/src/network/processor/index.ts +276 -148
- package/src/network/reqresp/protocols.ts +7 -24
- package/src/network/reqresp/rateLimit.ts +2 -1
- package/src/sync/range/range.ts +3 -1
package/src/chain/chain.ts
CHANGED
|
@@ -1271,59 +1271,65 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1271
1271
|
try {
|
|
1272
1272
|
const prevHead = this.forkChoice.getHead();
|
|
1273
1273
|
const head = this.forkChoice.updateAndGetHead({mode: UpdateHeadOpt.GetCanonicalHead}).head;
|
|
1274
|
+
this.emitHeadEvents(prevHead, head);
|
|
1275
|
+
return head;
|
|
1276
|
+
} catch (e) {
|
|
1277
|
+
this.metrics?.forkChoice.errors.inc({entrypoint: UpdateHeadOpt.GetCanonicalHead});
|
|
1278
|
+
throw e;
|
|
1279
|
+
} finally {
|
|
1280
|
+
timer?.();
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1274
1283
|
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1284
|
+
/**
|
|
1285
|
+
* Emit `head` and `head_v2` when the fork choice head differs between two observations. Every caller that
|
|
1286
|
+
* can move the head, `updateAndGetHead()` and `updateTime()`, must capture the head before and pass both.
|
|
1287
|
+
*/
|
|
1288
|
+
private emitHeadEvents(prevHead: ProtoBlock, head: ProtoBlock): void {
|
|
1289
|
+
const headRootChanged = head.blockRoot !== prevHead.blockRoot;
|
|
1280
1290
|
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
const epochTransition = computeStartSlotAtEpoch(computeEpochAtSlot(head.slot)) === head.slot;
|
|
1285
|
-
const executionOptimistic = isOptimisticBlock(head);
|
|
1286
|
-
|
|
1287
|
-
if (headRootChanged) {
|
|
1288
|
-
this.emitter.emit(routes.events.EventType.head, {
|
|
1289
|
-
block: head.blockRoot,
|
|
1290
|
-
epochTransition,
|
|
1291
|
-
slot: head.slot,
|
|
1292
|
-
state: head.stateRoot,
|
|
1293
|
-
previousDutyDependentRoot,
|
|
1294
|
-
currentDutyDependentRoot,
|
|
1295
|
-
executionOptimistic,
|
|
1296
|
-
});
|
|
1297
|
-
}
|
|
1291
|
+
if (!headRootChanged && prevHead.payloadStatus === head.payloadStatus) {
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1298
1294
|
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1295
|
+
try {
|
|
1296
|
+
const previousDutyDependentRoot = this.forkChoice.getDependentRoot(head, EpochDifference.previous);
|
|
1297
|
+
const currentDutyDependentRoot = this.forkChoice.getDependentRoot(head, EpochDifference.current);
|
|
1298
|
+
const epochTransition = computeStartSlotAtEpoch(computeEpochAtSlot(head.slot)) === head.slot;
|
|
1299
|
+
const executionOptimistic = isOptimisticBlock(head);
|
|
1300
|
+
|
|
1301
|
+
if (headRootChanged) {
|
|
1302
|
+
this.emitter.emit(routes.events.EventType.head, {
|
|
1303
|
+
block: head.blockRoot,
|
|
1304
|
+
epochTransition,
|
|
1305
|
+
slot: head.slot,
|
|
1306
|
+
state: head.stateRoot,
|
|
1307
|
+
previousDutyDependentRoot,
|
|
1308
|
+
currentDutyDependentRoot,
|
|
1309
|
+
executionOptimistic,
|
|
1311
1310
|
});
|
|
1312
|
-
} catch (e) {
|
|
1313
|
-
// getDependentRoot() may fail with error: "No block for root" as we can see in holesky non-finality issue
|
|
1314
|
-
this.logger.debug(
|
|
1315
|
-
"Error emitting head/head_v2 event",
|
|
1316
|
-
{slot: head.slot, root: head.blockRoot, headRootChanged},
|
|
1317
|
-
e as Error
|
|
1318
|
-
);
|
|
1319
1311
|
}
|
|
1320
1312
|
|
|
1321
|
-
|
|
1313
|
+
this.emitter.emit(routes.events.EventType.headV2, {
|
|
1314
|
+
version: this.config.getForkName(head.slot),
|
|
1315
|
+
data: {
|
|
1316
|
+
slot: head.slot,
|
|
1317
|
+
block: head.blockRoot,
|
|
1318
|
+
state: head.stateRoot,
|
|
1319
|
+
payloadStatus: head.payloadStatus === PayloadStatus.FULL ? "full" : "empty",
|
|
1320
|
+
epochTransition,
|
|
1321
|
+
currentEpochDependentRoot: previousDutyDependentRoot,
|
|
1322
|
+
nextEpochDependentRoot: currentDutyDependentRoot,
|
|
1323
|
+
executionOptimistic,
|
|
1324
|
+
},
|
|
1325
|
+
});
|
|
1322
1326
|
} catch (e) {
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
+
// getDependentRoot() may fail with error: "No block for root" as we can see in holesky non-finality issue
|
|
1328
|
+
this.logger.debug(
|
|
1329
|
+
"Error emitting head/head_v2 event",
|
|
1330
|
+
{slot: head.slot, root: head.blockRoot, headRootChanged},
|
|
1331
|
+
e as Error
|
|
1332
|
+
);
|
|
1327
1333
|
}
|
|
1328
1334
|
}
|
|
1329
1335
|
|
|
@@ -1612,7 +1618,10 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1612
1618
|
this.processShutdownCallback(this.forkChoice.irrecoverableError);
|
|
1613
1619
|
}
|
|
1614
1620
|
|
|
1621
|
+
// updateTime() recomputes the head on epoch-boundary checkpoint pull-up and under fast confirmation
|
|
1622
|
+
const prevHead = this.forkChoice.getHead();
|
|
1615
1623
|
this.forkChoice.updateTime(slot);
|
|
1624
|
+
this.emitHeadEvents(prevHead, this.forkChoice.getHead());
|
|
1616
1625
|
this.metrics?.clockSlot.set(slot);
|
|
1617
1626
|
|
|
1618
1627
|
this.attestationPool.prune(slot);
|
|
@@ -1670,6 +1679,25 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1670
1679
|
|
|
1671
1680
|
private async onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithHex): Promise<void> {
|
|
1672
1681
|
this.logger.verbose("Fork choice finalized", {epoch: cp.epoch, root: cp.rootHex});
|
|
1682
|
+
this.metrics?.finalizedEpoch.set(cp.epoch);
|
|
1683
|
+
const finalizedBlock = this.forkChoice.getBlockHexDefaultStatus(cp.rootHex);
|
|
1684
|
+
if (finalizedBlock) {
|
|
1685
|
+
// The callback runs synchronously inside fork choice checkpoint updates, defer writing to subscribers
|
|
1686
|
+
callInNextEventLoop(() => {
|
|
1687
|
+
this.emitter.emit(routes.events.EventType.finalizedCheckpoint, {
|
|
1688
|
+
block: cp.rootHex,
|
|
1689
|
+
epoch: cp.epoch,
|
|
1690
|
+
state: finalizedBlock.stateRoot,
|
|
1691
|
+
executionOptimistic: isOptimisticBlock(finalizedBlock),
|
|
1692
|
+
});
|
|
1693
|
+
});
|
|
1694
|
+
} else {
|
|
1695
|
+
this.logger.debug("Finalized block not found in fork choice, skip finalized_checkpoint event", {
|
|
1696
|
+
epoch: cp.epoch,
|
|
1697
|
+
root: cp.rootHex,
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1673
1701
|
const finalizedSlot = computeStartSlotAtEpoch(cp.epoch);
|
|
1674
1702
|
this.seenBlockProposers.prune(finalizedSlot);
|
|
1675
1703
|
|
package/src/chain/emitter.ts
CHANGED
|
@@ -33,7 +33,7 @@ export enum ChainEvent {
|
|
|
33
33
|
/**
|
|
34
34
|
* This event signals that the fork choice store has been updated.
|
|
35
35
|
*
|
|
36
|
-
* This event is guaranteed to be triggered whenever the fork choice
|
|
36
|
+
* This event is guaranteed to be triggered whenever the fork choice finalized checkpoint is updated. This is either in response to a newly processed block or a new clock tick.
|
|
37
37
|
*/
|
|
38
38
|
forkChoiceFinalized = "forkChoice:finalized",
|
|
39
39
|
/**
|
|
@@ -78,8 +78,8 @@ export enum BlockErrorCode {
|
|
|
78
78
|
TOO_MANY_KZG_COMMITMENTS = "BLOCK_ERROR_TOO_MANY_KZG_COMMITMENTS",
|
|
79
79
|
/** Bid parent block root does not match block parent root */
|
|
80
80
|
BID_PARENT_ROOT_MISMATCH = "BLOCK_ERROR_BID_PARENT_ROOT_MISMATCH",
|
|
81
|
-
/** A block
|
|
82
|
-
|
|
81
|
+
/** A block contains deposits where none are allowed */
|
|
82
|
+
NON_ZERO_DEPOSITS = "BLOCK_ERROR_NON_ZERO_DEPOSITS",
|
|
83
83
|
/** The parent block's execution payload has been verified as invalid */
|
|
84
84
|
PARENT_EXECUTION_INVALID = "BLOCK_ERROR_PARENT_EXECUTION_INVALID",
|
|
85
85
|
/**
|
|
@@ -153,7 +153,7 @@ export type BlockErrorType =
|
|
|
153
153
|
| {code: BlockErrorCode.DATA_UNAVAILABLE}
|
|
154
154
|
| {code: BlockErrorCode.TOO_MANY_KZG_COMMITMENTS; blobKzgCommitmentsLen: number; commitmentLimit: number}
|
|
155
155
|
| {code: BlockErrorCode.BID_PARENT_ROOT_MISMATCH; bidParentRoot: RootHex; blockParentRoot: RootHex}
|
|
156
|
-
| {code: BlockErrorCode.
|
|
156
|
+
| {code: BlockErrorCode.NON_ZERO_DEPOSITS; count: number}
|
|
157
157
|
| {code: BlockErrorCode.PARENT_EXECUTION_INVALID; parentRoot: RootHex}
|
|
158
158
|
| {code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN; parentRoot: RootHex; parentBlockHash: RootHex}
|
|
159
159
|
| {code: BlockErrorCode.NON_LINEAR_PAYLOAD_ROOTS; parentBlockHash: RootHex; expectedBlockHash: RootHex};
|
|
@@ -12,8 +12,6 @@ export enum ExecutionPayloadEnvelopeErrorCode {
|
|
|
12
12
|
BUILDER_INDEX_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BUILDER_INDEX_MISMATCH",
|
|
13
13
|
BLOCK_HASH_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BLOCK_HASH_MISMATCH",
|
|
14
14
|
EXECUTION_REQUESTS_ROOT_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_EXECUTION_REQUESTS_ROOT_MISMATCH",
|
|
15
|
-
EXECUTION_REQUESTS_COUNT_EXCEEDED = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_EXECUTION_REQUESTS_COUNT_EXCEEDED",
|
|
16
|
-
WITHDRAWALS_COUNT_EXCEEDED = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_WITHDRAWALS_COUNT_EXCEEDED",
|
|
17
15
|
INVALID_SIGNATURE = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_INVALID_SIGNATURE",
|
|
18
16
|
PAYLOAD_ENVELOPE_INPUT_MISSING = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_PAYLOAD_ENVELOPE_INPUT_MISSING",
|
|
19
17
|
}
|
|
@@ -44,13 +42,6 @@ export type ExecutionPayloadEnvelopeErrorType =
|
|
|
44
42
|
envelopeRequestsRoot: RootHex;
|
|
45
43
|
bidRequestsRoot: RootHex;
|
|
46
44
|
}
|
|
47
|
-
| {
|
|
48
|
-
code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_COUNT_EXCEEDED;
|
|
49
|
-
name: string;
|
|
50
|
-
count: number;
|
|
51
|
-
limit: number;
|
|
52
|
-
}
|
|
53
|
-
| {code: ExecutionPayloadEnvelopeErrorCode.WITHDRAWALS_COUNT_EXCEEDED; count: number; limit: number}
|
|
54
45
|
| {code: ExecutionPayloadEnvelopeErrorCode.INVALID_SIGNATURE}
|
|
55
46
|
| {code: ExecutionPayloadEnvelopeErrorCode.PAYLOAD_ENVELOPE_INPUT_MISSING; blockRoot: RootHex};
|
|
56
47
|
|
|
@@ -8,6 +8,7 @@ export enum GossipAction {
|
|
|
8
8
|
export enum GossipErrorCode {
|
|
9
9
|
INVALID_SERIALIZED_BYTES_ERROR_CODE = "GOSSIP_ERROR_INVALID_SERIALIZED_BYTES",
|
|
10
10
|
PAST_SLOT = "GOSSIP_ERROR_PAST_SLOT",
|
|
11
|
+
FUTURE_SLOT = "GOSSIP_ERROR_FUTURE_SLOT",
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export class GossipActionError<T extends {code: string}> extends LodestarError<T> {
|
|
@@ -243,6 +243,22 @@ export class PrepareNextSlotScheduler {
|
|
|
243
243
|
parentBlockHash = preparedState.latestExecutionPayloadHeader.blockHash;
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
// If emitPayloadAttributes is true emit a SSE payloadAttributes event for
|
|
247
|
+
// every slot. Without the flag, only emit the event if we are proposing in the next slot.
|
|
248
|
+
if (
|
|
249
|
+
(feeRecipient || this.chain.opts.emitPayloadAttributes === true) &&
|
|
250
|
+
this.chain.emitter.listenerCount(routes.events.EventType.payloadAttributes)
|
|
251
|
+
) {
|
|
252
|
+
const data = getPayloadAttributesForSSE(fork as ForkPostBellatrix, this.chain, {
|
|
253
|
+
prepareState: stateAfterParentPayload,
|
|
254
|
+
prepareSlot,
|
|
255
|
+
parentBlockRoot: fromHex(updatedHead.blockRoot),
|
|
256
|
+
parentBlockHash,
|
|
257
|
+
feeRecipient: feeRecipient ?? "0x0000000000000000000000000000000000000000",
|
|
258
|
+
});
|
|
259
|
+
this.chain.emitter.emit(routes.events.EventType.payloadAttributes, {data, version: fork});
|
|
260
|
+
}
|
|
261
|
+
|
|
246
262
|
if (feeRecipient) {
|
|
247
263
|
const preparationTime =
|
|
248
264
|
computeTimeAtSlot(this.config, prepareSlot, this.chain.genesisTime) - Date.now() / 1000;
|
|
@@ -273,22 +289,6 @@ export class PrepareNextSlotScheduler {
|
|
|
273
289
|
}
|
|
274
290
|
|
|
275
291
|
this.computeStateHashTreeRoot(preparedState, isEpochTransition);
|
|
276
|
-
|
|
277
|
-
// If emitPayloadAttributes is true emit a SSE payloadAttributes event for
|
|
278
|
-
// every slot. Without the flag, only emit the event if we are proposing in the next slot.
|
|
279
|
-
if (
|
|
280
|
-
(feeRecipient || this.chain.opts.emitPayloadAttributes === true) &&
|
|
281
|
-
this.chain.emitter.listenerCount(routes.events.EventType.payloadAttributes)
|
|
282
|
-
) {
|
|
283
|
-
const data = getPayloadAttributesForSSE(fork as ForkPostBellatrix, this.chain, {
|
|
284
|
-
prepareState: stateAfterParentPayload,
|
|
285
|
-
prepareSlot,
|
|
286
|
-
parentBlockRoot: fromHex(updatedHead.blockRoot),
|
|
287
|
-
parentBlockHash,
|
|
288
|
-
feeRecipient: feeRecipient ?? "0x0000000000000000000000000000000000000000",
|
|
289
|
-
});
|
|
290
|
-
this.chain.emitter.emit(routes.events.EventType.payloadAttributes, {data, version: fork});
|
|
291
|
-
}
|
|
292
292
|
} else {
|
|
293
293
|
// Pre-bellatrix only reaches here at an epoch transition to precompute the next epoch state
|
|
294
294
|
const preparedState = await this.chain.regen.getBlockSlotState(
|
|
@@ -528,23 +528,18 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
528
528
|
}
|
|
529
529
|
}
|
|
530
530
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
throw Error(`Invalid builder getHeader response for fork=${fork}, missing blobKzgCommitments`);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
(blockBody as deneb.BlindedBeaconBlockBody).blobKzgCommitments = blobKzgCommitments;
|
|
538
|
-
Object.assign(logMeta, {blobs: blobKzgCommitments.length});
|
|
531
|
+
const {blobKzgCommitments, executionRequests} = builderRes;
|
|
532
|
+
if (blobKzgCommitments === undefined) {
|
|
533
|
+
throw Error(`Invalid builder getHeader response for fork=${fork}, missing blobKzgCommitments`);
|
|
539
534
|
}
|
|
540
535
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
}
|
|
546
|
-
(blockBody as electra.BlindedBeaconBlockBody).executionRequests = executionRequests;
|
|
536
|
+
(blockBody as BlindedBeaconBlockBody<ForkName.fulu>).blobKzgCommitments = blobKzgCommitments;
|
|
537
|
+
Object.assign(logMeta, {blobs: blobKzgCommitments.length});
|
|
538
|
+
|
|
539
|
+
if (executionRequests === undefined) {
|
|
540
|
+
throw Error(`Invalid builder getHeader response for fork=${fork}, missing executionRequests`);
|
|
547
541
|
}
|
|
542
|
+
(blockBody as BlindedBeaconBlockBody<ForkName.fulu>).executionRequests = executionRequests;
|
|
548
543
|
}
|
|
549
544
|
|
|
550
545
|
// blockType === BlockType.Full
|
|
@@ -899,45 +894,38 @@ function preparePayloadAttributes(
|
|
|
899
894
|
): SSEPayloadAttributes["payloadAttributes"] {
|
|
900
895
|
const timestamp = computeTimeAtSlot(chain.config, prepareSlot, prepareState.genesisTime);
|
|
901
896
|
const prevRandao = prepareState.getRandaoMix(prepareState.epoch);
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
suggestedFeeRecipient: feeRecipient,
|
|
906
|
-
};
|
|
907
|
-
|
|
908
|
-
if (ForkSeq[fork] >= ForkSeq.capella) {
|
|
909
|
-
if (!isStatePostCapella(prepareState)) {
|
|
910
|
-
throw new Error("Expected Capella state for withdrawals");
|
|
911
|
-
}
|
|
897
|
+
if (!isStatePostCapella(prepareState)) {
|
|
898
|
+
throw new Error("Expected Capella state for withdrawals");
|
|
899
|
+
}
|
|
912
900
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
922
|
-
prepareState.getExpectedWithdrawals().expectedWithdrawals;
|
|
923
|
-
} else {
|
|
924
|
-
// When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
|
|
925
|
-
// already deducted from CL balances but never credited on the EL (the envelope
|
|
926
|
-
// was not delivered). The next payload must carry those same withdrawals to
|
|
927
|
-
// restore CL/EL consistency, otherwise validators permanently lose that balance.
|
|
928
|
-
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
929
|
-
prepareState.payloadExpectedWithdrawals;
|
|
901
|
+
let withdrawals: capella.Withdrawal[];
|
|
902
|
+
if (isStatePostGloas(prepareState)) {
|
|
903
|
+
const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
|
|
904
|
+
if (isExtendingPayload) {
|
|
905
|
+
// applyParentExecutionPayload sets latestBlockHash = parentBid.blockHash, so a mismatch
|
|
906
|
+
// here means the caller did not apply parent payload to prepareState
|
|
907
|
+
if (!byteArrayEquals(prepareState.latestBlockHash, prepareState.latestExecutionPayloadBid.blockHash)) {
|
|
908
|
+
throw new Error("Expected state with parent execution payload applied for withdrawals");
|
|
930
909
|
}
|
|
910
|
+
withdrawals = prepareState.getExpectedWithdrawals().expectedWithdrawals;
|
|
931
911
|
} else {
|
|
932
|
-
//
|
|
933
|
-
|
|
934
|
-
|
|
912
|
+
// When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
|
|
913
|
+
// already deducted from CL balances but never credited on the EL (the envelope
|
|
914
|
+
// was not delivered). The next payload must carry those same withdrawals to
|
|
915
|
+
// restore CL/EL consistency, otherwise validators permanently lose that balance.
|
|
916
|
+
withdrawals = prepareState.payloadExpectedWithdrawals;
|
|
935
917
|
}
|
|
918
|
+
} else {
|
|
919
|
+
withdrawals = prepareState.getExpectedWithdrawals().expectedWithdrawals;
|
|
936
920
|
}
|
|
937
921
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
922
|
+
const payloadAttributes: deneb.SSEPayloadAttributes["payloadAttributes"] = {
|
|
923
|
+
timestamp,
|
|
924
|
+
prevRandao,
|
|
925
|
+
suggestedFeeRecipient: feeRecipient,
|
|
926
|
+
withdrawals,
|
|
927
|
+
parentBeaconBlockRoot: parentBlockRoot,
|
|
928
|
+
};
|
|
941
929
|
|
|
942
930
|
if (ForkSeq[fork] >= ForkSeq.gloas) {
|
|
943
931
|
if (!isStatePostGloas(prepareState)) {
|
|
@@ -1050,37 +1038,28 @@ export async function produceCommonBlockBody<T extends BlockType>(
|
|
|
1050
1038
|
step: BlockProductionStep.attestations,
|
|
1051
1039
|
});
|
|
1052
1040
|
|
|
1053
|
-
const
|
|
1041
|
+
const endSyncAggregate = stepsMetrics?.startTimer();
|
|
1042
|
+
const parentBlockRoot = fromHex(parentBlock.blockRoot);
|
|
1043
|
+
const previousSlot = slot - 1;
|
|
1044
|
+
const syncAggregate = this.syncContributionAndProofPool.getAggregate(previousSlot, parentBlockRoot);
|
|
1045
|
+
this.metrics?.production.producedSyncAggregateParticipants.observe(
|
|
1046
|
+
syncAggregate.syncCommitteeBits.getTrueBitIndexes().length
|
|
1047
|
+
);
|
|
1048
|
+
endSyncAggregate?.({
|
|
1049
|
+
step: BlockProductionStep.syncAggregate,
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
// Live proposal production is supported from Fulu onward.
|
|
1053
|
+
return {
|
|
1054
1054
|
randaoReveal,
|
|
1055
1055
|
graffiti,
|
|
1056
|
-
// Eth1 data voting is no longer required since electra
|
|
1057
1056
|
eth1Data: currentState.eth1Data,
|
|
1058
1057
|
proposerSlashings: this.opts.disableProposerSlashings === true ? [] : proposerSlashings,
|
|
1059
1058
|
attesterSlashings,
|
|
1060
1059
|
attestations,
|
|
1061
|
-
// Since electra, deposits are processed by the execution layer,
|
|
1062
|
-
// we no longer support handling deposits from earlier forks.
|
|
1063
1060
|
deposits: [],
|
|
1064
1061
|
voluntaryExits,
|
|
1062
|
+
blsToExecutionChanges,
|
|
1063
|
+
syncAggregate,
|
|
1065
1064
|
};
|
|
1066
|
-
|
|
1067
|
-
if (ForkSeq[fork] >= ForkSeq.capella) {
|
|
1068
|
-
(blockBody as CommonBlockBody).blsToExecutionChanges = blsToExecutionChanges;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
const endSyncAggregate = stepsMetrics?.startTimer();
|
|
1072
|
-
if (ForkSeq[fork] >= ForkSeq.altair) {
|
|
1073
|
-
const parentBlockRoot = fromHex(parentBlock.blockRoot);
|
|
1074
|
-
const previousSlot = slot - 1;
|
|
1075
|
-
const syncAggregate = this.syncContributionAndProofPool.getAggregate(previousSlot, parentBlockRoot);
|
|
1076
|
-
this.metrics?.production.producedSyncAggregateParticipants.observe(
|
|
1077
|
-
syncAggregate.syncCommitteeBits.getTrueBitIndexes().length
|
|
1078
|
-
);
|
|
1079
|
-
(blockBody as CommonBlockBody).syncAggregate = syncAggregate;
|
|
1080
|
-
}
|
|
1081
|
-
endSyncAggregate?.({
|
|
1082
|
-
step: BlockProductionStep.syncAggregate,
|
|
1083
|
-
});
|
|
1084
|
-
|
|
1085
|
-
return blockBody as CommonBlockBody;
|
|
1086
1065
|
}
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
2
|
import {ExecutionStatus} from "@lodestar/fork-choice";
|
|
3
|
-
import {
|
|
4
|
-
ForkName,
|
|
5
|
-
MAX_ATTESTATIONS_ELECTRA,
|
|
6
|
-
MAX_ATTESTER_SLASHINGS_ELECTRA,
|
|
7
|
-
MAX_BLS_TO_EXECUTION_CHANGES,
|
|
8
|
-
MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
|
|
9
|
-
MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD,
|
|
10
|
-
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
|
|
11
|
-
MAX_PAYLOAD_ATTESTATIONS,
|
|
12
|
-
MAX_PROPOSER_SLASHINGS,
|
|
13
|
-
MAX_VOLUNTARY_EXITS,
|
|
14
|
-
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
|
|
15
|
-
MIN_SEED_LOOKAHEAD,
|
|
16
|
-
isForkPostBellatrix,
|
|
17
|
-
isForkPostDeneb,
|
|
18
|
-
isForkPostGloas,
|
|
19
|
-
} from "@lodestar/params";
|
|
3
|
+
import {ForkName, MIN_SEED_LOOKAHEAD, isForkPostBellatrix, isForkPostDeneb, isForkPostGloas} from "@lodestar/params";
|
|
20
4
|
import {
|
|
21
5
|
computeEpochAtSlot,
|
|
22
6
|
computeStartSlotAtEpoch,
|
|
@@ -173,7 +157,8 @@ export async function validateGossipBlock(
|
|
|
173
157
|
}
|
|
174
158
|
|
|
175
159
|
if (isForkPostGloas(fork)) {
|
|
176
|
-
const
|
|
160
|
+
const body = (block as gloas.BeaconBlock).body;
|
|
161
|
+
const bid = body.signedExecutionPayloadBid.message;
|
|
177
162
|
|
|
178
163
|
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in Consensus Layer
|
|
179
164
|
// -- i.e. validate that len(bid.blob_kzg_commitments) <= max_blobs_per_block
|
|
@@ -196,54 +181,12 @@ export async function validateGossipBlock(
|
|
|
196
181
|
});
|
|
197
182
|
}
|
|
198
183
|
|
|
199
|
-
// [REJECT] The
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
// `len(block.body.parent_execution_requests.builder_exits) <= MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD`.
|
|
206
|
-
// [REJECT] The counts of the block body operations are within their respective
|
|
207
|
-
// limits -- i.e. validate that
|
|
208
|
-
// `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`,
|
|
209
|
-
// `len(block.body.attester_slashings) <= MAX_ATTESTER_SLASHINGS_ELECTRA`,
|
|
210
|
-
// `len(block.body.attestations) <= MAX_ATTESTATIONS_ELECTRA`,
|
|
211
|
-
// `len(block.body.deposits) == 0`,
|
|
212
|
-
// `len(block.body.voluntary_exits) <= MAX_VOLUNTARY_EXITS`,
|
|
213
|
-
// `len(block.body.bls_to_execution_changes) <= MAX_BLS_TO_EXECUTION_CHANGES`,
|
|
214
|
-
// and `len(block.body.payload_attestations) <= MAX_PAYLOAD_ATTESTATIONS`.
|
|
215
|
-
const body = (block as gloas.BeaconBlock).body;
|
|
216
|
-
const requests = body.parentExecutionRequests;
|
|
217
|
-
const countLimits: [string, number, number][] = [
|
|
218
|
-
["parentExecutionRequests.withdrawals", requests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD],
|
|
219
|
-
[
|
|
220
|
-
"parentExecutionRequests.consolidations",
|
|
221
|
-
requests.consolidations.length,
|
|
222
|
-
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
|
|
223
|
-
],
|
|
224
|
-
[
|
|
225
|
-
"parentExecutionRequests.builderDeposits",
|
|
226
|
-
requests.builderDeposits.length,
|
|
227
|
-
MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
|
|
228
|
-
],
|
|
229
|
-
["parentExecutionRequests.builderExits", requests.builderExits.length, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD],
|
|
230
|
-
["proposerSlashings", body.proposerSlashings.length, MAX_PROPOSER_SLASHINGS],
|
|
231
|
-
["attesterSlashings", body.attesterSlashings.length, MAX_ATTESTER_SLASHINGS_ELECTRA],
|
|
232
|
-
["attestations", body.attestations.length, MAX_ATTESTATIONS_ELECTRA],
|
|
233
|
-
["deposits", body.deposits.length, 0],
|
|
234
|
-
["voluntaryExits", body.voluntaryExits.length, MAX_VOLUNTARY_EXITS],
|
|
235
|
-
["blsToExecutionChanges", body.blsToExecutionChanges.length, MAX_BLS_TO_EXECUTION_CHANGES],
|
|
236
|
-
["payloadAttestations", body.payloadAttestations.length, MAX_PAYLOAD_ATTESTATIONS],
|
|
237
|
-
];
|
|
238
|
-
for (const [name, count, limit] of countLimits) {
|
|
239
|
-
if (count > limit) {
|
|
240
|
-
throw new BlockGossipError(GossipAction.REJECT, {
|
|
241
|
-
code: BlockErrorCode.TOO_MANY_BLOCK_OPERATIONS,
|
|
242
|
-
name,
|
|
243
|
-
count,
|
|
244
|
-
limit,
|
|
245
|
-
});
|
|
246
|
-
}
|
|
184
|
+
// [REJECT] The block contains no deposits.
|
|
185
|
+
if (body.deposits.length !== 0) {
|
|
186
|
+
throw new BlockGossipError(GossipAction.REJECT, {
|
|
187
|
+
code: BlockErrorCode.NON_ZERO_DEPOSITS,
|
|
188
|
+
count: body.deposits.length,
|
|
189
|
+
});
|
|
247
190
|
}
|
|
248
191
|
|
|
249
192
|
// TODO GLOAS: [REJECT] The block's execution payload parent (defined by bid.parent_block_hash) passes all validation
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import {PayloadStatus} from "@lodestar/fork-choice";
|
|
2
|
-
import {
|
|
3
|
-
MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
|
|
4
|
-
MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD,
|
|
5
|
-
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
|
|
6
|
-
MAX_WITHDRAWALS_PER_PAYLOAD,
|
|
7
|
-
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
|
|
8
|
-
} from "@lodestar/params";
|
|
9
2
|
import {
|
|
10
3
|
computeStartSlotAtEpoch,
|
|
11
4
|
getExecutionPayloadEnvelopeSignatureSet,
|
|
@@ -122,36 +115,6 @@ async function validateExecutionPayloadEnvelope(
|
|
|
122
115
|
});
|
|
123
116
|
}
|
|
124
117
|
|
|
125
|
-
// [REJECT] The counts of `execution_requests` are within their respective limits.
|
|
126
|
-
// New in Gloas:EIP7688 — progressive lists are unbounded at the type level, so bounds
|
|
127
|
-
// are enforced here in gossip validation.
|
|
128
|
-
const {executionRequests} = envelope;
|
|
129
|
-
const requestCountLimits: [string, number, number][] = [
|
|
130
|
-
["withdrawals", executionRequests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD],
|
|
131
|
-
["consolidations", executionRequests.consolidations.length, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD],
|
|
132
|
-
["builderDeposits", executionRequests.builderDeposits.length, MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD],
|
|
133
|
-
["builderExits", executionRequests.builderExits.length, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD],
|
|
134
|
-
];
|
|
135
|
-
for (const [name, count, limit] of requestCountLimits) {
|
|
136
|
-
if (count > limit) {
|
|
137
|
-
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
138
|
-
code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_COUNT_EXCEEDED,
|
|
139
|
-
name,
|
|
140
|
-
count,
|
|
141
|
-
limit,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// [REJECT] The number of withdrawals is within the limit.
|
|
147
|
-
if (payload.withdrawals.length > MAX_WITHDRAWALS_PER_PAYLOAD) {
|
|
148
|
-
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
149
|
-
code: ExecutionPayloadEnvelopeErrorCode.WITHDRAWALS_COUNT_EXCEEDED,
|
|
150
|
-
count: payload.withdrawals.length,
|
|
151
|
-
limit: MAX_WITHDRAWALS_PER_PAYLOAD,
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
118
|
// Get the block state to verify the builder's signature.
|
|
156
119
|
const blockState = await chain.regen
|
|
157
120
|
.getState(block.stateRoot, RegenCaller.validateGossipPayloadEnvelope)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
+
import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
3
3
|
import {
|
|
4
4
|
IBeaconStateView,
|
|
5
5
|
ParticipationFlags,
|
|
@@ -1117,7 +1117,11 @@ function isCanonical(rootCache: RootHexCache, block: AttestationBlockInclusion):
|
|
|
1117
1117
|
|
|
1118
1118
|
/** Returns true if root at slot is the same at slot - 1 == there was no new block at slot */
|
|
1119
1119
|
function isMissedSlot(rootCache: RootHexCache, slot: Slot): boolean {
|
|
1120
|
-
|
|
1120
|
+
if (slot <= 0) {
|
|
1121
|
+
return false;
|
|
1122
|
+
}
|
|
1123
|
+
const root = rootCache.getBlockRootAtSlot(slot);
|
|
1124
|
+
return root !== null && root === rootCache.getBlockRootAtSlot(slot - 1);
|
|
1121
1125
|
}
|
|
1122
1126
|
|
|
1123
1127
|
function renderBlockProposalSummary(
|
|
@@ -1131,7 +1135,11 @@ function renderBlockProposalSummary(
|
|
|
1131
1135
|
return "not_submitted";
|
|
1132
1136
|
}
|
|
1133
1137
|
|
|
1134
|
-
|
|
1138
|
+
const canonicalRoot = rootCache.getBlockRootAtSlot(proposalSlot);
|
|
1139
|
+
if (canonicalRoot === null) {
|
|
1140
|
+
return "unknown";
|
|
1141
|
+
}
|
|
1142
|
+
if (canonicalRoot === proposal.blockRoot) {
|
|
1135
1143
|
// Canonical state includes our block
|
|
1136
1144
|
return "canonical";
|
|
1137
1145
|
}
|
|
@@ -1157,14 +1165,23 @@ function renderBlockProposalSummary(
|
|
|
1157
1165
|
* In normal network conditions the same root is read multiple times, specially the target.
|
|
1158
1166
|
*/
|
|
1159
1167
|
export class RootHexCache {
|
|
1160
|
-
private readonly blockRootSlotCache = new Map<Slot, RootHex>();
|
|
1168
|
+
private readonly blockRootSlotCache = new Map<Slot, RootHex | null>();
|
|
1161
1169
|
|
|
1162
1170
|
constructor(private readonly state: IBeaconStateView) {}
|
|
1163
1171
|
|
|
1164
|
-
|
|
1172
|
+
/**
|
|
1173
|
+
* Block root at `slot`, null if the state does not cover it: slots at or after the state's own slot (an inclusion
|
|
1174
|
+
* in a block the head state does not know yet, e.g. an orphaned block, or the slot after the last attestation of
|
|
1175
|
+
* the epoch) or slots older than `SLOTS_PER_HISTORICAL_ROOT`. Callers treat null as unknown instead of throwing
|
|
1176
|
+
* and aborting the summaries of all remaining validators.
|
|
1177
|
+
*/
|
|
1178
|
+
getBlockRootAtSlot(slot: Slot): RootHex | null {
|
|
1165
1179
|
let root = this.blockRootSlotCache.get(slot);
|
|
1166
|
-
if (
|
|
1167
|
-
root =
|
|
1180
|
+
if (root === undefined) {
|
|
1181
|
+
root =
|
|
1182
|
+
slot < this.state.slot && slot >= this.state.slot - SLOTS_PER_HISTORICAL_ROOT
|
|
1183
|
+
? toRootHex(this.state.getBlockRootAtSlot(slot))
|
|
1184
|
+
: null;
|
|
1168
1185
|
this.blockRootSlotCache.set(slot, root);
|
|
1169
1186
|
}
|
|
1170
1187
|
return root;
|
|
@@ -296,7 +296,10 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
|
|
|
296
296
|
|
|
297
297
|
// 5. Client software MUST update its forkchoice state if payloads referenced by forkchoiceState.headBlockHash and
|
|
298
298
|
// forkchoiceState.finalizedBlockHash are VALID.
|
|
299
|
-
|
|
299
|
+
//
|
|
300
|
+
// A zero finalizedBlockHash means "no finalized execution block" (e.g. the finalized checkpoint has no execution
|
|
301
|
+
// payload, pre-merge/pre-TTD). Real EL clients accept this, so the mock must not treat it as an unknown block.
|
|
302
|
+
if (finalizedBlockHash !== ZERO_HASH_HEX && !this.validBlocks.has(finalizedBlockHash)) {
|
|
300
303
|
throw Error(`Unknown finalizedBlockHash ${finalizedBlockHash}`);
|
|
301
304
|
}
|
|
302
305
|
this.headBlockHash = headBlockHash;
|
|
@@ -123,9 +123,6 @@ export class DataTransformSnappy implements DataTransform {
|
|
|
123
123
|
if (uncompressedDataLength > maxSize) {
|
|
124
124
|
throw Error(`ssz_snappy decoded data length ${uncompressedDataLength} > ${maxSize}`);
|
|
125
125
|
}
|
|
126
|
-
if (uncompressedDataLength > sszType.maxSize) {
|
|
127
|
-
throw Error(`ssz_snappy decoded data length ${uncompressedDataLength} > ${sszType.maxSize}`);
|
|
128
|
-
}
|
|
129
126
|
|
|
130
127
|
// Only after sanity length checks, we can decompress the data
|
|
131
128
|
// Using Buffer.alloc() instead of Buffer.allocUnsafe() to mitigate high GC pressure observed in some environments
|
|
@@ -146,9 +143,6 @@ export class DataTransformSnappy implements DataTransform {
|
|
|
146
143
|
if (data.length > maxSize) {
|
|
147
144
|
throw Error(`ssz_snappy encoded data length ${data.length} > ${maxSize}`);
|
|
148
145
|
}
|
|
149
|
-
if (data.length > sszType.maxSize) {
|
|
150
|
-
throw Error(`ssz_snappy encoded data length ${data.length} > ${sszType.maxSize}`);
|
|
151
|
-
}
|
|
152
146
|
|
|
153
147
|
// Using Buffer.alloc() instead of Buffer.allocUnsafe() to mitigate high GC pressure observed in some environments
|
|
154
148
|
const compressedData = Buffer.alloc(snappyWasm.max_compress_len(data.length));
|