@lodestar/beacon-node 1.36.0-dev.793f92c091 → 1.36.0-dev.797fa46c1b
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 +41 -22
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/config/constants.d.ts +4 -2
- package/lib/api/impl/config/constants.d.ts.map +1 -1
- package/lib/api/impl/config/constants.js +6 -3
- package/lib/api/impl/config/constants.js.map +1 -1
- package/lib/api/impl/lodestar/index.d.ts +5 -0
- package/lib/api/impl/lodestar/index.d.ts.map +1 -1
- package/lib/api/impl/lodestar/index.js +35 -10
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/node/utils.js +1 -1
- package/lib/api/impl/node/utils.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +2 -2
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +9 -0
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +24 -0
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +7 -0
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js +31 -5
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
- package/lib/chain/beaconProposerCache.d.ts +3 -0
- package/lib/chain/beaconProposerCache.d.ts.map +1 -1
- package/lib/chain/beaconProposerCache.js +4 -6
- package/lib/chain/beaconProposerCache.js.map +1 -1
- package/lib/chain/chain.d.ts +5 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +34 -18
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/dataColumnSidecarError.d.ts +7 -0
- package/lib/chain/errors/dataColumnSidecarError.d.ts.map +1 -1
- package/lib/chain/errors/dataColumnSidecarError.js +1 -0
- package/lib/chain/errors/dataColumnSidecarError.js.map +1 -1
- package/lib/chain/errors/voluntaryExitError.d.ts +16 -2
- package/lib/chain/errors/voluntaryExitError.d.ts.map +1 -1
- package/lib/chain/errors/voluntaryExitError.js +22 -1
- package/lib/chain/errors/voluntaryExitError.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts +9 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +109 -4
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -0
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/lightClient/index.d.ts +3 -0
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +24 -13
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/opPools/syncContributionAndProofPool.d.ts +3 -1
- package/lib/chain/opPools/syncContributionAndProofPool.d.ts.map +1 -1
- package/lib/chain/opPools/syncContributionAndProofPool.js +4 -3
- package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
- package/lib/chain/options.d.ts +0 -2
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +0 -1
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/stateCache/datastore/db.d.ts +12 -0
- package/lib/chain/stateCache/datastore/db.d.ts.map +1 -1
- package/lib/chain/stateCache/datastore/db.js +70 -0
- package/lib/chain/stateCache/datastore/db.js.map +1 -1
- package/lib/chain/stateCache/datastore/file.d.ts +1 -0
- package/lib/chain/stateCache/datastore/file.d.ts.map +1 -1
- package/lib/chain/stateCache/datastore/file.js +7 -0
- package/lib/chain/stateCache/datastore/file.js.map +1 -1
- package/lib/chain/stateCache/datastore/types.d.ts +1 -0
- package/lib/chain/stateCache/datastore/types.d.ts.map +1 -1
- package/lib/chain/validation/attestation.d.ts.map +1 -1
- package/lib/chain/validation/attestation.js +6 -7
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +1 -2
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.js +14 -3
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/chain/validation/lightClientOptimisticUpdate.d.ts.map +1 -1
- package/lib/chain/validation/lightClientOptimisticUpdate.js +1 -2
- package/lib/chain/validation/lightClientOptimisticUpdate.js.map +1 -1
- package/lib/chain/validation/voluntaryExit.d.ts.map +1 -1
- package/lib/chain/validation/voluntaryExit.js +5 -4
- package/lib/chain/validation/voluntaryExit.js.map +1 -1
- package/lib/constants/constants.d.ts +0 -5
- package/lib/constants/constants.d.ts.map +1 -1
- package/lib/constants/constants.js +0 -5
- package/lib/constants/constants.js.map +1 -1
- package/lib/constants/network.d.ts +0 -14
- package/lib/constants/network.d.ts.map +1 -1
- package/lib/constants/network.js +0 -15
- package/lib/constants/network.js.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +11 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +19 -1
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/core/networkCore.d.ts.map +1 -1
- package/lib/network/core/networkCore.js +5 -1
- package/lib/network/core/networkCore.js.map +1 -1
- package/lib/network/core/networkCoreWorker.js +2 -7
- package/lib/network/core/networkCoreWorker.js.map +1 -1
- package/lib/network/discv5/utils.d.ts.map +1 -1
- package/lib/network/discv5/utils.js +1 -2
- package/lib/network/discv5/utils.js.map +1 -1
- package/lib/network/discv5/worker.js +2 -7
- package/lib/network/discv5/worker.js.map +1 -1
- package/lib/network/gossip/encoding.js +1 -1
- 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 +1 -7
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/gossip/snappy_bun.d.ts +3 -0
- package/lib/network/gossip/snappy_bun.d.ts.map +1 -0
- package/lib/network/gossip/snappy_bun.js +3 -0
- package/lib/network/gossip/snappy_bun.js.map +1 -0
- package/lib/network/metadata.d.ts +1 -1
- package/lib/network/metadata.d.ts.map +1 -1
- package/lib/network/metadata.js +1 -0
- package/lib/network/metadata.js.map +1 -1
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +1 -0
- package/lib/network/network.js.map +1 -1
- package/lib/network/options.d.ts +0 -1
- package/lib/network/options.d.ts.map +1 -1
- package/lib/network/options.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +14 -8
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +3 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js +5 -5
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.js +4 -4
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.js.map +1 -1
- package/lib/network/subnets/attnetsService.d.ts +1 -1
- package/lib/network/subnets/attnetsService.js +6 -6
- package/lib/network/subnets/attnetsService.js.map +1 -1
- package/lib/network/subnets/util.d.ts +3 -2
- package/lib/network/subnets/util.d.ts.map +1 -1
- package/lib/network/subnets/util.js +6 -6
- package/lib/network/subnets/util.js.map +1 -1
- package/lib/node/nodejs.d.ts +2 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +2 -1
- package/lib/node/nodejs.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +2 -1
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/utils/remoteSyncType.d.ts +2 -1
- package/lib/sync/utils/remoteSyncType.d.ts.map +1 -1
- package/lib/sync/utils/remoteSyncType.js +19 -4
- package/lib/sync/utils/remoteSyncType.js.map +1 -1
- package/lib/util/blobs.d.ts +1 -1
- package/lib/util/blobs.d.ts.map +1 -1
- package/lib/util/blobs.js +53 -20
- package/lib/util/blobs.js.map +1 -1
- package/lib/util/clock.d.ts.map +1 -1
- package/lib/util/clock.js +3 -4
- package/lib/util/clock.js.map +1 -1
- package/lib/util/profile.d.ts +6 -4
- package/lib/util/profile.d.ts.map +1 -1
- package/lib/util/profile.js +40 -3
- package/lib/util/profile.js.map +1 -1
- package/lib/util/sszBytes.d.ts +2 -0
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +25 -0
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +31 -24
- package/src/api/impl/beacon/blocks/index.ts +47 -25
- package/src/api/impl/config/constants.ts +10 -4
- package/src/api/impl/lodestar/index.ts +42 -10
- package/src/api/impl/node/utils.ts +1 -1
- package/src/api/impl/validator/index.ts +5 -2
- package/src/chain/archiveStore/archiveStore.ts +27 -0
- package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +32 -5
- package/src/chain/beaconProposerCache.ts +4 -8
- package/src/chain/chain.ts +50 -25
- package/src/chain/errors/dataColumnSidecarError.ts +8 -0
- package/src/chain/errors/voluntaryExitError.ts +30 -2
- package/src/chain/forkChoice/index.ts +178 -2
- package/src/chain/interface.ts +2 -0
- package/src/chain/lightClient/index.ts +26 -12
- package/src/chain/opPools/syncContributionAndProofPool.ts +3 -2
- package/src/chain/options.ts +0 -3
- package/src/chain/stateCache/datastore/db.ts +89 -1
- package/src/chain/stateCache/datastore/file.ts +8 -0
- package/src/chain/stateCache/datastore/types.ts +1 -0
- package/src/chain/validation/attestation.ts +6 -7
- package/src/chain/validation/block.ts +1 -2
- package/src/chain/validation/dataColumnSidecar.ts +21 -4
- package/src/chain/validation/lightClientOptimisticUpdate.ts +3 -2
- package/src/chain/validation/voluntaryExit.ts +14 -4
- package/src/constants/constants.ts +0 -6
- package/src/constants/network.ts +0 -19
- package/src/index.ts +2 -0
- package/src/metrics/metrics/lodestar.ts +22 -1
- package/src/network/core/networkCore.ts +5 -1
- package/src/network/core/networkCoreWorker.ts +2 -7
- package/src/network/discv5/utils.ts +1 -2
- package/src/network/discv5/worker.ts +2 -7
- package/src/network/gossip/encoding.ts +1 -1
- package/src/network/gossip/gossipsub.ts +1 -10
- package/src/network/gossip/snappy_bun.ts +2 -0
- package/src/network/metadata.ts +3 -1
- package/src/network/network.ts +1 -0
- package/src/network/options.ts +0 -1
- package/src/network/processor/gossipHandlers.ts +16 -7
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +3 -1
- package/src/network/reqresp/handlers/blobSidecarsByRange.ts +6 -6
- package/src/network/reqresp/handlers/blobSidecarsByRoot.ts +5 -5
- package/src/network/subnets/attnetsService.ts +6 -6
- package/src/network/subnets/util.ts +12 -12
- package/src/node/nodejs.ts +3 -0
- package/src/sync/range/range.ts +2 -1
- package/src/sync/utils/remoteSyncType.ts +23 -4
- package/src/util/blobs.ts +64 -20
- package/src/util/clock.ts +3 -4
- package/src/util/profile.ts +45 -3
- package/src/util/sszBytes.ts +30 -0
package/src/network/metadata.ts
CHANGED
|
@@ -126,7 +126,7 @@ export class MetadataController {
|
|
|
126
126
|
* 2. Network MUST call this method on fork transition.
|
|
127
127
|
* Current Clock implementation ensures no race conditions, epoch is correct if re-fetched
|
|
128
128
|
*/
|
|
129
|
-
updateEth2Field(epoch: Epoch):
|
|
129
|
+
updateEth2Field(epoch: Epoch): phase0.ENRForkID {
|
|
130
130
|
const config = this.networkConfig.config;
|
|
131
131
|
const enrForkId = getENRForkID(config, epoch);
|
|
132
132
|
const {forkDigest, nextForkVersion, nextForkEpoch} = enrForkId;
|
|
@@ -143,6 +143,8 @@ export class MetadataController {
|
|
|
143
143
|
: ssz.ForkDigest.defaultValue();
|
|
144
144
|
this.onSetValue(ENRKey.nfd, nextForkDigest);
|
|
145
145
|
this.logger.debug("Updated nfd field in ENR", {nextForkDigest: toHex(nextForkDigest)});
|
|
146
|
+
|
|
147
|
+
return enrForkId;
|
|
146
148
|
}
|
|
147
149
|
}
|
|
148
150
|
|
package/src/network/network.ts
CHANGED
|
@@ -236,6 +236,7 @@ export class Network implements INetwork {
|
|
|
236
236
|
this.chain.emitter.off(routes.events.EventType.lightClientOptimisticUpdate, this.onLightClientOptimisticUpdate);
|
|
237
237
|
this.chain.emitter.off(ChainEvent.updateTargetCustodyGroupCount, this.onTargetGroupCountUpdated);
|
|
238
238
|
this.chain.emitter.off(ChainEvent.publishDataColumns, this.onPublishDataColumns);
|
|
239
|
+
this.chain.emitter.off(ChainEvent.publishBlobSidecars, this.onPublishBlobSidecars);
|
|
239
240
|
this.chain.emitter.off(ChainEvent.updateStatus, this.onUpdateStatus);
|
|
240
241
|
await this.core.close();
|
|
241
242
|
|
package/src/network/options.ts
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
BlockError,
|
|
40
40
|
BlockErrorCode,
|
|
41
41
|
BlockGossipError,
|
|
42
|
+
DataColumnSidecarErrorCode,
|
|
42
43
|
DataColumnSidecarGossipError,
|
|
43
44
|
GossipAction,
|
|
44
45
|
GossipActionError,
|
|
@@ -304,7 +305,11 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
304
305
|
...blockInput.getLogMeta(),
|
|
305
306
|
index: dataColumnSidecar.index,
|
|
306
307
|
});
|
|
307
|
-
|
|
308
|
+
throw new DataColumnSidecarGossipError(GossipAction.IGNORE, {
|
|
309
|
+
code: DataColumnSidecarErrorCode.ALREADY_KNOWN,
|
|
310
|
+
columnIdx: dataColumnSidecar.index,
|
|
311
|
+
slot,
|
|
312
|
+
});
|
|
308
313
|
}
|
|
309
314
|
}
|
|
310
315
|
|
|
@@ -556,6 +561,16 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
556
561
|
metrics?.dataColumns.elapsedTimeTillReceived.observe({receivedOrder: receivedColumns}, delaySec);
|
|
557
562
|
break;
|
|
558
563
|
}
|
|
564
|
+
|
|
565
|
+
if (!blockInput.hasAllData()) {
|
|
566
|
+
// immediately attempt fetch of data columns from execution engine
|
|
567
|
+
chain.getBlobsTracker.triggerGetBlobs(blockInput);
|
|
568
|
+
// if we've received at least half of the columns, trigger reconstruction of the rest
|
|
569
|
+
if (blockInput.columnCount >= NUMBER_OF_COLUMNS / 2) {
|
|
570
|
+
chain.columnReconstructionTracker.triggerColumnReconstruction(blockInput);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
559
574
|
if (!blockInput.hasBlockAndAllData()) {
|
|
560
575
|
const cutoffTimeMs = getCutoffTimeMs(chain, dataColumnSlot, BLOCK_AVAILABILITY_CUTOFF_MS);
|
|
561
576
|
chain.logger.debug("Received gossip data column, waiting for full data availability", {
|
|
@@ -578,12 +593,6 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
578
593
|
source: BlockInputSource.gossip,
|
|
579
594
|
});
|
|
580
595
|
});
|
|
581
|
-
// immediately attempt fetch of data columns from execution engine
|
|
582
|
-
chain.getBlobsTracker.triggerGetBlobs(blockInput);
|
|
583
|
-
// if we've received at least half of the columns, trigger reconstruction of the rest
|
|
584
|
-
if (blockInput.columnCount >= NUMBER_OF_COLUMNS / 2) {
|
|
585
|
-
chain.columnReconstructionTracker.triggerColumnReconstruction(blockInput);
|
|
586
|
-
}
|
|
587
596
|
}
|
|
588
597
|
},
|
|
589
598
|
|
|
@@ -19,7 +19,9 @@ export async function* onBeaconBlocksByRange(
|
|
|
19
19
|
|
|
20
20
|
const finalized = db.blockArchive;
|
|
21
21
|
const unfinalized = db.block;
|
|
22
|
-
|
|
22
|
+
// in the case of initializing from a non-finalized state, we don't have the finalized block so this api does not work
|
|
23
|
+
// chain.forkChoice.getFinalizeBlock().slot
|
|
24
|
+
const finalizedSlot = chain.forkChoice.getFinalizedCheckpointSlot();
|
|
23
25
|
|
|
24
26
|
// Finalized range of blocks
|
|
25
27
|
if (startSlot <= finalizedSlot) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {ChainConfig} from "@lodestar/config";
|
|
2
|
-
import {
|
|
2
|
+
import {BLOB_SIDECAR_FIXED_SIZE, GENESIS_SLOT} from "@lodestar/params";
|
|
3
3
|
import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp";
|
|
4
4
|
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
5
5
|
import {Slot, deneb} from "@lodestar/types";
|
|
@@ -71,17 +71,17 @@ export function* iterateBlobBytesFromWrapper(
|
|
|
71
71
|
blockSlot: Slot
|
|
72
72
|
): Iterable<ResponseOutgoing> {
|
|
73
73
|
const allBlobSideCarsBytes = blobSideCarsBytesWrapped.slice(BLOB_SIDECARS_IN_WRAPPER_INDEX);
|
|
74
|
-
const blobsLen = allBlobSideCarsBytes.length /
|
|
74
|
+
const blobsLen = allBlobSideCarsBytes.length / BLOB_SIDECAR_FIXED_SIZE;
|
|
75
75
|
|
|
76
76
|
for (let index = 0; index < blobsLen; index++) {
|
|
77
77
|
const blobSideCarBytes = allBlobSideCarsBytes.slice(
|
|
78
|
-
index *
|
|
79
|
-
(index + 1) *
|
|
78
|
+
index * BLOB_SIDECAR_FIXED_SIZE,
|
|
79
|
+
(index + 1) * BLOB_SIDECAR_FIXED_SIZE
|
|
80
80
|
);
|
|
81
|
-
if (blobSideCarBytes.length !==
|
|
81
|
+
if (blobSideCarBytes.length !== BLOB_SIDECAR_FIXED_SIZE) {
|
|
82
82
|
throw new ResponseError(
|
|
83
83
|
RespStatus.SERVER_ERROR,
|
|
84
|
-
`Invalid blobSidecar index=${index} bytes length=${blobSideCarBytes.length} expected=${
|
|
84
|
+
`Invalid blobSidecar index=${index} bytes length=${blobSideCarBytes.length} expected=${BLOB_SIDECAR_FIXED_SIZE} for slot ${blockSlot} blobsLen=${blobsLen}`
|
|
85
85
|
);
|
|
86
86
|
}
|
|
87
87
|
yield {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {BLOB_SIDECAR_FIXED_SIZE} from "@lodestar/params";
|
|
2
2
|
import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp";
|
|
3
3
|
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
4
4
|
import {RootHex} from "@lodestar/types";
|
|
@@ -45,12 +45,12 @@ export async function* onBlobSidecarsByRoot(
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const blobSidecarBytes = lastFetchedSideCars.bytes.slice(
|
|
48
|
-
index *
|
|
49
|
-
(index + 1) *
|
|
48
|
+
index * BLOB_SIDECAR_FIXED_SIZE,
|
|
49
|
+
(index + 1) * BLOB_SIDECAR_FIXED_SIZE
|
|
50
50
|
);
|
|
51
|
-
if (blobSidecarBytes.length !==
|
|
51
|
+
if (blobSidecarBytes.length !== BLOB_SIDECAR_FIXED_SIZE) {
|
|
52
52
|
throw Error(
|
|
53
|
-
`Inconsistent state, blobSidecar blockRoot=${blockRootHex} index=${index} blobSidecarBytes=${blobSidecarBytes.length} expected=${
|
|
53
|
+
`Inconsistent state, blobSidecar blockRoot=${blockRootHex} index=${index} blobSidecarBytes=${blobSidecarBytes.length} expected=${BLOB_SIDECAR_FIXED_SIZE}`
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {BeaconConfig, ForkBoundary} from "@lodestar/config";
|
|
2
|
-
import {ATTESTATION_SUBNET_COUNT,
|
|
2
|
+
import {ATTESTATION_SUBNET_COUNT, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
3
3
|
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
4
4
|
import {Epoch, Slot, SubnetID, ssz} from "@lodestar/types";
|
|
5
5
|
import {Logger, MapDef} from "@lodestar/utils";
|
|
@@ -92,8 +92,8 @@ export class AttnetsService implements IAttnetsService {
|
|
|
92
92
|
const shortLivedSubnets = this.committeeSubnets.getActiveTtl(this.clock.currentSlot);
|
|
93
93
|
|
|
94
94
|
const longLivedSubscriptionsToSlot =
|
|
95
|
-
(Math.floor(this.clock.currentEpoch /
|
|
96
|
-
|
|
95
|
+
(Math.floor(this.clock.currentEpoch / this.config.EPOCHS_PER_SUBNET_SUBSCRIPTION) + 1) *
|
|
96
|
+
this.config.EPOCHS_PER_SUBNET_SUBSCRIPTION *
|
|
97
97
|
SLOTS_PER_EPOCH;
|
|
98
98
|
const longLivedSubnets = Array.from(this.longLivedSubscriptions).map((subnet) => ({
|
|
99
99
|
subnet,
|
|
@@ -234,11 +234,11 @@ export class AttnetsService implements IAttnetsService {
|
|
|
234
234
|
|
|
235
235
|
/**
|
|
236
236
|
* Run per epoch, clean-up operations that are not urgent
|
|
237
|
-
* Subscribe to new random subnets every
|
|
237
|
+
* Subscribe to new random subnets every EPOCHS_PER_SUBNET_SUBSCRIPTION epochs
|
|
238
238
|
*/
|
|
239
239
|
private onEpoch = (epoch: Epoch): void => {
|
|
240
240
|
try {
|
|
241
|
-
if (epoch %
|
|
241
|
+
if (epoch % this.config.EPOCHS_PER_SUBNET_SUBSCRIPTION === 0) {
|
|
242
242
|
this.recomputeLongLivedSubnets();
|
|
243
243
|
}
|
|
244
244
|
} catch (e) {
|
|
@@ -253,7 +253,7 @@ export class AttnetsService implements IAttnetsService {
|
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
const oldSubnets = this.longLivedSubscriptions;
|
|
256
|
-
const newSubnets = computeSubscribedSubnet(this.nodeId, this.clock.currentEpoch);
|
|
256
|
+
const newSubnets = computeSubscribedSubnet(this.config, this.nodeId, this.clock.currentEpoch);
|
|
257
257
|
this.logger.verbose("Recomputing long-lived subscriptions", {
|
|
258
258
|
epoch: this.clock.currentEpoch,
|
|
259
259
|
oldSubnets: Array.from(oldSubnets).join(","),
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import {digest} from "@chainsafe/as-sha256";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
ATTESTATION_SUBNET_PREFIX_BITS,
|
|
5
|
-
EPOCHS_PER_SUBNET_SUBSCRIPTION,
|
|
6
|
-
NODE_ID_BITS,
|
|
7
|
-
SUBNETS_PER_NODE,
|
|
8
|
-
} from "@lodestar/params";
|
|
2
|
+
import {ChainConfig} from "@lodestar/config";
|
|
3
|
+
import {ATTESTATION_SUBNET_COUNT, ATTESTATION_SUBNET_PREFIX_BITS, NODE_ID_BITS} from "@lodestar/params";
|
|
9
4
|
import {computeShuffledIndex} from "@lodestar/state-transition";
|
|
10
5
|
import {Epoch, ssz} from "@lodestar/types";
|
|
11
6
|
import {NodeId} from "./interface.js";
|
|
@@ -13,10 +8,10 @@ import {NodeId} from "./interface.js";
|
|
|
13
8
|
/**
|
|
14
9
|
* Spec https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/p2p-interface.md
|
|
15
10
|
*/
|
|
16
|
-
export function computeSubscribedSubnet(nodeId: NodeId, epoch: Epoch): number[] {
|
|
11
|
+
export function computeSubscribedSubnet(config: ChainConfig, nodeId: NodeId, epoch: Epoch): number[] {
|
|
17
12
|
const subnets: number[] = [];
|
|
18
|
-
for (let index = 0; index < SUBNETS_PER_NODE; index++) {
|
|
19
|
-
subnets.push(computeSubscribedSubnetByIndex(nodeId, epoch, index));
|
|
13
|
+
for (let index = 0; index < config.SUBNETS_PER_NODE; index++) {
|
|
14
|
+
subnets.push(computeSubscribedSubnetByIndex(config, nodeId, epoch, index));
|
|
20
15
|
}
|
|
21
16
|
return subnets;
|
|
22
17
|
}
|
|
@@ -24,11 +19,16 @@ export function computeSubscribedSubnet(nodeId: NodeId, epoch: Epoch): number[]
|
|
|
24
19
|
/**
|
|
25
20
|
* Spec https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/p2p-interface.md
|
|
26
21
|
*/
|
|
27
|
-
export function computeSubscribedSubnetByIndex(
|
|
22
|
+
export function computeSubscribedSubnetByIndex(
|
|
23
|
+
config: ChainConfig,
|
|
24
|
+
nodeId: NodeId,
|
|
25
|
+
epoch: Epoch,
|
|
26
|
+
index: number
|
|
27
|
+
): number {
|
|
28
28
|
const nodeIdPrefix = getNodeIdPrefix(nodeId);
|
|
29
29
|
const nodeOffset = getNodeOffset(nodeId);
|
|
30
30
|
const permutationSeed = digest(
|
|
31
|
-
ssz.UintNum64.serialize(Math.floor((epoch + nodeOffset) / EPOCHS_PER_SUBNET_SUBSCRIPTION))
|
|
31
|
+
ssz.UintNum64.serialize(Math.floor((epoch + nodeOffset) / config.EPOCHS_PER_SUBNET_SUBSCRIPTION))
|
|
32
32
|
);
|
|
33
33
|
const permutatedPrefix = computeShuffledIndex(nodeIdPrefix, 1 << ATTESTATION_SUBNET_PREFIX_BITS, permutationSeed);
|
|
34
34
|
return (permutatedPrefix + index) % ATTESTATION_SUBNET_COUNT;
|
package/src/node/nodejs.ts
CHANGED
|
@@ -53,6 +53,7 @@ export type BeaconNodeInitModules = {
|
|
|
53
53
|
dataDir: string;
|
|
54
54
|
peerStoreDir?: string;
|
|
55
55
|
anchorState: BeaconStateAllForks;
|
|
56
|
+
isAnchorStateFinalized: boolean;
|
|
56
57
|
wsCheckpoint?: phase0.Checkpoint;
|
|
57
58
|
metricsRegistries?: Registry[];
|
|
58
59
|
};
|
|
@@ -154,6 +155,7 @@ export class BeaconNode {
|
|
|
154
155
|
dataDir,
|
|
155
156
|
peerStoreDir,
|
|
156
157
|
anchorState,
|
|
158
|
+
isAnchorStateFinalized,
|
|
157
159
|
wsCheckpoint,
|
|
158
160
|
metricsRegistries = [],
|
|
159
161
|
}: BeaconNodeInitModules): Promise<T> {
|
|
@@ -217,6 +219,7 @@ export class BeaconNode {
|
|
|
217
219
|
metrics,
|
|
218
220
|
validatorMonitor,
|
|
219
221
|
anchorState,
|
|
222
|
+
isAnchorStateFinalized,
|
|
220
223
|
eth1: initializeEth1ForBlockProduction(opts.eth1, {
|
|
221
224
|
config,
|
|
222
225
|
db,
|
package/src/sync/range/range.ts
CHANGED
|
@@ -114,13 +114,14 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
114
114
|
*/
|
|
115
115
|
addPeer(peerId: PeerIdStr, localStatus: Status, peerStatus: Status): void {
|
|
116
116
|
// Compute if we should do a Finalized or Head sync with this peer
|
|
117
|
-
const {syncType, startEpoch, target} = getRangeSyncTarget(localStatus, peerStatus, this.chain
|
|
117
|
+
const {syncType, startEpoch, target} = getRangeSyncTarget(localStatus, peerStatus, this.chain);
|
|
118
118
|
this.logger.debug("Sync peer joined", {
|
|
119
119
|
peer: peerId,
|
|
120
120
|
syncType,
|
|
121
121
|
startEpoch,
|
|
122
122
|
targetSlot: target.slot,
|
|
123
123
|
targetRoot: toRootHex(target.root),
|
|
124
|
+
localHeadSlot: localStatus.headSlot,
|
|
124
125
|
earliestAvailableSlot: (peerStatus as fulu.Status).earliestAvailableSlot ?? Infinity,
|
|
125
126
|
});
|
|
126
127
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {IForkChoice} from "@lodestar/fork-choice";
|
|
2
2
|
import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
3
3
|
import {Slot, Status} from "@lodestar/types";
|
|
4
|
+
import {IBeaconChain} from "../../chain/interface.ts";
|
|
4
5
|
import {ChainTarget} from "../range/utils/index.js";
|
|
5
6
|
|
|
6
7
|
/** The type of peer relative to our current state */
|
|
@@ -103,8 +104,11 @@ export function getRangeSyncType(local: Status, remote: Status, forkChoice: IFor
|
|
|
103
104
|
export function getRangeSyncTarget(
|
|
104
105
|
local: Status,
|
|
105
106
|
remote: Status,
|
|
106
|
-
|
|
107
|
+
chain: IBeaconChain
|
|
107
108
|
): {syncType: RangeSyncType; startEpoch: Slot; target: ChainTarget} {
|
|
109
|
+
const forkChoice = chain.forkChoice;
|
|
110
|
+
|
|
111
|
+
// finalized sync
|
|
108
112
|
if (remote.finalizedEpoch > local.finalizedEpoch && !forkChoice.hasBlock(remote.finalizedRoot)) {
|
|
109
113
|
return {
|
|
110
114
|
// If RangeSyncType.Finalized, the range of blocks fetchable from startEpoch and target must allow to switch
|
|
@@ -131,11 +135,26 @@ export function getRangeSyncTarget(
|
|
|
131
135
|
},
|
|
132
136
|
};
|
|
133
137
|
}
|
|
138
|
+
|
|
139
|
+
// we don't want to sync from epoch < minEpoch
|
|
140
|
+
// if we boot from an unfinalized checkpoint state, we don't want to sync before anchorStateLatestBlockSlot
|
|
141
|
+
// if we boot from a finalized checkpoint state, anchorStateLatestBlockSlot is trusted and we also don't want to sync before it
|
|
142
|
+
const minEpoch = Math.max(remote.finalizedEpoch, computeEpochAtSlot(chain.anchorStateLatestBlockSlot));
|
|
143
|
+
|
|
144
|
+
// head sync
|
|
134
145
|
return {
|
|
135
146
|
syncType: RangeSyncType.Head,
|
|
136
|
-
// The new peer has the same finalized
|
|
137
|
-
// earlier finalized chain from reaching here
|
|
138
|
-
|
|
147
|
+
// The new peer has the same finalized `remote.finalizedEpoch == local.finalizedEpoch` since
|
|
148
|
+
// previous filters should prevent a peer with an earlier finalized chain from reaching here.
|
|
149
|
+
//
|
|
150
|
+
// By default and during stable network conditions, the head sync always starts from
|
|
151
|
+
// the finalized epoch (even though it's the head sync) because finalized epoch is < local head.
|
|
152
|
+
// This is to prevent the issue noted here https://github.com/ChainSafe/lodestar/pull/7509#discussion_r1984353063.
|
|
153
|
+
//
|
|
154
|
+
// During non-finality of the network, when starting from an unfinalized checkpoint state, we don't want
|
|
155
|
+
// to sync before anchorStateLatestBlockSlot as finalized epoch is too far away. Local head will also be
|
|
156
|
+
// the same to that value at startup, the head sync always starts from anchorStateLatestBlockSlot in this case.
|
|
157
|
+
startEpoch: Math.min(computeEpochAtSlot(local.headSlot), minEpoch),
|
|
139
158
|
target: {
|
|
140
159
|
slot: remote.headSlot,
|
|
141
160
|
root: remote.headRoot,
|
package/src/util/blobs.ts
CHANGED
|
@@ -149,41 +149,85 @@ export async function dataColumnMatrixRecovery(
|
|
|
149
149
|
* Reconstruct blobs from a set of data columns, at least 50%+ of all the columns
|
|
150
150
|
* must be provided to allow to reconstruct the full data matrix
|
|
151
151
|
*/
|
|
152
|
-
export async function reconstructBlobs(sidecars: fulu.DataColumnSidecars): Promise<deneb.Blobs> {
|
|
152
|
+
export async function reconstructBlobs(sidecars: fulu.DataColumnSidecars, indices?: number[]): Promise<deneb.Blobs> {
|
|
153
153
|
if (sidecars.length < NUMBER_OF_COLUMNS / 2) {
|
|
154
154
|
throw Error(
|
|
155
155
|
`Expected at least ${NUMBER_OF_COLUMNS / 2} data columns to reconstruct blobs, received ${sidecars.length}`
|
|
156
156
|
);
|
|
157
157
|
}
|
|
158
|
+
const blobCount = sidecars[0].column.length;
|
|
158
159
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
// Full columns, no need to recover
|
|
163
|
-
fullSidecars = sidecars;
|
|
164
|
-
} else {
|
|
165
|
-
const sidecarsByIndex = new Map<number, fulu.DataColumnSidecar>(sidecars.map((sc) => [sc.index, sc]));
|
|
166
|
-
const recoveredSidecars = await dataColumnMatrixRecovery(sidecarsByIndex);
|
|
167
|
-
if (recoveredSidecars === null) {
|
|
168
|
-
// Should not happen because we check the column count above
|
|
169
|
-
throw Error("Failed to reconstruct the full data matrix");
|
|
160
|
+
for (const index of indices ?? []) {
|
|
161
|
+
if (index < 0 || index >= blobCount) {
|
|
162
|
+
throw Error(`Invalid blob index ${index}, must be between 0 and ${blobCount - 1}`);
|
|
170
163
|
}
|
|
171
|
-
|
|
164
|
+
}
|
|
165
|
+
const indicesToReconstruct = indices ?? Array.from({length: blobCount}, (_, i) => i);
|
|
166
|
+
|
|
167
|
+
const recoveredCells = await recoverBlobCells(sidecars, indicesToReconstruct);
|
|
168
|
+
if (recoveredCells === null) {
|
|
169
|
+
// Should not happen because we check the column count above
|
|
170
|
+
throw Error("Failed to recover cells to reconstruct blobs");
|
|
172
171
|
}
|
|
173
172
|
|
|
174
|
-
const
|
|
175
|
-
const blobs: deneb.Blobs = new Array(blobCount);
|
|
173
|
+
const blobs: deneb.Blobs = new Array(indicesToReconstruct.length);
|
|
176
174
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
175
|
+
for (let i = 0; i < indicesToReconstruct.length; i++) {
|
|
176
|
+
const blobIndex = indicesToReconstruct[i];
|
|
177
|
+
const cells = recoveredCells.get(blobIndex);
|
|
178
|
+
if (!cells) {
|
|
179
|
+
throw Error(`Failed to get recovered cells for blob index ${blobIndex}`);
|
|
180
|
+
}
|
|
181
|
+
blobs[i] = cellsToBlob(cells);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
return blobs;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Recover cells for specific blob indices from a set of data columns
|
|
189
|
+
*/
|
|
190
|
+
async function recoverBlobCells(
|
|
191
|
+
partialSidecars: fulu.DataColumnSidecar[],
|
|
192
|
+
blobIndices: number[]
|
|
193
|
+
): Promise<Map<number, fulu.Cell[]> | null> {
|
|
194
|
+
const columnCount = partialSidecars.length;
|
|
195
|
+
if (columnCount < NUMBER_OF_COLUMNS / 2) {
|
|
196
|
+
// We don't have enough columns to recover
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const recoveredCells = new Map<number, fulu.Cell[]>();
|
|
201
|
+
// Sort data columns by index in ascending order
|
|
202
|
+
const partialSidecarsSorted = partialSidecars.slice().sort((a, b) => a.index - b.index);
|
|
203
|
+
|
|
204
|
+
if (columnCount === NUMBER_OF_COLUMNS) {
|
|
205
|
+
// Full columns, no need to recover
|
|
206
|
+
for (const blobIndex of blobIndices) {
|
|
207
|
+
// 128 cells that make up one "extended blob" row
|
|
208
|
+
const cells = partialSidecarsSorted.map((col) => col.column[blobIndex]);
|
|
209
|
+
recoveredCells.set(blobIndex, cells);
|
|
210
|
+
}
|
|
211
|
+
return recoveredCells;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
await Promise.all(
|
|
215
|
+
blobIndices.map(async (blobIndex) => {
|
|
216
|
+
const cellIndices: number[] = [];
|
|
217
|
+
const cells: fulu.Cell[] = [];
|
|
218
|
+
for (const dataColumn of partialSidecarsSorted) {
|
|
219
|
+
cellIndices.push(dataColumn.index);
|
|
220
|
+
cells.push(dataColumn.column[blobIndex]);
|
|
221
|
+
}
|
|
222
|
+
// Recover cells for this specific blob row
|
|
223
|
+
const recovered = await kzg.asyncRecoverCellsAndKzgProofs(cellIndices, cells);
|
|
224
|
+
recoveredCells.set(blobIndex, recovered.cells);
|
|
225
|
+
})
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
return recoveredCells;
|
|
229
|
+
}
|
|
230
|
+
|
|
187
231
|
/**
|
|
188
232
|
* Concatenate the systematic half (columns 0‑63) of a row of cells into
|
|
189
233
|
* the original 131072 byte blob. The parity half (64‑127) is ignored as
|
package/src/util/clock.ts
CHANGED
|
@@ -4,7 +4,6 @@ import {ChainForkConfig} from "@lodestar/config";
|
|
|
4
4
|
import {computeEpochAtSlot, computeTimeAtSlot, getCurrentSlot} from "@lodestar/state-transition";
|
|
5
5
|
import type {Epoch, Slot} from "@lodestar/types";
|
|
6
6
|
import {ErrorAborted} from "@lodestar/utils";
|
|
7
|
-
import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../constants/constants.js";
|
|
8
7
|
|
|
9
8
|
export enum ClockEvent {
|
|
10
9
|
/**
|
|
@@ -101,7 +100,7 @@ export class Clock extends EventEmitter implements IClock {
|
|
|
101
100
|
get currentSlotWithGossipDisparity(): Slot {
|
|
102
101
|
const currentSlot = this.currentSlot;
|
|
103
102
|
const nextSlotTime = computeTimeAtSlot(this.config, currentSlot + 1, this.genesisTime) * 1000;
|
|
104
|
-
return nextSlotTime - Date.now() < MAXIMUM_GOSSIP_CLOCK_DISPARITY ? currentSlot + 1 : currentSlot;
|
|
103
|
+
return nextSlotTime - Date.now() < this.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY ? currentSlot + 1 : currentSlot;
|
|
105
104
|
}
|
|
106
105
|
|
|
107
106
|
get currentEpoch(): Epoch {
|
|
@@ -130,12 +129,12 @@ export class Clock extends EventEmitter implements IClock {
|
|
|
130
129
|
}
|
|
131
130
|
const nextSlotTime = computeTimeAtSlot(this.config, currentSlot + 1, this.genesisTime) * 1000;
|
|
132
131
|
// we're too close to next slot, accept next slot
|
|
133
|
-
if (nextSlotTime - Date.now() < MAXIMUM_GOSSIP_CLOCK_DISPARITY) {
|
|
132
|
+
if (nextSlotTime - Date.now() < this.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY) {
|
|
134
133
|
return slot === currentSlot + 1;
|
|
135
134
|
}
|
|
136
135
|
const currentSlotTime = computeTimeAtSlot(this.config, currentSlot, this.genesisTime) * 1000;
|
|
137
136
|
// we've just passed the current slot, accept previous slot
|
|
138
|
-
if (Date.now() - currentSlotTime < MAXIMUM_GOSSIP_CLOCK_DISPARITY) {
|
|
137
|
+
if (Date.now() - currentSlotTime < this.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY) {
|
|
139
138
|
return slot === currentSlot - 1;
|
|
140
139
|
}
|
|
141
140
|
return false;
|
package/src/util/profile.ts
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
import {sleep} from "@lodestar/utils";
|
|
2
4
|
|
|
5
|
+
export enum ProfileThread {
|
|
6
|
+
MAIN = "main",
|
|
7
|
+
NETWORK = "network",
|
|
8
|
+
DISC5 = "discv5",
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The time to take a Bun profile.
|
|
13
|
+
* If we increase this time it'll potentiall cause the app to crash.
|
|
14
|
+
* If we decrease this time, profile recorded will be fragmented and hard to analyze.
|
|
15
|
+
*/
|
|
16
|
+
const BUN_PROFILE_MS = 3 * 1000;
|
|
17
|
+
|
|
18
|
+
export async function profileThread(thread: ProfileThread, durationMs: number, dirpath: string): Promise<string> {
|
|
19
|
+
return globalThis.Bun ? profileBun(thread, durationMs) : profileNodeJS(thread, durationMs, dirpath);
|
|
20
|
+
}
|
|
21
|
+
|
|
3
22
|
/**
|
|
4
|
-
* Take
|
|
23
|
+
* Take `durationMs` profile of the current thread and return the persisted file path.
|
|
5
24
|
*/
|
|
6
|
-
|
|
25
|
+
async function profileNodeJS(thread: ProfileThread, durationMs: number, dirpath: string): Promise<string> {
|
|
7
26
|
const inspector = await import("node:inspector");
|
|
8
27
|
|
|
9
28
|
// due to some typing issues, not able to use promisify here
|
|
10
|
-
|
|
29
|
+
const profile = await new Promise<string>((resolve, reject) => {
|
|
11
30
|
// Start the inspector and connect to it
|
|
12
31
|
const session = new inspector.Session();
|
|
13
32
|
session.connect();
|
|
@@ -29,6 +48,29 @@ export async function profileNodeJS(durationMs: number): Promise<string> {
|
|
|
29
48
|
});
|
|
30
49
|
});
|
|
31
50
|
});
|
|
51
|
+
|
|
52
|
+
const filePath = path.join(dirpath, `${thread}_thread_${new Date().toISOString()}.cpuprofile`);
|
|
53
|
+
fs.writeFileSync(filePath, profile);
|
|
54
|
+
return filePath;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Unlike NodeJS, Bun console.profile() api flush data to the inspector,
|
|
59
|
+
* so this api returns ms taken of this profile instead of file path.
|
|
60
|
+
*/
|
|
61
|
+
async function profileBun(thread: ProfileThread, durationMs: number): Promise<string> {
|
|
62
|
+
const start = Date.now();
|
|
63
|
+
let now = Date.now();
|
|
64
|
+
while (now - start < durationMs) {
|
|
65
|
+
// biome-ignore lint/suspicious/noConsole: need to use console api to profile in Bun
|
|
66
|
+
console.profile(String(now));
|
|
67
|
+
await sleep(BUN_PROFILE_MS);
|
|
68
|
+
// biome-ignore lint/suspicious/noConsole: need to use console api to profile in Bun
|
|
69
|
+
console.profileEnd(String(now));
|
|
70
|
+
now = Date.now();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return `Successfully take Bun ${thread} thread profile in ${now - start}ms. Check your inspector to see the profile.`;
|
|
32
74
|
}
|
|
33
75
|
|
|
34
76
|
/**
|
package/src/util/sszBytes.ts
CHANGED
|
@@ -417,6 +417,36 @@ export function getSlotFromDataColumnSidecarSerialized(data: Uint8Array): Slot |
|
|
|
417
417
|
return getSlotFromOffset(data, SLOT_BYTES_POSITION_IN_SIGNED_DATA_COLUMN_SIDECAR);
|
|
418
418
|
}
|
|
419
419
|
|
|
420
|
+
/**
|
|
421
|
+
* BeaconState of all forks (up until Electra, check with new forks)
|
|
422
|
+
* class BeaconState(Container):
|
|
423
|
+
* genesis_time: uint64 - 8 bytes
|
|
424
|
+
* genesis_validators_root: Root - 32 bytes
|
|
425
|
+
* slot: Slot - 8 bytes
|
|
426
|
+
* fork: Fork - 16 bytes
|
|
427
|
+
* latest_block_header: BeaconBlockHeader - fixed size
|
|
428
|
+
* slot: Slot - 8 bytes
|
|
429
|
+
*
|
|
430
|
+
*/
|
|
431
|
+
|
|
432
|
+
const BLOCK_HEADER_SLOT_BYTES_POSITION_IN_BEACON_STATE = 8 + 32 + 8 + 16;
|
|
433
|
+
export function getLastProcessedSlotFromBeaconStateSerialized(data: Uint8Array): Slot | null {
|
|
434
|
+
if (data.length < BLOCK_HEADER_SLOT_BYTES_POSITION_IN_BEACON_STATE + SLOT_SIZE) {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return getSlotFromOffset(data, BLOCK_HEADER_SLOT_BYTES_POSITION_IN_BEACON_STATE);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const SLOT_BYTES_POSITION_IN_BEACON_STATE = 8 + 32;
|
|
442
|
+
export function getSlotFromBeaconStateSerialized(data: Uint8Array): Slot | null {
|
|
443
|
+
if (data.length < SLOT_BYTES_POSITION_IN_BEACON_STATE) {
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return getSlotFromOffset(data, SLOT_BYTES_POSITION_IN_BEACON_STATE);
|
|
448
|
+
}
|
|
449
|
+
|
|
420
450
|
/**
|
|
421
451
|
* Read only the first 4 bytes of Slot, max value is 4,294,967,295 will be reached 1634 years after genesis
|
|
422
452
|
*
|