@lodestar/beacon-node 1.48.0-dev.67344272c0 → 1.48.0-dev.68ce7b06a0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +4 -11
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +14 -0
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/config/index.d.ts.map +1 -1
- package/lib/api/impl/config/index.js +4 -1
- package/lib/api/impl/config/index.js.map +1 -1
- 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/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +4 -1
- package/lib/chain/archiveStore/archiveStore.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/archiveStore/utils/archiveBlocks.d.ts +9 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +37 -4
- package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts +5 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +12 -18
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/index.d.ts +8 -4
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +83 -17
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +8 -0
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/types.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 +26 -11
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/chain.d.ts +9 -4
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +82 -51
- 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/executionPayloadBid.d.ts +4 -0
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +1 -0
- package/lib/chain/errors/executionPayloadBid.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/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +2 -0
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +4 -4
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/lightClient/index.d.ts +3 -3
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +21 -23
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/lightClient/proofs.d.ts +2 -1
- package/lib/chain/lightClient/proofs.d.ts.map +1 -1
- package/lib/chain/lightClient/proofs.js +5 -1
- package/lib/chain/lightClient/proofs.js.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.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/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +56 -40
- package/lib/chain/validation/executionPayloadBid.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/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +5 -6
- package/lib/chain/validation/payloadAttestationMessage.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/builder/validateBid.d.ts.map +1 -1
- package/lib/execution/builder/validateBid.js +8 -5
- package/lib/execution/builder/validateBid.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/metrics/metrics/lodestar.d.ts +4 -3
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +5 -5
- package/lib/metrics/metrics/lodestar.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/network.js +2 -2
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +383 -279
- package/lib/network/processor/gossipHandlers.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 +254 -114
- 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 +24 -1
- package/lib/sync/range/range.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/blocks/index.ts +8 -14
- package/src/api/impl/beacon/state/utils.ts +15 -0
- package/src/api/impl/config/index.ts +4 -1
- package/src/api/impl/validator/index.ts +44 -43
- package/src/chain/archiveStore/archiveStore.ts +6 -0
- package/src/chain/archiveStore/historicalState/metrics.ts +14 -1
- package/src/chain/archiveStore/utils/archiveBlocks.ts +39 -3
- package/src/chain/blocks/importBlock.ts +25 -20
- package/src/chain/blocks/index.ts +120 -23
- package/src/chain/blocks/types.ts +9 -0
- package/src/chain/blocks/utils/chainSegment.ts +26 -12
- package/src/chain/chain.ts +100 -61
- package/src/chain/emitter.ts +1 -1
- package/src/chain/errors/blockError.ts +3 -3
- package/src/chain/errors/executionPayloadBid.ts +2 -0
- package/src/chain/errors/executionPayloadEnvelope.ts +0 -9
- package/src/chain/errors/gossipValidation.ts +1 -0
- package/src/chain/forkChoice/index.ts +2 -0
- package/src/chain/interface.ts +4 -4
- package/src/chain/lightClient/index.ts +32 -36
- package/src/chain/lightClient/proofs.ts +10 -0
- package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
- 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/executionPayloadBid.ts +62 -44
- package/src/chain/validation/executionPayloadEnvelope.ts +0 -37
- package/src/chain/validation/payloadAttestationMessage.ts +8 -9
- package/src/chain/validatorMonitor.ts +24 -7
- package/src/execution/builder/validateBid.ts +10 -6
- package/src/execution/engine/mock.ts +4 -1
- package/src/metrics/metrics/lodestar.ts +6 -5
- package/src/network/gossip/encoding.ts +0 -6
- package/src/network/gossip/topic.ts +3 -25
- package/src/network/network.ts +2 -2
- package/src/network/processor/gossipHandlers.ts +495 -345
- package/src/network/processor/index.ts +287 -165
- package/src/network/reqresp/protocols.ts +7 -24
- package/src/network/reqresp/rateLimit.ts +2 -1
- package/src/sync/range/range.ts +23 -1
package/src/chain/chain.ts
CHANGED
|
@@ -82,7 +82,7 @@ import {IBlockInput, isBlockInputBlobs, isBlockInputColumns} from "./blocks/bloc
|
|
|
82
82
|
import {BlockProcessor, ImportBlockOpts} from "./blocks/index.js";
|
|
83
83
|
import {PayloadEnvelopeInputSource} from "./blocks/payloadEnvelopeInput/index.js";
|
|
84
84
|
import {PayloadEnvelopeProcessor} from "./blocks/payloadEnvelopeProcessor.js";
|
|
85
|
-
import {ImportPayloadOpts} from "./blocks/types.js";
|
|
85
|
+
import {ImportPayloadOpts, ProcessBlocksResult} from "./blocks/types.js";
|
|
86
86
|
import {persistBlockInput} from "./blocks/writeBlockInputToDb.js";
|
|
87
87
|
import {persistPayloadEnvelopeInput} from "./blocks/writePayloadEnvelopeInputToDb.js";
|
|
88
88
|
import {BlsMultiThreadWorkerPool, BlsSingleThreadVerifier, IBlsVerifier} from "./bls/index.js";
|
|
@@ -1167,15 +1167,15 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1167
1167
|
}
|
|
1168
1168
|
|
|
1169
1169
|
async processBlock(block: IBlockInput, opts?: ImportBlockOpts): Promise<void> {
|
|
1170
|
-
|
|
1170
|
+
await this.blockProcessor.processBlocksJob([block], null, opts);
|
|
1171
1171
|
}
|
|
1172
1172
|
|
|
1173
1173
|
async processChainSegment(
|
|
1174
1174
|
blocks: IBlockInput[],
|
|
1175
1175
|
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
1176
1176
|
opts?: ImportBlockOpts
|
|
1177
|
-
): Promise<
|
|
1178
|
-
|
|
1177
|
+
): Promise<ProcessBlocksResult> {
|
|
1178
|
+
return this.blockProcessor.processBlocksJob(blocks, payloadEnvelopes, opts);
|
|
1179
1179
|
}
|
|
1180
1180
|
|
|
1181
1181
|
async processExecutionPayload(payloadInput: PayloadEnvelopeInput, opts?: ImportPayloadOpts): Promise<void> {
|
|
@@ -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
|
|
|
@@ -1381,10 +1387,15 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1381
1387
|
const slot = data.slot;
|
|
1382
1388
|
if (isBlindedBeaconBlock(data)) {
|
|
1383
1389
|
const sszType = this.config.getPostBellatrixForkTypes(slot).BlindedBeaconBlock;
|
|
1384
|
-
void this.persistSszObject(
|
|
1390
|
+
void this.persistSszObject(
|
|
1391
|
+
"BlindedBeaconBlock",
|
|
1392
|
+
sszType.serialize(data),
|
|
1393
|
+
toRootHex(sszType.hashTreeRoot(data)),
|
|
1394
|
+
suffix
|
|
1395
|
+
);
|
|
1385
1396
|
} else {
|
|
1386
1397
|
const sszType = this.config.getForkTypes(slot).BeaconBlock;
|
|
1387
|
-
void this.persistSszObject("BeaconBlock", sszType.serialize(data), sszType.hashTreeRoot(data), suffix);
|
|
1398
|
+
void this.persistSszObject("BeaconBlock", sszType.serialize(data), toRootHex(sszType.hashTreeRoot(data)), suffix);
|
|
1388
1399
|
}
|
|
1389
1400
|
}
|
|
1390
1401
|
|
|
@@ -1405,33 +1416,39 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1405
1416
|
this.persistSszObject(
|
|
1406
1417
|
`SignedBeaconBlock_slot_${blockSlot}`,
|
|
1407
1418
|
blockType.serialize(block),
|
|
1408
|
-
|
|
1419
|
+
toRootHex(this.config.getForkTypes(blockSlot).BeaconBlock.hashTreeRoot(block.message)),
|
|
1409
1420
|
`${logStr}_block`
|
|
1410
1421
|
),
|
|
1411
1422
|
this.persistSszObject(
|
|
1412
1423
|
`preState_slot_${preState.slot}_BeaconState`,
|
|
1413
1424
|
preState.serialize(),
|
|
1414
|
-
preState.hashTreeRoot(),
|
|
1425
|
+
toRootHex(preState.hashTreeRoot()),
|
|
1415
1426
|
`${logStr}_pre_state`
|
|
1416
1427
|
),
|
|
1417
1428
|
this.persistSszObject(
|
|
1418
1429
|
`postState_slot_${postState.slot}_BeaconState`,
|
|
1419
1430
|
postState.serialize(),
|
|
1420
|
-
|
|
1431
|
+
toRootHex(postStateRoot),
|
|
1421
1432
|
`${logStr}_post_state`
|
|
1422
1433
|
),
|
|
1423
1434
|
]);
|
|
1424
1435
|
}
|
|
1425
1436
|
|
|
1426
|
-
persistInvalidSszValue<T>(type: Type<T>, sszObject: T, suffix?: string): void {
|
|
1437
|
+
persistInvalidSszValue<T>(type: Type<T>, sszObject: T, suffix?: string, rootHex?: RootHex): void {
|
|
1427
1438
|
if (this.opts.persistInvalidSszObjects) {
|
|
1428
|
-
void this.persistSszObject(
|
|
1439
|
+
void this.persistSszObject(
|
|
1440
|
+
type.typeName,
|
|
1441
|
+
type.serialize(sszObject),
|
|
1442
|
+
// in SignedBeaconBlock case, we want to use BeaconBlock root instead
|
|
1443
|
+
rootHex ?? toRootHex(type.hashTreeRoot(sszObject)),
|
|
1444
|
+
suffix
|
|
1445
|
+
);
|
|
1429
1446
|
}
|
|
1430
1447
|
}
|
|
1431
1448
|
|
|
1432
|
-
persistInvalidSszBytes(typeName: string, sszBytes: Uint8Array, suffix?: string): void {
|
|
1449
|
+
persistInvalidSszBytes(typeName: string, sszBytes: Uint8Array, rootHex: RootHex, suffix?: string): void {
|
|
1433
1450
|
if (this.opts.persistInvalidSszObjects) {
|
|
1434
|
-
void this.persistSszObject(typeName, sszBytes,
|
|
1451
|
+
void this.persistSszObject(typeName, sszBytes, rootHex, suffix);
|
|
1435
1452
|
}
|
|
1436
1453
|
}
|
|
1437
1454
|
|
|
@@ -1562,14 +1579,14 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1562
1579
|
return {state: blockState, stateId: "block_state_any_epoch", shouldWarn: true};
|
|
1563
1580
|
}
|
|
1564
1581
|
|
|
1565
|
-
private async persistSszObject(prefix: string, bytes: Uint8Array,
|
|
1582
|
+
private async persistSszObject(prefix: string, bytes: Uint8Array, rootHex: RootHex, logStr?: string): Promise<void> {
|
|
1566
1583
|
const now = new Date();
|
|
1567
1584
|
// yyyy-MM-dd
|
|
1568
1585
|
const dateStr = now.toISOString().split("T")[0];
|
|
1569
1586
|
|
|
1570
1587
|
// by default store to lodestar_archive of current dir
|
|
1571
1588
|
const dirpath = path.join(this.opts.persistInvalidSszObjectsDir ?? "invalid_ssz_objects", dateStr);
|
|
1572
|
-
const filepath = path.join(dirpath, `${prefix}_${
|
|
1589
|
+
const filepath = path.join(dirpath, `${prefix}_${rootHex}.ssz`);
|
|
1573
1590
|
|
|
1574
1591
|
await ensureDir(dirpath);
|
|
1575
1592
|
|
|
@@ -1612,7 +1629,10 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1612
1629
|
this.processShutdownCallback(this.forkChoice.irrecoverableError);
|
|
1613
1630
|
}
|
|
1614
1631
|
|
|
1632
|
+
// updateTime() recomputes the head on epoch-boundary checkpoint pull-up and under fast confirmation
|
|
1633
|
+
const prevHead = this.forkChoice.getHead();
|
|
1615
1634
|
this.forkChoice.updateTime(slot);
|
|
1635
|
+
this.emitHeadEvents(prevHead, this.forkChoice.getHead());
|
|
1616
1636
|
this.metrics?.clockSlot.set(slot);
|
|
1617
1637
|
|
|
1618
1638
|
this.attestationPool.prune(slot);
|
|
@@ -1670,6 +1690,25 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1670
1690
|
|
|
1671
1691
|
private async onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithHex): Promise<void> {
|
|
1672
1692
|
this.logger.verbose("Fork choice finalized", {epoch: cp.epoch, root: cp.rootHex});
|
|
1693
|
+
this.metrics?.finalizedEpoch.set(cp.epoch);
|
|
1694
|
+
const finalizedBlock = this.forkChoice.getBlockHexDefaultStatus(cp.rootHex);
|
|
1695
|
+
if (finalizedBlock) {
|
|
1696
|
+
// The callback runs synchronously inside fork choice checkpoint updates, defer writing to subscribers
|
|
1697
|
+
callInNextEventLoop(() => {
|
|
1698
|
+
this.emitter.emit(routes.events.EventType.finalizedCheckpoint, {
|
|
1699
|
+
block: cp.rootHex,
|
|
1700
|
+
epoch: cp.epoch,
|
|
1701
|
+
state: finalizedBlock.stateRoot,
|
|
1702
|
+
executionOptimistic: isOptimisticBlock(finalizedBlock),
|
|
1703
|
+
});
|
|
1704
|
+
});
|
|
1705
|
+
} else {
|
|
1706
|
+
this.logger.debug("Finalized block not found in fork choice, skip finalized_checkpoint event", {
|
|
1707
|
+
epoch: cp.epoch,
|
|
1708
|
+
root: cp.rootHex,
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1673
1712
|
const finalizedSlot = computeStartSlotAtEpoch(cp.epoch);
|
|
1674
1713
|
this.seenBlockProposers.prune(finalizedSlot);
|
|
1675
1714
|
|
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};
|
|
@@ -5,6 +5,7 @@ export enum ExecutionPayloadBidErrorCode {
|
|
|
5
5
|
BUILDER_NOT_ELIGIBLE = "EXECUTION_PAYLOAD_BID_ERROR_BUILDER_NOT_ELIGIBLE",
|
|
6
6
|
INVALID_BUILDER_VERSION = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_BUILDER_VERSION",
|
|
7
7
|
NON_ZERO_EXECUTION_PAYMENT = "EXECUTION_PAYLOAD_BID_ERROR_NON_ZERO_EXECUTION_PAYMENT",
|
|
8
|
+
BLOCK_HASH_EQUALS_PARENT_BLOCK_HASH = "EXECUTION_PAYLOAD_BID_ERROR_BLOCK_HASH_EQUALS_PARENT_BLOCK_HASH",
|
|
8
9
|
INCOMPATIBLE_WITH_HEAD = "EXECUTION_PAYLOAD_BID_ERROR_INCOMPATIBLE_WITH_HEAD",
|
|
9
10
|
BID_ALREADY_KNOWN = "EXECUTION_PAYLOAD_BID_ERROR_BID_ALREADY_KNOWN",
|
|
10
11
|
BID_TOO_LOW = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_LOW",
|
|
@@ -63,6 +64,7 @@ export type ExecutionPayloadBidErrorType =
|
|
|
63
64
|
}
|
|
64
65
|
| {code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT; parentBlockRoot: RootHex}
|
|
65
66
|
| {code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH; parentBlockHash: RootHex}
|
|
67
|
+
| {code: ExecutionPayloadBidErrorCode.BLOCK_HASH_EQUALS_PARENT_BLOCK_HASH; blockHash: RootHex}
|
|
66
68
|
| {code: ExecutionPayloadBidErrorCode.INVALID_SLOT; builderIndex: BuilderIndex; slot: Slot}
|
|
67
69
|
| {code: ExecutionPayloadBidErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot}
|
|
68
70
|
| {
|
|
@@ -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> {
|
|
@@ -135,6 +135,7 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
135
135
|
blockRoot: toRootHex(checkpoint.root),
|
|
136
136
|
timeliness: true, // Optimistically assume is timely
|
|
137
137
|
ptcTimeliness: true, // Spec: block_timeliness for anchor = [True, True]
|
|
138
|
+
importedTimely: true, // Optimistically assume is timely
|
|
138
139
|
proposerIndex: blockHeader.proposerIndex,
|
|
139
140
|
|
|
140
141
|
justifiedEpoch: justifiedCheckpoint.epoch,
|
|
@@ -233,6 +234,7 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
233
234
|
targetRoot: headRoot,
|
|
234
235
|
timeliness: true, // Optimistically assume is timely
|
|
235
236
|
ptcTimeliness: true, // Spec: block_timeliness for anchor = [True, True]
|
|
237
|
+
importedTimely: true, // Optimistically assume is timely
|
|
236
238
|
proposerIndex: blockHeader.proposerIndex,
|
|
237
239
|
|
|
238
240
|
justifiedEpoch: justifiedCheckpoint.epoch,
|
package/src/chain/interface.ts
CHANGED
|
@@ -35,7 +35,7 @@ import {IArchiveStore} from "./archiveStore/interface.js";
|
|
|
35
35
|
import {CheckpointBalancesCache} from "./balancesCache.js";
|
|
36
36
|
import {BeaconProposerCache, ProposerPreparationData} from "./beaconProposerCache.js";
|
|
37
37
|
import {IBlockInput} from "./blocks/blockInput/index.js";
|
|
38
|
-
import {ImportBlockOpts, ImportPayloadOpts} from "./blocks/types.js";
|
|
38
|
+
import {ImportBlockOpts, ImportPayloadOpts, ProcessBlocksResult} from "./blocks/types.js";
|
|
39
39
|
import {IBlsVerifier} from "./bls/index.js";
|
|
40
40
|
import {BuilderCircuitBreaker} from "./builderCircuitBreaker.js";
|
|
41
41
|
import {ColumnReconstructionTracker} from "./ColumnReconstructionTracker.js";
|
|
@@ -262,7 +262,7 @@ export interface IBeaconChain {
|
|
|
262
262
|
blocks: IBlockInput[],
|
|
263
263
|
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
264
264
|
opts?: ImportBlockOpts
|
|
265
|
-
): Promise<
|
|
265
|
+
): Promise<ProcessBlocksResult>;
|
|
266
266
|
|
|
267
267
|
/** Process execution payload envelope: verify, import to fork choice, and persist to DB */
|
|
268
268
|
processExecutionPayload(payloadInput: PayloadEnvelopeInput, opts?: ImportPayloadOpts): Promise<void>;
|
|
@@ -290,8 +290,8 @@ export interface IBeaconChain {
|
|
|
290
290
|
postState: IBeaconStateView,
|
|
291
291
|
block: SignedBeaconBlock
|
|
292
292
|
): Promise<void>;
|
|
293
|
-
persistInvalidSszValue<T>(type: Type<T>, sszObject: T
|
|
294
|
-
persistInvalidSszBytes(type: string, sszBytes: Uint8Array, suffix?: string): void;
|
|
293
|
+
persistInvalidSszValue<T>(type: Type<T>, sszObject: T, suffix?: string, rootHex?: RootHex): void;
|
|
294
|
+
persistInvalidSszBytes(type: string, sszBytes: Uint8Array, rootHex: RootHex, suffix?: string): void;
|
|
295
295
|
regenStateForAttestationVerification(
|
|
296
296
|
attEpoch: Epoch,
|
|
297
297
|
shufflingDependentRoot: RootHex,
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
ForkName,
|
|
6
6
|
ForkPostAltair,
|
|
7
7
|
ForkPostBellatrix,
|
|
8
|
+
ForkPostGloas,
|
|
8
9
|
ForkPreGloas,
|
|
9
10
|
ForkSeq,
|
|
10
11
|
MIN_SYNC_COMMITTEE_PARTICIPANTS,
|
|
@@ -40,7 +41,6 @@ import {
|
|
|
40
41
|
Slot,
|
|
41
42
|
SyncPeriod,
|
|
42
43
|
altair,
|
|
43
|
-
electra,
|
|
44
44
|
phase0,
|
|
45
45
|
ssz,
|
|
46
46
|
} from "@lodestar/types";
|
|
@@ -52,7 +52,12 @@ import {Metrics} from "../../metrics/index.js";
|
|
|
52
52
|
import {IClock} from "../../util/clock.js";
|
|
53
53
|
import {ChainEventEmitter} from "../emitter.js";
|
|
54
54
|
import {LightClientServerError, LightClientServerErrorCode} from "../errors/lightClientError.js";
|
|
55
|
-
import {
|
|
55
|
+
import {
|
|
56
|
+
getBlockBodyExecutionBlockHashProof,
|
|
57
|
+
getBlockBodyExecutionHeaderProof,
|
|
58
|
+
getCurrentSyncCommitteeBranch,
|
|
59
|
+
getNextSyncCommitteeBranch,
|
|
60
|
+
} from "./proofs.js";
|
|
56
61
|
|
|
57
62
|
export type LightClientServerOpts = {
|
|
58
63
|
disableLightClientServerOnImportBlockHead?: boolean;
|
|
@@ -61,6 +66,7 @@ export type LightClientServerOpts = {
|
|
|
61
66
|
|
|
62
67
|
type DependentRootHex = RootHex;
|
|
63
68
|
type BlockRooHex = RootHex;
|
|
69
|
+
type LightClientZeroFinality = Pick<LightClientUpdate, "finalityBranch" | "finalizedHeader">;
|
|
64
70
|
|
|
65
71
|
export type SyncAttestedData = {
|
|
66
72
|
attestedHeader: LightClientHeader;
|
|
@@ -199,6 +205,7 @@ export class LightClientServer {
|
|
|
199
205
|
private readonly clock: IClock;
|
|
200
206
|
private readonly signal: AbortSignal;
|
|
201
207
|
private readonly knownSyncCommittee = new MapDef<SyncPeriod, Set<DependentRootHex>>(() => new Set());
|
|
208
|
+
private readonly zeroFinalityByFork = new Map<ForkName, LightClientZeroFinality>();
|
|
202
209
|
private storedCurrentSyncCommittee = false;
|
|
203
210
|
|
|
204
211
|
/**
|
|
@@ -208,10 +215,6 @@ export class LightClientServer {
|
|
|
208
215
|
private checkpointHeaders = new Map<BlockRooHex, LightClientHeader>();
|
|
209
216
|
private latestHeadUpdate: LightClientOptimisticUpdate | null = null;
|
|
210
217
|
|
|
211
|
-
private readonly zero: Pick<
|
|
212
|
-
altair.LightClientUpdate | electra.LightClientUpdate,
|
|
213
|
-
"finalityBranch" | "finalizedHeader"
|
|
214
|
-
>;
|
|
215
218
|
private finalized: LightClientFinalityUpdate | null = null;
|
|
216
219
|
|
|
217
220
|
constructor(
|
|
@@ -227,14 +230,6 @@ export class LightClientServer {
|
|
|
227
230
|
this.logger = logger;
|
|
228
231
|
this.signal = signal;
|
|
229
232
|
|
|
230
|
-
this.zero = {
|
|
231
|
-
// Assign the highest pre-Gloas light-client header because post-Gloas light-client updates are skipped for now.
|
|
232
|
-
finalizedHeader: ssz.electra.LightClientHeader.defaultValue(),
|
|
233
|
-
// Electra finalityBranch has fixed length of 5 whereas altair has 4. The fifth element will be ignored
|
|
234
|
-
// when serializing as altair LightClientUpdate
|
|
235
|
-
finalityBranch: ssz.electra.LightClientUpdate.fields.finalityBranch.defaultValue(),
|
|
236
|
-
};
|
|
237
|
-
|
|
238
233
|
if (metrics) {
|
|
239
234
|
metrics.lightclientServer.highestSlot.addCollect(() => {
|
|
240
235
|
if (this.latestHeadUpdate) {
|
|
@@ -270,14 +265,6 @@ export class LightClientServer {
|
|
|
270
265
|
return;
|
|
271
266
|
}
|
|
272
267
|
|
|
273
|
-
// TODO GLOAS: Light client updates for gloas are not yet updated in the spec.
|
|
274
|
-
// The block body no longer contains execution payload, so `blockToLightClientHeader`
|
|
275
|
-
// cannot construct a header from a gloas block. Skip all light client processing
|
|
276
|
-
// for post-gloas blocks, revisit once there is a spec for it.
|
|
277
|
-
if (this.config.getForkSeq(block.slot) >= ForkSeq.gloas) {
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
268
|
// What is the syncAggregate signing?
|
|
282
269
|
// From the state-transition
|
|
283
270
|
// ```
|
|
@@ -695,9 +682,16 @@ export class LightClientServer {
|
|
|
695
682
|
}
|
|
696
683
|
} else {
|
|
697
684
|
isFinalized = false;
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
685
|
+
let zeroFinality = this.zeroFinalityByFork.get(attestedFork);
|
|
686
|
+
if (!zeroFinality) {
|
|
687
|
+
const {finalityBranch, finalizedHeader} = this.config
|
|
688
|
+
.getPostAltairForkTypes(attestedHeader.beacon.slot)
|
|
689
|
+
.LightClientUpdate.defaultValue();
|
|
690
|
+
zeroFinality = {finalityBranch, finalizedHeader};
|
|
691
|
+
this.zeroFinalityByFork.set(attestedFork, zeroFinality);
|
|
692
|
+
}
|
|
693
|
+
finalityBranch = zeroFinality.finalityBranch;
|
|
694
|
+
finalizedHeader = zeroFinality.finalizedHeader;
|
|
701
695
|
}
|
|
702
696
|
|
|
703
697
|
const newUpdate = {
|
|
@@ -769,22 +763,24 @@ export function sumBits(bits: BitArray): number {
|
|
|
769
763
|
return bits.getTrueBitIndexes().length;
|
|
770
764
|
}
|
|
771
765
|
|
|
772
|
-
|
|
773
|
-
// in Gloas. So we can assume any types here are pre-gloas
|
|
774
|
-
export function blockToLightClientHeader(
|
|
775
|
-
fork: ForkName,
|
|
776
|
-
block: BeaconBlock<ForkPostAltair & ForkPreGloas>
|
|
777
|
-
): LightClientHeader {
|
|
778
|
-
const blockSlot = block.slot;
|
|
766
|
+
export function blockToLightClientHeader(fork: ForkName, block: BeaconBlock<ForkPostAltair>): LightClientHeader {
|
|
779
767
|
const beacon: phase0.BeaconBlockHeader = {
|
|
780
|
-
slot:
|
|
768
|
+
slot: block.slot,
|
|
781
769
|
proposerIndex: block.proposerIndex,
|
|
782
770
|
parentRoot: block.parentRoot,
|
|
783
771
|
stateRoot: block.stateRoot,
|
|
784
|
-
bodyRoot: (ssz[fork].BeaconBlockBody as SSZTypesFor<ForkPostAltair
|
|
785
|
-
block.body
|
|
786
|
-
),
|
|
772
|
+
bodyRoot: (ssz[fork].BeaconBlockBody as SSZTypesFor<ForkPostAltair, "BeaconBlockBody">).hashTreeRoot(block.body),
|
|
787
773
|
};
|
|
774
|
+
|
|
775
|
+
if (isForkPostGloas(fork)) {
|
|
776
|
+
const blockBody = block.body as BeaconBlockBody<ForkPostGloas>;
|
|
777
|
+
return {
|
|
778
|
+
beacon,
|
|
779
|
+
executionBlockHash: blockBody.signedExecutionPayloadBid.message.parentBlockHash,
|
|
780
|
+
executionBranch: getBlockBodyExecutionBlockHashProof(fork, blockBody),
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
|
|
788
784
|
if (ForkSeq[fork] >= ForkSeq.capella) {
|
|
789
785
|
const blockBody = block.body as BeaconBlockBody<ForkPostBellatrix & ForkPreGloas>;
|
|
790
786
|
const execution = executionPayloadToPayloadHeader(ForkSeq[fork], blockBody.executionPayload);
|
|
@@ -2,11 +2,13 @@ import {Tree} from "@chainsafe/persistent-merkle-tree";
|
|
|
2
2
|
import {
|
|
3
3
|
BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX,
|
|
4
4
|
CURRENT_SYNC_COMMITTEE_GINDEX_GLOAS,
|
|
5
|
+
EXECUTION_BLOCK_HASH_GINDEX_GLOAS,
|
|
5
6
|
FINALIZED_ROOT_GINDEX,
|
|
6
7
|
FINALIZED_ROOT_GINDEX_ELECTRA,
|
|
7
8
|
FINALIZED_ROOT_GINDEX_GLOAS,
|
|
8
9
|
ForkName,
|
|
9
10
|
ForkPostBellatrix,
|
|
11
|
+
ForkPostGloas,
|
|
10
12
|
NEXT_SYNC_COMMITTEE_GINDEX_GLOAS,
|
|
11
13
|
isForkPostElectra,
|
|
12
14
|
isForkPostGloas,
|
|
@@ -116,3 +118,11 @@ export function getBlockBodyExecutionHeaderProof(
|
|
|
116
118
|
const bodyView = (ssz[fork].BeaconBlockBody as SSZTypesFor<ForkPostBellatrix, "BeaconBlockBody">).toView(body);
|
|
117
119
|
return new Tree(bodyView.node).getSingleProof(BigInt(BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX));
|
|
118
120
|
}
|
|
121
|
+
|
|
122
|
+
export function getBlockBodyExecutionBlockHashProof(
|
|
123
|
+
fork: ForkPostGloas,
|
|
124
|
+
body: BeaconBlockBody<ForkPostGloas>
|
|
125
|
+
): Uint8Array[] {
|
|
126
|
+
const bodyView = (ssz[fork].BeaconBlockBody as SSZTypesFor<ForkPostGloas, "BeaconBlockBody">).toView(body);
|
|
127
|
+
return new Tree(bodyView.node).getSingleProof(BigInt(EXECUTION_BLOCK_HASH_GINDEX_GLOAS));
|
|
128
|
+
}
|
|
@@ -363,7 +363,7 @@ export class AggregatedAttestationPool {
|
|
|
363
363
|
stateEpoch,
|
|
364
364
|
rootCache,
|
|
365
365
|
gloasState?.executionPayloadAvailability ?? null,
|
|
366
|
-
gloasState?.
|
|
366
|
+
gloasState?.latestBlockHeader.slot ?? null
|
|
367
367
|
);
|
|
368
368
|
|
|
369
369
|
const weight =
|
|
@@ -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(
|